Git Workflow
Purpose
Keep history readable and recoverable. A good history is a debugging tool: it lets you bisect, revert, and explain. A bad one is a wall of "fix", "fix again", "wip".
When to Use
- Structuring commits before opening a pull request.
- Recovering from a bad rebase, reset, or force-push.
- Bisecting to find the commit that introduced a regression.
- Cleaning up a branch's history.
- Deciding a team branching strategy.
Capabilities
- Atomic commit construction, including interactive staging.
- History rewriting: interactive rebase, squash, fixup, autosquash.
- Recovery: reflog,
ORIG_HEAD, git restore, cherry-pick.
- Bisection, including automated bisection with a test script.
- Conflict resolution and
rerere.
Inputs
- The repository state and the branch's relationship to its base.
- Whether the branch has been pushed and whether others have based work on it.
Outputs
- A branch whose commits each build, pass tests, and do one thing.
- Commit messages that explain why, not what.
- A rebase or merge that preserves the ability to revert cleanly.
Workflow
- Commit atomically — One logical change per commit. Use
git add -p to split a messy working tree.
- Write the message for the future — Subject in the imperative under 72 characters; body explaining why the change was needed.
- Clean before review —
git rebase -i to squash fixups and reorder. Reviewers should read the story, not the process.
- Rebase private branches, merge shared ones — Rewriting history that others have pulled is how you lose their work.
- Recover with reflog — Almost nothing is truly lost.
git reflog shows every position HEAD has held.
Best Practices
- Never
git push --force to a shared branch. Use --force-with-lease, which refuses if someone else has pushed.
- A commit that does not build is a commit that breaks bisect. Keep every commit green.
git commit --fixup <sha> plus git rebase -i --autosquash makes review-response commits disappear cleanly.
- Do not commit generated files, secrets, or large binaries. Removing them later requires rewriting history for everyone.
git bisect run ./test.sh finds the offending commit automatically. It is the fastest regression hunt available.
- Enable
rerere — Git will remember how you resolved a conflict and reapply it next time.
Examples
Automated bisection:
git bisect start
git bisect bad HEAD # current commit is broken
git bisect good v2.14.0 # this release was fine
# Any script exiting 0 for good, non-zero for bad.
git bisect run pytest tests/test_checkout.py::test_total
# Git prints the first bad commit, then:
git bisect reset
Recovering a branch destroyed by a bad reset:
git reflog # find the sha from before the reset
# 8a3f1c2 HEAD@{3}: commit: add proration handling
git reset --hard 8a3f1c2 # branch is back
Splitting a messy working tree into reviewable commits:
git add -p # stage hunks belonging to the first change
git commit -m "Extract proration calculator"
git add -p # stage the next logical change
git commit -m "Fix double-charge on mid-cycle upgrade"
Notes
- The reflog is local and expires (90 days by default). It will not save you from a force-push that only ever existed on someone else's machine.
- Merge commits make
git log --oneline noisy but preserve the true topology. On a team that reviews by PR, squash-merging to main and keeping the branch history in the PR is a reasonable middle ground.
- If a secret is committed, rotating it is mandatory and rewriting history is optional. Assume it is compromised the moment it is pushed.
1---2name: git-workflow3description: Use for branching, committing, history repair, and release hygiene. Covers atomic commits, rebase versus merge, bisect, reflog recovery, and undoing mistakes safely.4---56# Git Workflow78## Purpose910Keep history readable and recoverable. A good history is a debugging tool: it lets you bisect, revert, and explain. A bad one is a wall of "fix", "fix again", "wip".1112## When to Use1314- Structuring commits before opening a pull request.15- Recovering from a bad rebase, reset, or force-push.16- Bisecting to find the commit that introduced a regression.17- Cleaning up a branch's history.18- Deciding a team branching strategy.1920## Capabilities2122- Atomic commit construction, including interactive staging.23- History rewriting: interactive rebase, squash, fixup, autosquash.24- Recovery: reflog, `ORIG_HEAD`, `git restore`, cherry-pick.25- Bisection, including automated bisection with a test script.26- Conflict resolution and `rerere`.2728## Inputs2930- The repository state and the branch's relationship to its base.31- Whether the branch has been pushed and whether others have based work on it.3233## Outputs3435- A branch whose commits each build, pass tests, and do one thing.36- Commit messages that explain why, not what.37- A rebase or merge that preserves the ability to revert cleanly.3839## Workflow40411. **Commit atomically** — One logical change per commit. Use `git add -p` to split a messy working tree.422. **Write the message for the future** — Subject in the imperative under 72 characters; body explaining why the change was needed.433. **Clean before review** — `git rebase -i` to squash fixups and reorder. Reviewers should read the story, not the process.444. **Rebase private branches, merge shared ones** — Rewriting history that others have pulled is how you lose their work.455. **Recover with reflog** — Almost nothing is truly lost. `git reflog` shows every position HEAD has held.4647## Best Practices4849- Never `git push --force` to a shared branch. Use `--force-with-lease`, which refuses if someone else has pushed.50- A commit that does not build is a commit that breaks bisect. Keep every commit green.51- `git commit --fixup <sha>` plus `git rebase -i --autosquash` makes review-response commits disappear cleanly.52- Do not commit generated files, secrets, or large binaries. Removing them later requires rewriting history for everyone.53- `git bisect run ./test.sh` finds the offending commit automatically. It is the fastest regression hunt available.54- Enable `rerere` — Git will remember how you resolved a conflict and reapply it next time.5556## Examples5758**Automated bisection:**5960```bash61git bisect start62git bisect bad HEAD # current commit is broken63git bisect good v2.14.0 # this release was fine6465# Any script exiting 0 for good, non-zero for bad.66git bisect run pytest tests/test_checkout.py::test_total6768# Git prints the first bad commit, then:69git bisect reset70```7172**Recovering a branch destroyed by a bad reset:**7374```bash75git reflog # find the sha from before the reset76# 8a3f1c2 HEAD@{3}: commit: add proration handling77git reset --hard 8a3f1c2 # branch is back78```7980**Splitting a messy working tree into reviewable commits:**8182```bash83git add -p # stage hunks belonging to the first change84git commit -m "Extract proration calculator"85git add -p # stage the next logical change86git commit -m "Fix double-charge on mid-cycle upgrade"87```8889## Notes9091- The reflog is local and expires (90 days by default). It will not save you from a force-push that only ever existed on someone else's machine.92- Merge commits make `git log --oneline` noisy but preserve the true topology. On a team that reviews by PR, squash-merging to main and keeping the branch history in the PR is a reasonable middle ground.93- If a secret is committed, rotating it is mandatory and rewriting history is optional. Assume it is compromised the moment it is pushed.