Skip to content

Lesson: Cherry-pick and stash

The lesson where “I need that fix on the other branch too” becomes one command

Section titled “The lesson where “I need that fix on the other branch too” becomes one command”

It’s 3:14pm on a Wednesday. You just merged a fix to main: a one-line patch that closes a payment-flow bug your customers have been hitting. PR approved, merged, deployed. You feel good.

Then your phone buzzes. It’s your team lead. “Hey, that fix needs to go onto the v1.4 release branch too. We’re still supporting v1.4 for the enterprise customers who haven’t upgraded yet. Can you backport it?”

What do you do? You could re-implement the fix by hand on the v1.4 release branch. You could merge main into that release branch, but that drags in fifty other commits you don’t want on the release branch. You could create a new branch off the v1.4 release branch and try to remember exactly what you changed.

Or you could run one command:

Terminal window
git cherry-pick abc1234

Where the hash shown is the SHA of that one fix commit on main. Cherry-pick takes that single commit’s diff and applies it to your current branch as a new commit. The fix lands on the v1.4 release branch. You push. You’re done.

L11 is about two tools that live next to each other in your toolbox: cherry-pick (surgically copy a single commit from one branch to another) and stash (set aside in-progress work without committing). Different problems, same flavor; both are about moving small units of change around between branches and contexts. Both feel “advanced” the first time you reach for them and routine by the tenth time.

This matters because: every working developer hits cherry-pick situations. Backporting hotfixes to old releases. Forwarding a useful commit from an experimental branch you’re about to abandon. Pulling one commit from a teammate’s branch before their PR merges. And stash is the daily safety net for “wait, I’m on the wrong branch” and “the boss just paged me about a fire” and “I want to try this experiment without committing yet.” Without them, you reach for clumsier alternatives that work but waste time and leave messier history.

Take a commit on branch A. Its diff says “change line 47 from X to Y in some source file.” Cherry-pick on branch B replays that diff on top of branch B’s current state, producing a new commit on B with the same author info and message but a different SHA.

The key word is new commit. Cherry-pick does NOT move the original commit. It does NOT make the original commit “appear” on the new branch. It creates a fresh commit whose content is the same diff. The original keeps living on its original branch. The new one lives on your current branch.

Mental model: cherry-pick is git diff plus git apply plus git commit rolled into one command. The result is two commits with the same change but different SHAs.

This is why cherry-pick gets the “duplicate” reputation. If both branches eventually merge into the same place, you’ll have two commits with the same change. Most of the time this is fine; the merge will collapse them. Occasionally it causes conflicts, which is why some teams have rules about when to cherry-pick versus when to merge.

The basic form:

Terminal window
git checkout release/v1.4
git cherry-pick abc1234

You first switch to the branch where you want the commit to land. Then you cherry-pick the SHA of the source commit. Git replays the diff and creates a new commit. The new commit’s message defaults to the original commit’s message.

Cherry-pick multiple commits:

Terminal window
git cherry-pick abc1234 def5678 ghi9012

Applies them in order, creating three new commits on the current branch.

Cherry-pick a range:

Terminal window
git cherry-pick abc1234..ghi9012

Applies all commits from (but NOT including) the first commit up to and including the last. The exclusive-start form is a common source of off-by-one confusion; if you want the first commit included, append a caret to it (the caret means “the parent of,” so the range starts just before that commit).

Cherry-pick without committing immediately:

Terminal window
git cherry-pick --no-commit abc1234

Applies the diff to your working tree and index but does NOT create the commit. Useful when you want to tweak the change before committing, or combine it with other work.

Cherry-pick with traceability:

Terminal window
git cherry-pick -x abc1234

The traceability flag adds a line to the new commit message noting that it was cherry picked from the original commit. This is gold for debugging six months later when someone asks “where did this commit come from?” Some teams require the traceability flag on all cherry-picks for exactly this reason.

Cherry-pick conflicts work exactly like merge conflicts (from L7). The diff from the source commit didn’t apply cleanly to the target branch because the surrounding code differs. Git stops mid-cherry-pick with conflict markers in the affected files.

You see:

Applying: Fix payment-flow timeout
CONFLICT (content): Merge conflict in src/payment/processor.py
error: could not apply abc1234... Fix payment-flow timeout
hint: After resolving the conflicts, mark them with
hint: "git add/rm <file>", then run "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the original state, use "git cherry-pick --abort".

Three choices:

Resolve the conflict and continue:

