The Sharp Tools

five power tools: copy a commit, hunt a bug, park a desk, seal a release, rewrite a run

Everything before this chapter was daily life: edit, stage, commit, branch, merge, undo. These five are the specialist instruments - each solves one specific professional problem, and each leans on the mental model you already hold: commits are snapshots, branches are names, history is a graph of parent pointers.

One law binds three of them: a replayed change is a NEW commit. cherry-pick copies one, rebase -i replays a run - in both, the change may match but the commit ids differ. Tags are the opposite instrument: a name whose whole job is to never move at all.

$ git cherry-pick hotfix
[main 9ded166] fix: salt the focaccia
  ... (Date line)
 1 file changed, 1 insertion(+)
 create mode 100644 fix.txt
one change, second id

git cherry-pick lifts one commit's change onto your branch. Maria's fix lived on hotfix as 858f504; picking it onto main filed 9ded166 - same message, same change, different commit. One common maintenance workflow: the fix lands where it was written, then gets picked onto every release line that needs it. The dark side: the two commits never link, so a later merge can re-collide the same change.

$ git bisect run ./check.sh
  ... (three halvings)
09714e6d7ce... is the first bad commit
bisect found first bad commit
the archive interrogates itself

git bisect turns debugging into arithmetic. Mark one commit good and one bad, and git serves you midpoints - each answer halves the suspects. Our 15-suspect hunt took four answers and named 09714e6 exactly. Our check.sh simply greps for the bad symptom; hand any such script to git bisect run - it asks zero questions: exit 0 means good, 1-127 bad (125 = skip this commit, 128+ aborts). The one rule: leave via git bisect reset, and never trust a flaky test - one wrong answer sends the whole search into the wrong half.

the side drawer - park, not archive
the side drawer - park, not archive

git stash is the side drawer: your tracked edits and staged changes swept in with one motion, desk reset clean, and pop lays everything back (dropping the entry only after a clean apply - on conflict it is kept). The law that burns people: untracked files stay on the desk - our check.sh sat untouched through the whole park-and-return; only -u sweeps them too. And the drawer is for the SHORT hold: work you will care about later belongs on a branch, where it has a name and a history.

the sealed exhibit: a name glued to one commit
the sealed exhibit: a name glued to one commit

git tag plants a name that never rides forward. We sealed v1.0 on 0f07caf and kept committing - git describe answered v1.0-7-g9ded166: seven commits past the release, currently at 9ded166 - every build traceable back to its nearest sealed version. Annotated tags (-a) carry tagger, date and message; that is the release standard. Staying put is policy, not physics: -f can move one, which is exactly why moving a published tag is taboo.

reword ac85a77 draft: outline
squash 0e7cb67 draft: fix typo
pick   4fc6860 draft: second thought
the docket, reconstructed from a real rebase -i session

git rebase -i opens an instruction list over your recent commits: pick keeps, squash folds a commit into the one above, reword edits a message. Our three drafts replayed into two clean commits - fdf9056 and 93763db, both NEW ids. The old drafts survive in the reflog (and any ref still naming them). The working rule: rewrite only commits others may not yet depend on - rewriting shared history forks reality for everyone who already fetched it.

Where the tools meet: pick one gem off a dying branch, bisect the regression it fixes, stash the desk while you jump lines, seal the release when it ships, and tidy the run before review. Five instruments, one graph underneath.