crew-git: history as a communication act
A commit is not a save point; it's the unit someone else reviews, bisects,
reverts, and reads in git blame three years from now. Hygiene here is not
tidiness; it's making every one of those four operations work.
Committing
- One logical change per commit. The operational test isn't "is it small"
but "can it be reverted alone without collateral damage". Mechanical noise
(rename, format, lockfile churn) goes in its own commit, separated from
behavior. A reviewer can wave through a pure-rename commit in seconds if
it's pure, and
git bisect stays sharp.
- Read the staged diff before every commit.
git diff --staged, every
hunk, in the terminal. The medium switch from your editor resets
pattern-blindness. This is where debug prints, stray files, commented-out
code, and "how did THAT get staged" are caught. Stage deliberately
(git add -p when the tree is mixed), never git add -A out of habit.
- Message = why, not what. The diff already says what. Imperative subject
≤ 72 chars; body for the why, the alternative you rejected, and any
non-obvious consequence. If the subject needs "and", split the commit.
- Never commit: secrets, generated files the repo doesn't already track,
half-done work on a shared branch.
WIP commits are fine on your own
branch if they're squashed before review.
Branching
Branch per task, from up-to-date main. Never commit to main by habit: if
the repo allows it, that's the repo being polite, not it being a good idea.
Rebase your own unshared branch to stay current; never rewrite anything
already pushed to a branch others use. Whether the repo merges or rebases
onto main is the repo's convention, not yours to relitigate mid-PR.
Safe repair table
| Situation |
Repair |
| Committed too soon, not pushed |
git commit --amend / git rebase -i freely |
| Committed too soon, already pushed to shared branch |
New commit on top; amending pushed history transfers your mistake to everyone's clone |
| Wrong branch |
git cherry-pick onto the right one, then remove from the wrong one |
| Need to undo a pushed commit |
git revert (an honest new commit, history intact) |
| Staged/tracked file that must never be |
remove + .gitignore in the same commit, or it returns |
| Secret committed |
Rotate the secret FIRST. History rewriting comes second and only for tidiness. Clones, forks, and CI logs already have the value, so scrubbing without rotating is theater |
| Detached HEAD / "everything is gone" |
git reflog. It's almost never gone; find the SHA, branch from it |
Failure modes
| Habit |
Cost |
git add -A && git commit -m fix |
Unreviewable history; bisect finds "fix" |
| Force-push to a shared branch |
Everyone downstream rebases their morning away |
| Mixing rename + logic in one commit |
Reviewer must diff-in-head the rename to see the logic |
| Amending as amnesia (repeatedly rewriting local history mid-debug) |
You destroy the trail git bisect needed |
| Commit message novel for a typo fix |
Effort budget spent where nobody needed it |
1---2name: crew-git3description: Use whenever committing, branching, or repairing git history. Enforces atomic commits, the staged-diff read-through, honest messages, and the safe-repair table (including the rotate-first rule for leaked secrets).4---56# crew-git: history as a communication act78A commit is not a save point; it's the unit someone else reviews, bisects,9reverts, and reads in `git blame` three years from now. Hygiene here is not10tidiness; it's making every one of those four operations work.1112## Committing1314- **One logical change per commit.** The operational test isn't "is it small"15 but "can it be reverted alone without collateral damage". Mechanical noise16 (rename, format, lockfile churn) goes in its own commit, separated from17 behavior. A reviewer can wave through a pure-rename commit in seconds *if*18 it's pure, and `git bisect` stays sharp.19- **Read the staged diff before every commit.** `git diff --staged`, every20 hunk, in the terminal. The medium switch from your editor resets21 pattern-blindness. This is where debug prints, stray files, commented-out22 code, and "how did THAT get staged" are caught. Stage deliberately23 (`git add -p` when the tree is mixed), never `git add -A` out of habit.24- **Message = why, not what.** The diff already says what. Imperative subject25 ≤ 72 chars; body for the why, the alternative you rejected, and any26 non-obvious consequence. If the subject needs "and", split the commit.27- Never commit: secrets, generated files the repo doesn't already track,28 half-done work on a shared branch. `WIP` commits are fine on your own29 branch *if* they're squashed before review.3031## Branching3233Branch per task, from up-to-date main. Never commit to main by habit: if34the repo allows it, that's the repo being polite, not it being a good idea.35Rebase your own unshared branch to stay current; **never rewrite anything36already pushed to a branch others use.** Whether the repo merges or rebases37onto main is the repo's convention, not yours to relitigate mid-PR.3839## Safe repair table4041| Situation | Repair |42|---|---|43| Committed too soon, not pushed | `git commit --amend` / `git rebase -i` freely |44| Committed too soon, already pushed to shared branch | New commit on top; amending pushed history transfers your mistake to everyone's clone |45| Wrong branch | `git cherry-pick` onto the right one, then remove from the wrong one |46| Need to undo a pushed commit | `git revert` (an honest new commit, history intact) |47| Staged/tracked file that must never be | remove + `.gitignore` in the same commit, or it returns |48| **Secret committed** | **Rotate the secret FIRST.** History rewriting comes second and only for tidiness. Clones, forks, and CI logs already have the value, so scrubbing without rotating is theater |49| Detached HEAD / "everything is gone" | `git reflog`. It's almost never gone; find the SHA, branch from it |5051## Failure modes5253| Habit | Cost |54|---|---|55| `git add -A && git commit -m fix` | Unreviewable history; bisect finds "fix" |56| Force-push to a shared branch | Everyone downstream rebases their morning away |57| Mixing rename + logic in one commit | Reviewer must diff-in-head the rename to see the logic |58| Amending as amnesia (repeatedly rewriting local history mid-debug) | You destroy the trail `git bisect` needed |59| Commit message novel for a typo fix | Effort budget spent where nobody needed it |