Terminal window
# edit the file to resolve conflict markers (same process as L7)
git add src/payment/processor.py
git cherry-pick --continue

Skip this commit and continue with the next one in the range:

Terminal window
git cherry-pick --skip

Only relevant if you were cherry-picking multiple commits and want to skip the conflicting one.

Abort and go back:

Terminal window
git cherry-pick --abort

Throws away the cherry-pick attempt entirely. Working tree returns to where it was before. Useful when you realize the conflict is too gnarly and you’d rather rethink the approach.

Cherry-pick is right when:

  • Hotfix backport. Fix is on main, you need it on the v1.4 release branch too. Cherry-pick the fix commit onto the release branch.
  • Forward-port from a release branch. A fix went to the v1.4 release branch first (the LTS branch). It also needs to be on main going forward. Cherry-pick it forward.
  • Pulling one commit from an experimental branch. You wrote a useful refactor on an experimental branch you’re now abandoning. Cherry-pick just that commit onto main before deleting the branch.
  • Picking from another developer’s branch. Their PR is still in review but you need one specific commit now. Cherry-pick it onto your branch (with their permission and the traceability flag).

Cherry-pick is the WRONG tool when:

  • You want all of branch X on branch Y. That’s a merge, not many cherry-picks. Cherry-picking each commit one by one is slower and creates a confusing history.
  • The commits depend on each other in subtle ways. Cherry-picking just one of three related commits might leave you with code that doesn’t compile because it references things in the other two.
  • Both branches will eventually merge. If A and B will merge anyway, cherry-picking creates duplicate commits that the merge will then have to reconcile. Just wait for the merge.

The general rule: cherry-pick when you need a SPECIFIC commit on a DIFFERENT branch and the two branches will NOT be merged in the near future (typical of release branches diverging from main).

Stash takes everything in your working tree and index that’s different from HEAD, packages it as a special commit-like object, pushes it onto a stack, and resets your working tree to clean (matching HEAD).

Later, you can pop the stash off the stack and your changes come back.

Three reasons to reach for stash:

  1. You’re on the wrong branch. You started editing files, then realized you’re on main and should be on a feature branch. Stash, switch branches, pop. Your changes appear on the right branch.
  2. You need to switch contexts urgently. Your boss pings about a production fire. You’re mid-feature, nothing’s ready to commit. Stash. Switch to a hotfix branch. Fix the fire. Push. Switch back. Pop. Resume.
  3. You want to test something quickly. You’ve got changes in your working tree. You want to pull the latest from remote to see if something they did breaks your work. Stash. Pull. Test. Pop.

Stash is the safety net for “I have uncommitted work and need to do something else with this checkout right now.”

Stash everything (tracked, modified files):

Terminal window
git stash

Working tree resets to clean. Stash goes on the stack as the most recent stash.

Stash with a descriptive message (recommended):

Terminal window
git stash push -m "WIP frontend dashboard tweak"

The message shows in git stash list so you can identify stashes later. Without messages, you end up with auto-generated names like “WIP on main” followed by a commit hash that don’t tell you anything.

Include untracked files:

Terminal window
git stash -u
# or
git stash push -u -m "WIP including new files"

By default, stash only catches files git already knows about. Untracked files (new files you haven’t added yet) get left in your working tree. The include-untracked flag scoops them up too. Use this when you’ve created new files that you want stashed with the rest.

Include ignored files too:

Terminal window
git stash -a

The “all” flag includes ignored files. Rarely needed but exists.

List your stashes:

Terminal window
git stash list

Output looks like:

stash@{0}: On feature/dashboard: WIP frontend dashboard tweak
stash@{1}: On main: WIP something I forgot about three weeks ago
stash@{2}: On feature/auth: WIP auth refactor before lunch

The branch shown is the branch you were on WHEN you stashed. The number in each stash reference is the stack position (zero is most recent).

Show a stash’s contents (diff):

Terminal window
git stash show -p stash@{0}

Without the patch flag, you get a summary (which files changed, how many lines). With the patch flag, the full diff. Useful when you’re not sure if a stash is still relevant.

Two main commands: pop and apply. Plus a third for special cases: branch.

Pop the most recent stash (and remove it from the stack):

Terminal window
git stash pop

Restores the most recent stash to your working tree AND deletes it from the stack. The default. Use this when you’re confident the restore will work cleanly.

Apply a stash without removing it:

Terminal window
git stash apply # apply stash@{0}, keep it on the stack
git stash apply stash@{2} # apply a specific stash

