GitHub Workflow — Branch, PR, Review, Merge
A complete walkthrough of the standard GitHub Flow for a developer working on any project. Pair this with
workflow-example.mdonce you're comfortable with the basics — that one shows how GovForge layers governance on top of this same flow.
TL;DR — yes, create a new branch every time you work on a feature, a
fix, or any change. The main branch must always stay stable and
deployable.
Step 1 — Sync your local main
Before starting any new task, make sure you have the latest version:
git checkout main
git pull origin main
Step 2 — Create a dedicated branch
One branch per task, feature, or bug fix. The typical naming convention:
# Format: type/short-description
git checkout -b feature/add-oauth-authentication
git checkout -b fix/pdf-vectorization-bug
git checkout -b refactor/optimize-rag-pipeline
git checkout -b docs/update-readme
Common prefixes: feature/, fix/, hotfix/, refactor/, docs/,
test/, chore/.
Step 3 — Develop and commit regularly
Make small, atomic commits (one idea per commit) with clear messages. The Conventional Commits specification is widely adopted:
git add modified_file.py
git commit -m "feat: add /api/vectorize endpoint for async processing"
git commit -m "fix: correct timeout on documents > 100 pages"
git commit -m "refactor: extract embedding logic into dedicated module"
Common types: feat, fix, docs, style, refactor, test,
chore, perf.
Step 4 — Push your branch to GitHub
# First push (creates the remote branch)
git push -u origin feature/add-oauth-authentication
# Subsequent pushes
git push
Step 5 — Open a Pull Request (PR)
On GitHub, click Compare & pull request. A good PR contains:
- Clear title — e.g.
feat: add OAuth authentication via Azure Entra ID - Structured description:
- Context — why this change is being made
- Changes — what was modified
- Tests performed — how you validated it
- Screenshots / logs — if relevant
- Linked issues — e.g.
Closes #42
- Assigned reviewers — the people who should validate the change
- Labels —
bug,enhancement,needs-review, etc.
Step 6 — Code review (the critical step)
This is where your team (or yourself, on personal projects) examines the code. The reviewer will:
- Read the changes in the Files changed tab
- Leave inline comments on specific lines
- Suggest modifications directly using GitHub's
suggestionsyntax - Choose an action:
- Approve ✅ — ready to merge
- Request changes ❌ — modifications required
- Comment 💬 — feedback without blocking
Step 7 — Iterate on the feedback
Respond to comments, update the code, then:
# On your feature branch
git add .
git commit -m "fix: apply review suggestions (input validation)"
git push
The PR updates automatically. Mark each thread as Resolved as you address it.
Step 8 — Keep your branch up to date with main
If main has moved forward during the review, sync your branch:
# Option 1 — Merge (preserves full history, but "noisy")
git checkout feature/my-branch
git merge main
# Option 2 — Rebase (clean history, recommended)
git checkout feature/my-branch
git rebase main
git push --force-with-lease # --force-with-lease is safer than --force
--force-with-lease refuses the push if someone else has pushed to your
branch in the meantime — a safety net against accidentally overwriting
teammates' work.
Step 9 — Merge the PR
Once the PR is approved and CI/tests are green, merge it on GitHub. There are three merge strategies:
| Strategy | When to use it |
|---|---|
| Merge commit | Preserves the full branch history (useful for complex features). |
| Squash and merge | Combines every branch commit into a single one (recommended for PRs with many small commits). |
| Rebase and merge | Linear history with no merge commit (for teams that demand a pristine git log). |
For most teams, Squash and merge is the most practical default.
Step 10 — Clean up
git checkout main
git pull origin main
git branch -d feature/my-branch # delete the local branch
# GitHub shows a "Delete branch" button to remove the remote branch
Retrospective reviews — auditing code already on main
A natural follow-up question: can you review code that's already merged? Yes, and it's a recognized practice with several names: post-merge review, retrospective review, audit review, brownfield review.
Why you might do this
- Onboarding — a new dev wants to understand a legacy module by reviewing it cold, as if it were a fresh PR.
- Compliance / audit — code shipped via hotfix without normal review needs a paper trail after the fact.
- Pre-refactor — before touching a legacy module, anchor "what is this doing, and is it OK as-is?"
- Periodic security audit — auth, payments, secrets-handling: a scheduled review every 6 months, even with no changes.
- Post-incident — a bug caused an outage; revisit the merged code that introduced it.
- AI-generated code retro — an agent shipped fast; come back later for a cold human read.
- Tech-debt triage — identify problem areas without changing them.
- Knowledge transfer — a bus-factor-1 module gets a second pair of eyes.
What GitHub gives you natively
| Approach | How it works | Trade-off |
|---|---|---|
[REVIEW-ONLY] PR |
Branch from a historical commit, open a PR with [NO-MERGE] in the title, close it without merging. |
The diff against main is empty — you have to trick GitHub (e.g. revert + revert) or comment on commits directly. |
| Commit-level comments | The github.com/org/repo/commit/<sha> page accepts inline comments even after merge. |
Fragmented, no "reviewed" status, no approve/request-changes workflow. |
| Dedicated issue | Open an issue titled Audit: session auth with permalinks (…/blob/<sha>/file.py#L42-L88). |
No native review workflow — just a thread. |
| GitHub Discussions | Richer than issues for long-form audits. | Same limitation — discussion, not review. |
| Third-party (Reviewable, Graphite) | Multi-pass reviews independent of the PR. | Cost and tool lock-in. |
The structural limit
GitHub's review machinery is bound to the PR, and the PR is bound to the merge. There's no native concept of a review that's decoupled from merging. Every workaround above pushes against that coupling.
Where GovForge changes the model
GovForge treats Decision and Review as first-class entities,
independent of merge. You can create a decision against any commit
(historical or fresh), attach the diff read-only, run policies, request
a review, capture findings, and approve — without touching the branch
or merge state at all.
For the full retro-review walkthrough:
- CLI version:
workflow-example.md→ Scenario 2 - Agent-driven version:
workflow-example-agents.md→ Scenario 2
Variants depending on context
Solo on personal projects. You can simplify — creating a branch is still useful to isolate experimental work, but you can self-approve your own PRs. It's also a great way to keep a clean history and easily roll back later.
Team setting with clients. The full flow applies: required
reviewers, branch protection rules on main (no direct push), mandatory
CI/CD before merge, and possibly a more structured workflow like
Git Flow (with develop, release/, and hotfix/ branches) when
you ship versioned releases.
Going further
- Branch protection rules — enable them on
mainin Settings → Branches: require PRs, require reviews, and require green CI checks before merging. - PR templates — add a
.github/PULL_REQUEST_TEMPLATE.mdfile to standardize PR descriptions across the team. - GitHub Actions — automate tests, linting (e.g.
ruff,blackfor Python), and security checks on every PR. ghCLI — install it (brew install ghor equivalent) to manage PRs straight from the terminal:gh pr create,gh pr review,gh pr merge.CODEOWNERS— assign reviewers automatically based on which files are modified. Particularly useful for Django/Python projects with clear module ownership.
Where GovForge fits in
This workflow is the foundation. GovForge sits on top of it: when you commit, push, and open a PR, GovForge records the decision, attaches the diff, runs policy checks, and tracks reviews and disagreements in an append-only audit trail.
Once you're comfortable with the GitHub flow above, read
workflow-example.md for the CLI version of the
governed flow, or
workflow-example-agents.md for the
agent-driven version where Claude Code and Codex do most of the work.