Course outline · 0% complete

0/28 lessons0%

Course overview →

cherry-pick and detached HEAD

lesson 9-3 · ~9 min · 26/28

Borrowing exactly one commit

Merge and rebase move whole branches. Real weeks regularly need something smaller. The critical bug fix sits as one commit on a teammate's unfinished branch, or it has to reach the released version without dragging along everything else that has landed on main.

Applying the fix twice by hand invites typos and produces two slightly different changes with no relationship to each other. Git can transplant the commit instead.

git cherry-pick <hash> takes one existing commit and applies the same change as a new commit on your current branch.

$ git switch main
$ git cherry-pick f4a5b6c
[main 8d7c6b5] Fix crash when cart is empty
 1 file changed, 2 insertions(+)

Look at the hashes. The fix was f4a5b6c over there, and the copy here is 8d7c6b5, a new commit with a new hash. The reason is the one from lesson 1-2: a commit's id is computed from its contents including its parent, and this copy has a different parent.

That should sound familiar, because rebase from lesson 9-1 is essentially cherry-pick run in a loop, replaying each of your commits onto a new base. Both operations copy rather than move, for the same underlying reason.

If the borrowed change collides with lines your branch already changed, you get an ordinary conflict from unit 6, resolved in the ordinary way.

Detached HEAD: visiting the past safely

Sometimes you want to stand on an old commit, either to run the code as it was or to test whether a bug already existed back then. The bisect tool in the next unit does this to you repeatedly.

Asking to stand on a commit rather than a branch puts you in detached HEAD state.

$ git switch --detach a1b2c3d
HEAD is now at a1b2c3d Add pancake recipe

Detached means HEAD points directly at a commit instead of at a branch, so lesson 5-1's chain of HEAD to branch to commit loses its middle link.

Looking around is perfectly safe. Files on disk match that old snapshot, every read-only command works, and switching back restores everything.

The danger is committing. With no branch label following you, a commit made here is reachable by nothing once you switch away, and only the reflog from lesson 4-3 remembers it, temporarily.

Git's own warning text says exactly what to do if work made in the past turns out to be worth keeping. Put a label on it before leaving.

$ git switch -c fix-from-the-past

That creates a branch right where you stand, so your commits become ordinary, protected history again.

Normally HEAD follows a branch, so commits are safemainHEAD is here tooDetached: HEAD sits on a commit with no branch attachedmainHEADa commit made here has no label,so switching away leaves it unreachable
HEAD attached to a branch in the normal case, compared with detached HEAD on an older commit where a new commit would have no label pointing at it.

A recorded session

The needed fix is commit f4a5b6c on a teammate's unfinished branch. This session copies just that commit onto main.

Each step below shows the command and the output it printed.

Step 1. Make sure you are standing on the branch that should receive the fix.

~/recipe-book $ git switch main
Switched to branch 'main'

Cherry-pick always applies to your current branch, so this step is the one that decides where the fix lands.

Step 2. Transplant commit f4a5b6c onto main.

~/recipe-book $ git cherry-pick f4a5b6c
[main 8d7c6b5] Fix crash when cart is empty
 1 file changed, 2 insertions(+)

Step 3. Check the log.

~/recipe-book $ git log --oneline
8d7c6b5 Fix crash when cart is empty
c7d8e9f Add photo of finished pancakes
a1b2c3d Add pancake recipe

The fix arrived as a new commit at the tip of main, carrying the original's message but a new hash. The teammate's branch is untouched and still holds f4a5b6c, so when that branch eventually merges, Git recognizes the change is already present and does not apply it twice.

After a successful git cherry-pick f4a5b6c on main, what exists there is a new commit with a different hash that applies the same change. The original stays exactly where it was.

Cherry-pick copies a commit's change onto your branch as a brand-new commit, message included. The hash differs because a commit's id is computed from its contents including its parent, and the copy sits on a different parent.

Nothing about the source branch changes, which is what makes the operation safe to use on a teammate's work in progress. You are reading their commit, not taking it, and their branch continues from the original.

The new commit is at risk because no branch label points at it, so nothing reachable refers to it once you leave.

In detached HEAD state no branch follows your commits, which is the whole meaning of detached. Switching away moves HEAD elsewhere and leaves that commit unreferenced, invisible to git log and to every branch.

Only the reflog from lesson 4-3 can still find it, and reflog entries expire after around 90 days, so the safety is real but temporary.

The fix is to act before leaving. git switch -c some-branch while still standing there pins a label on the commit and turns it into ordinary, protected history.

The full command is git cherry-pick f4a5b6c.

Git applies that commit's change to the branch you are standing on as a new commit, with a new hash, the same change, and the same message.

The name is the mental model: you are picking one commit off another branch the way you would pick a single cherry, rather than taking the whole branch. It takes the commit hash as its argument, which you get from git log --oneline on the branch that holds the fix.