Useful when you want to try restoring and not lose the stash if something goes wrong. After confirming, you can drop the most recent stash to remove it.

Drop a stash explicitly:

Terminal window
git stash drop stash@{1}

Removes a specific stash from the stack without applying it. Useful when you have a stale stash you don’t need anymore.

Drop ALL stashes:

Terminal window
git stash clear

Nuclear. Use with care. Stashes don’t come back; they’re gone.

Restoring a stash to a NEW branch, the underused power tool

Section titled “Restoring a stash to a NEW branch, the underused power tool”

What if you stashed on main, then main advanced (you pulled, teammates merged work), and now your stash conflicts with main’s new state? You don’t want to deal with the conflicts on main. You want to restore the stash exactly as it was, isolated.

Terminal window
git stash branch experiment-from-stash stash@{0}

This creates a new branch starting from the commit you were ON when you stashed, applies the stash to it, and drops the stash from the stack. You get a clean branch with your stashed work exactly as it was, no conflicts with main’s drift.

This is the “I stashed three weeks ago and now main has moved on” recovery move. Underused, very effective.

When you pop or apply a stash and the working tree has diverged, you can get conflicts. They look like merge conflicts. Resolve them the same way (L7 process). Then:

Terminal window
git add <resolved-files>
# the stash is already applied; just commit (or continue editing)

If you used git stash pop and conflicts occurred, the stash is NOT automatically removed from the stack (git is being conservative). After resolving, drop it manually:

Terminal window
git stash drop stash@{0}

If you’d rather start over, you can reset:

Terminal window
git reset --merge # bail out of the stash apply, keep stash on stack

Or, if you’re really stuck and want to abandon both the stash and the apply attempt:

Terminal window
git checkout -- . # discard working tree changes
git stash drop stash@{0} # drop the stash

Stash is convenient. It’s also addictive. Some teams forbid stashing because it leads to:

  • Stash piles that grow indefinitely. You stash, forget, stash again, three months later you have nine stashes and no idea what’s in any of them.
  • Lost work. A git stash drop or git stash clear is essentially deletion. If you stashed something important and dropped it, recovery is hard (possible via the reflog, but requires comfort with the lost-and-found mode of git fsck).
  • Hiding work. Stash isn’t committed. It doesn’t push. If your laptop dies with stashed work on it, the work is gone. Teammates can’t see it. CI can’t run on it.

The cleaner alternative: commit work-in-progress to a branch. Make a WIP commit, push it. Switch contexts. Come back, reset to the previous commit (keeping the WIP work in the working tree), continue. WIP commits are visible, recoverable, and shareable. Stash is private, ephemeral, and easy to lose.

The rule of thumb: stash for SHORT context switches (minutes to a few hours). For longer pauses or anything you’d be sad to lose, commit it.

A common pattern: “the boss just paged me”

Section titled “A common pattern: “the boss just paged me””

You’re mid-feature on a feature branch named feature slash dashboard. Two files modified, nothing committed yet. Your team lead pings: “Production is down. A nullpointer in the auth flow. Can you fix it?”

Terminal window
# Save your work
git stash push -m "WIP dashboard - midway through filter logic"
# Switch to the hotfix branch
git checkout -b hotfix/auth-nullpointer main
# Fix the bug
# ... edit, test, commit ...
# Push and open a PR
git push origin hotfix/auth-nullpointer
# (open PR via GitHub/GitLab UI)
# After merge, go back to your feature
git checkout feature/dashboard
git stash pop

You’re back where you were. Two files still modified. Filter logic still half-done. Production is fixed. Total elapsed: maybe 45 minutes. Your dashboard work was never lost, never committed, never visible to teammates, and is exactly where you left it. This is stash at its best.

A common pattern: cherry-pick a hotfix to a release branch

Section titled “A common pattern: cherry-pick a hotfix to a release branch”

You merged a fix to main. The fix needs to also land on the v1.4 release branch for the customers still on that release.

Terminal window
# Find the SHA of the fix commit
git log main --oneline | head -5
# you see: abc1234 fix: payment timeout on slow networks
# Switch to the release branch
git checkout release/v1.4
# Cherry-pick the fix
git cherry-pick -x abc1234
# the -x flag adds "(cherry picked from commit abc1234)" to the message
# Push
git push origin release/v1.4

The fix is now on both branches. Different commit SHAs, same change. The release-branch commit’s message includes the traceability line so anyone debugging later can find the original.

Worked example 1: Backporting a critical fix to two LTS branches

Section titled “Worked example 1: Backporting a critical fix to two LTS branches”

Setup: You’re maintaining a library with three active versions: main (3.x development), the v2.4 release branch (LTS, 24-month support), and the v1.8 release branch (LTS, last 6 months of support). A security bug is found that affects all three.

Step 1: Fix on main first.

You write the fix as you normally would. Branch off main, write the patch, write a regression test, open a PR, get review, merge.

After merge, you note the SHA:

Terminal window
git log main --oneline | head -3
# fe5d23a fix: sanitize input in deserializer (CVE-2026-1234)
# ...

The fix is the commit fe5d23a.

Step 2: Backport to v2.4.

Terminal window
git checkout release/v2.4
git pull
git checkout -b backport/cve-2026-1234-v2.4
git cherry-pick -x fe5d23a

It applies cleanly. You run the test suite locally, it passes. You push:

Terminal window
git push origin backport/cve-2026-1234-v2.4

Open a PR against the v2.4 release branch. Get review (a peer who knows the v2.4 codebase). Merge.

Step 3: Backport to v1.8.

Terminal window
git checkout release/v1.8
git pull
git checkout -b backport/cve-2026-1234-v1.8
git cherry-pick -x fe5d23a

This time, conflict. v1.8’s deserializer was implemented differently. The fix as written doesn’t apply.

You don’t panic. You read the conflict markers, understand what the fix is doing conceptually, and re-apply it by hand using v1.8’s structure. You add a comment explaining the original fix SHA so future debuggers can find the connection:

# Sanitize input to prevent CVE-2026-1234.
# Cherry-pick equivalent from main: fe5d23a
def deserialize(raw):
if not _is_valid(raw):
raise ValueError("invalid input")
...

Tests pass. You commit:

Terminal window
git add <files>
git cherry-pick --continue

Push, PR, review, merge. Three branches now patched. Cut releases on each.

This is the canonical multi-release backport workflow. Library maintainers do this monthly. Application teams running multiple production versions do this whenever a critical fix needs to ride into older versions.

Worked example 2: Stash to swap branches mid-thought

Section titled “Worked example 2: Stash to swap branches mid-thought”

Setup: You’re on a feature branch named feature slash payment-receipts. You’ve been editing the receipt template and the email service file. Nothing committed.

You realize you also wanted to check something on main, there was a discussion in chat about how a related class is structured, and you want to look at the current implementation before continuing.

You don’t want to commit half-finished work. You also don’t want to lose what you have.

Terminal window
# Save and clean the working tree
git stash push -m "WIP receipt template - email integration half done"
# Look at main
git checkout main
# ... browse, read, understand ...
# Return
git checkout feature/payment-receipts
git stash pop

You’re back. Two files modified, exactly as before. The 30-second detour to read main cost nothing. Without stash, you’d have had to commit the half-finished work (and either un-commit it later or live with the messy history) or use a separate worktree (more on that in L13).

Worked example 3: Cherry-pick from an abandoned experiment

Section titled “Worked example 3: Cherry-pick from an abandoned experiment”

Setup: You spent two days on an experimental branch named experiment slash new-cache-layer. You wrote five commits. You explored an idea and decided the overall architecture isn’t right. The branch is going to be deleted.

BUT: one of the five commits was a useful refactor to the existing cache code. It cleaned up a long-standing wart. You want to keep just that commit.

Terminal window
git log experiment/new-cache-layer --oneline
# c5b2f01 (HEAD -> experiment/new-cache-layer) wip: layer 4 of new cache
# a8d3e22 wip: layer 3
# 7f9a44b refactor: extract cache eviction logic (this is the useful one)
# 4e1c789 wip: layer 1
# 2b0f567 spike: new cache layer skeleton
git checkout main
git cherry-pick -x 7f9a44b

The refactor lands on main as a clean standalone commit, with traceability back to the experiment branch. You can now safely delete the experiment branch:

Terminal window
git branch -D experiment/new-cache-layer

The branch is gone. The good commit is preserved. Two days of work that you mostly discarded just paid back the one useful piece of it.

Worked example 4: Stash branch as a “get me out of trouble” move

Section titled “Worked example 4: Stash branch as a “get me out of trouble” move”

Setup: Three weeks ago, you stashed work on main. It was a feature you started, got distracted from, never came back to. Today you want to finish it.

Terminal window
git stash list
# stash@{0}: On main: WIP analytics dashboard

Meanwhile, main has moved on. Forty commits have landed. You suspect the stash won’t pop cleanly.

Terminal window
git stash pop

As expected, conflict. The files you edited have been refactored. Resolving inside main would be a mess.

Better approach: bail out of the pop and use stash branch:

Terminal window
git checkout -- . # discard the partial conflict state
git stash drop stash@{0} # if pop already dropped it, skip this

Wait, pop conflicts mean the stash is NOT automatically dropped. Let’s redo:

Terminal window
git checkout -- . # discard the conflict state
# the stash is still on the stack
git stash branch feature/analytics-revival stash@{0}

The stash branch command creates a new branch starting from the commit you were on when you stashed (three weeks ago), applies the stash there, and drops it. You now have a clean branch with your work in its original context. You can rebase or merge from main at your own pace.

If you’re coming from Mercurial: hg graft is the equivalent of git cherry-pick. Same concept (copy a commit’s diff onto your current branch), same conflict-handling pattern. The hg shelve extension is the equivalent of git stash. The mental model transfers directly.

If you’re coming from SVN: there is no SVN equivalent of cherry-pick. SVN’s “merge a range” is the closest, and it’s a much heavier operation. SVN users coming to git often discover cherry-pick and immediately fall in love with it for the precision. Stash also has no SVN equivalent; SVN users either committed half-finished work to a branch or used patches (save the diff to a patch file, then revert, then apply it later).

If you’re coming from Perforce: shelving in P4 is the close equivalent of git stash, but P4 shelves live on the server (visible to others, recoverable across machines). Git stashes are local-only. If you want git stashes to behave like P4 shelves, the answer is: don’t stash, commit to a branch and push.

The general principle: cherry-pick is unique to git’s snapshot model in how easy it is. Stash is convenient but should be treated as ephemeral, not as a substitute for committing.

A useful frame for managers and technical product managers

Section titled “A useful frame for managers and technical product managers”

When your engineers talk about backporting fixes, they’re talking about cherry-pick (almost always). Here’s what’s useful to know:

  • Backports take real time. Cherry-picks that apply cleanly take five minutes. Cherry-picks that conflict can take hours. When estimating “we’ll backport the security fix to v1.8 and v2.4,” budget for the possibility of significant rework on the older branch.
  • Backports need their own QA. A fix that passed tests on main might not behave identically on the v1.8 release branch because the surrounding code differs. Each backport needs its own validation pass.
  • Backport policies vary. Some teams backport every bug fix to every supported release. Some backport only security fixes. Some backport only “critical” fixes with explicit customer impact. The policy choice trades support burden against customer trust. A clear written policy prevents per-fix debates.
  • Cherry-pick traceability matters for audit. Use the traceability flag (or a project convention that links new to original commits) so when an auditor asks “how did this fix get to the v1.8 release?” the answer is in the commit message.
  • Stash never appears in remote history. If an engineer says “I stashed it,” that work exists only on their laptop. For high-value work-in-progress (multi-day projects, things being handed off to another engineer), encourage commits to a feature branch instead. Stash is fine for “I’ll come back in 20 minutes.”

For TPMs specifically: when a high-priority backport needs to land on multiple release branches, the cherry-pick pattern is your friend. The work is broken into N parallel work items (one per release branch), each one is small and self-contained, each can be reviewed independently, each is tractable to schedule and track. This is cleaner than “backport sprint” framing where one ticket covers all branches and progress is opaque.

In Phase 4 (L13-L16) we’ll see why cherry-pick is the canonical way to move commits between parallel agents working in separate worktrees. Each agent commits to its own branch. The integration step often involves cherry-picking specific commits between branches before the final merge. Stash, by contrast, isn’t great for agents (their work should be committed to a branch so the lead and other agents can see it). The asymmetry (humans stash often, agents stash rarely) is one of the subtle workflow differences between solo human work and multi-agent fleets.

Startup, 3-person team, single product:

Stash is used constantly (a few times per day per developer), the small team, fast-context-switching environment is where stash shines. Cherry-pick is rare because there’s usually one branch (main) that everyone targets; no release branches yet, no backport situations.

Typical stash usage: “PM just pinged me about the demo bug, let me stash and switch to the demo branch real quick.”

When a startup hits its first big customer (often around series A or first enterprise sale), suddenly they have a “stable release” the customer is on and a “development tip” everyone else uses. That’s when cherry-pick enters the workflow as backport tool. Often a culture shock: “wait, we have to maintain TWO branches now?”

Mid-size company, 50-person engineering team:

Both tools used heavily but for different reasons. Stash is daily-driver for context switches (review request, hotfix, lunch). Cherry-pick is monthly-or-weekly for backports, typically a release branch for the current quarter’s release, plus 1-2 older branches still in support.

Cherry-pick traceability with the traceability flag is usually a team convention or required by code review. Backports have their own PR templates that reference the original fix.

A common pattern at this size: a designated “release engineer” or rotating role handles all backports for the current sprint. Centralizes the cherry-pick judgment calls.

Open-source project with LTS releases:

Cherry-pick is the lifeblood of LTS maintenance. The project’s maintainer team triages every fix that lands on main and decides which LTS branches it goes to. Bots sometimes help (a label on the PR triggers an automated cherry-pick attempt; if it applies cleanly, the bot opens a PR on the LTS branch; if it conflicts, the bot pings a maintainer).

Stash is mostly individual-contributor convenience, not project-level workflow.

Documentation for backport policy is critical. “We backport security fixes to all LTS branches, critical bug fixes to LTS branches still in active support, no new features.” Without a written policy, every backport is a debate.

Multi-agent team, 6 agents working in parallel:

Cherry-pick is the canonical inter-agent transport mechanism. Agent A commits a useful base refactor on its branch. Agent B realizes their feature would benefit from that refactor. Lead cherry-picks Agent A’s refactor commit onto Agent B’s branch (or asks Agent B to do it).

Stash is essentially unused by agents, agents commit small, often, to their own branches. Their work is always recoverable, always visible to the lead, always pushable to remote. The “small commits often” discipline replaces the need for stash entirely.

Humans on a multi-agent team still stash for their own context switches, but inter-agent work moves via cherry-pick, branch merge, or worktree sharing (L13).

The stay-calm psychology for cherry-pick and stash

Section titled “The stay-calm psychology for cherry-pick and stash”

Both tools feel “advanced” the first time. They aren’t. They’re each one command (plus some flag options for common cases).

The thing to internalize: both are reversible. git cherry-pick with abort undoes a cherry-pick mid-conflict. git stash drop removes a stash without applying it. A git reset back one commit undoes a cherry-pick that already committed. Nothing about either command is destructive in a way that can’t be recovered (the reflog has your back for 90 days).

The thing to NOT internalize: stash is NOT a backup. Stash is a short-term holding place. Don’t put work on the stash and walk away for two weeks. Don’t run git stash clear casually; you might lose work you needed. For longer-term safety, commit (even WIP commits) to a branch and push.

The thing to NOT do: cherry-pick the same commit twice onto the same branch. You’ll get duplicate commits with different SHAs. The duplicates won’t break anything immediately but will confuse anyone reading history later. If you accidentally double-cherry-picked, the fix is a hard reset back one commit to drop the second copy.

You can:

  • Backport a hotfix from main to a release branch using git cherry-pick with the traceability flag and the commit’s SHA, and recognize when conflicts need conceptual re-application rather than line-by-line resolution
  • Stash in-progress work to handle an urgent context switch, then restore it cleanly with git stash pop
  • Choose between git stash pop, git stash apply, and git stash branch based on whether you want the stash gone after restore and whether the working tree has diverged
  • Recognize when cherry-pick is the right tool (specific commit, divergent branches, hotfix backport) versus when a merge would be cleaner (all of branch X needs to go to branch Y)
  • Recognize when stash is the right tool (short-term context switch) versus when a WIP commit would be safer (longer pause, multi-day work, anything you’d be sad to lose)
  • Cherry-pick a useful commit from an abandoned experimental branch before deleting it

L12 (Rebase, deeper) takes the rebase concept from earlier lessons and digs into the production patterns: interactive rebase for history cleanup, fixup and squash for collapsing related commits, the difference between rebasing local commits (fine, encouraged) and rebasing published commits (dangerous, usually wrong). L12 closes Phase 3.

Then Phase 4 (L13-L16) introduces multi-agent territory: worktrees, integration patterns for parallel agents, AI-authored commits, and the future of git in an AI-collaborative world.

Git stores snapshots. Every other command is just navigating those snapshots.

Cherry-pick takes the snapshot at commit X, computes its diff against its parent, and applies that diff as a new snapshot on top of your current branch. Stash takes the difference between your current working tree and HEAD, packages it as a stashed snapshot, and resets the working tree to HEAD. Pop applies the stashed diff back onto whatever HEAD is now. Both are just snapshot manipulation. Once you see the snapshot model, neither command is mysterious.