git stash push -u -m 'label': saves tracked + untracked changes with a description
git stash pop: restores and removes from stack — deletes stash even on conflict
git stash apply: restores but keeps in stack — safer when conflicts are possible
git cherry-pick : replays a commit's diff onto current branch with a new SHA
git cherry-pick -n : applies changes without committing — combine multiple into one
✦ Definition~90s read
What is Git Stash and Cherry-pick?
Git stash and cherry-pick are two distinct operations that solve different problems, but when combined they form a powerful workflow for moving work between branches without cluttering your history. git stash temporarily shelves uncommitted changes — both staged and unstaged — so you can switch branches or pull upstream changes without making a half-baked commit. It’s a parking lot for work-in-progress, not a permanent record. git cherry-pick, on the other hand, takes an existing commit from one branch and applies its diff onto your current HEAD, effectively copying a specific change set.
★
Imagine you're a chef mid-way through making a complex sauce when your manager rushes in and says 'drop everything — the dessert is on fire.' Git stash is like wrapping your half-chopped ingredients in cling film and putting them in the fridge so nothing is wasted.
This is useful when you need a hotfix from main into a feature branch, or when you want to selectively port commits without merging the entire branch.
The confusion arises when you try to cherry-pick a stash commit. A stash is stored as a special ref (refs/stash) with a merge commit structure (two parents: your working tree and index). When you cherry-pick a stash, Git sees a merge commit and cannot determine a single source SHA for the diff — it doesn’t know which parent to use as the base.
This triggers a "duplicate conflict" or "missing source SHA" error because cherry-pick expects a linear commit history. The fix is to never cherry-pick a stash directly; instead, use git stash apply or git stash pop to restore the changes, then commit normally.
In practice, you should reach for stash when you need to quickly context-switch without losing work, and cherry-pick when you need to transplant a specific, already-committed change. If you find yourself needing to cherry-pick a stash, you’ve likely misused one of them — the stash should have been a proper commit in the first place.
Tools like git stash list and git stash show -p help manage multiple stashes, but they’re a crutch; for anything beyond temporary parking, commit to a branch. The real-world rule: stash is for minutes, cherry-pick is for permanent history.
Plain-English First
Imagine you're a chef mid-way through making a complex sauce when your manager rushes in and says 'drop everything — the dessert is on fire.' Git stash is like wrapping your half-chopped ingredients in cling film and putting them in the fridge so nothing is wasted. Cherry-pick is like looking at another chef's finished dish, spotting one brilliant garnish they added, and copying just that garnish onto your own plate — without taking their whole meal.
Two commands solve the two most common context-switching problems in Git: stash and cherry-pick. Stash shelves uncommitted changes so you can switch branches cleanly. Cherry-pick copies specific commits from one branch to another without merging the entire branch.
Stash is a local-only stack — not a branch, not a commit in your history, not synced to the remote. It is ideal for short context switches but dangerous for anything you want to share or keep long-term. Cherry-pick creates a new commit with a new SHA on the target branch. The original commit is untouched. This matters because Git may not recognise the two as the same change during a future merge, causing duplicate conflicts.
Common misconceptions: that stash saves everything (it excludes untracked files by default), that cherry-pick moves commits (it copies them), and that stash pop is always safe (it deletes the stash even on merge conflicts).
Git Stash and Cherry-Pick — The Fundamentals
git stash temporarily shelves uncommitted changes. It takes your modified tracked files and staged changes, saves them to a stack, and restores your working directory to match HEAD. This lets you switch contexts without committing half-finished work.
Key stash commands
git stash push -m 'message' — save changes with a label
git stash list — view saved stashes
git stash pop — restore and remove the latest stash
git stash apply — restore without removing (safer when conflicts possible)
git stash drop — remove a stash
git stash push -u — include untracked files (critical: stash ignores new files by default)
git cherry-pick applies the changes from a specific commit onto your current branch. Instead of merging an entire branch, you pick individual commits.
Key cherry-pick commands
git cherry-pick <sha> — apply the commit's changes to HEAD
git cherry-pick <sha-a>..<sha-b> — apply a range of commits
git cherry-pick --no-commit <sha> — apply changes but don't commit (lets you modify before committing)
Both commands are for local workflow management. Cherry-picking is especially useful for hotfixes where you need only one specific commit from a feature branch.
01_stash_cherrypick.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# STASH: save work-in-progress
git init && echo 'Initial' > file.txt && git add . && git commit -m 'Initial'
echo 'Half-finished feature' >> file.txt
git stash push -m 'WIP: feature in progress'
git status # clean! Changes are safely shelved
# Retrieve the stash later
git stash pop # restores 'Half-finished feature' and removes from stack
# CHERRY-PICK: apply a specific commit
echo 'Hotfix' >> hotfix.txt && git add . && git commit -m 'hotfix: critical fix'
git log --oneline --format='%h %s'
# Switch to another branch and pick just the hotfix
git checkout -b release
git cherry-pick main # cherry-pick the latest commit from main
git log --oneline
Output
Initialized empty Git repository
[main (root-commit) a1b2c3d] Initial
Saved working directory and index state WIP on main: a1b2c3d Initial
nothing to commit, working tree clean
On branch main, changes not staged for commit: modified: file.txt
[main d4e5f6g] hotfix: critical fix
1 file changed, 1 insertion(+)
d4e5f6g hotfix: critical fix
a1b2c3d Initial
[release e5f6g7h] hotfix: critical fix
1 file changed, 1 insertion(+)
⚠ Stash Pop Destroys on Conflict
git stash pop removes the stash from the stack even if the apply hits a merge conflict. If the conflict is unresolved, the changes are gone from the stash but not applied. Use git stash apply when conflicts are possible, then git stash drop manually after resolving.
📊 Production Insight
Cherry-picking is the standard mechanism for backporting hotfixes to release branches. However, overuse creates duplicate commits with different SHAs, making git log traversal harder. Prefer merging where feasible. For stashes, always use stash push -u to include untracked files — the default behavior of excluding them causes the most common stash-related incident.
🎯 Key Takeaway
Stash shelves uncommitted work for context switching. Cherry-pick applies specific commits anywhere. Use stash apply (not pop) when conflicts are possible. Cherry-pick is for hotfix backports, not regular workflow.
thecodeforge.io
Git Stash Cherry Pick
What Git Stash Cherry-Pick Actually Does
Git stash cherry-pick is the operation of applying a commit from the stash (a temporary commit object) onto your current branch using git cherry-pick. The stash stores changes as regular commit objects under refs/stash, but with a flattened tree — it has no parent commit in the normal sense. When you cherry-pick a stash entry, Git treats it like any other commit: it computes a diff between the stash commit and its (nonexistent) parent, then applies that diff to your current HEAD. The critical difference: because the stash commit has no parent, Git cannot compute a three-way merge automatically. Instead, it uses the stash commit's tree as the base, which often leads to false conflicts — Git reports a conflict even when the changes are logically compatible. This is the root cause of the "duplicate conflict" pattern where the same change appears both in the stash and in your working tree, yet Git refuses to merge cleanly.
⚠ Missing Source SHA
A stash commit has no parent, so cherry-pick cannot perform a three-way merge — it always uses the stash tree as the base, causing spurious conflicts.
📊 Production Insight
A team cherry-picks a hotfix from stash onto a release branch, but Git reports a conflict on every line of the fix — even though the fix is identical to the target branch's state.
The exact symptom: git cherry-pick <stash-ref> fails with 'CONFLICT (content)' on every hunk, and git diff shows zero differences between the stash's changes and the working tree.
Rule of thumb: never cherry-pick a stash commit directly — always apply the stash (git stash apply) or create a proper branch from the stash first.
🎯 Key Takeaway
Stash commits have no parent, so cherry-pick cannot do a three-way merge — expect false conflicts.
Always use git stash apply or git stash pop instead of cherry-picking a stash entry.
If you must cherry-pick, first create a branch from the stash commit to give it a proper parent.
Git Stash — Parking Your Work Without a Throwaway Commit
When you run git stash, Git takes everything in your working directory and staging area that differs from HEAD, bundles it into a special stash entry, and hands you back a perfectly clean working tree. The stash lives on a per-repo stack — last in, first out — and it persists across branch switches, which is the whole point.
The key mental model is this: a stash entry is NOT a branch, NOT a commit on your history, and NOT synced to the remote automatically. It's local scratch space. That makes it ideal for short context switches, but dangerous for anything you want to share with teammates or keep long-term.
People often assume git stash only captures tracked files. It doesn't touch untracked files by default. That silent omission is responsible for a lot of lost work. Use git stash push --include-untracked (or the short form -u) when you have new files that haven't been staged yet.
You can also give stashes a descriptive message with git stash push -m "wip: payment gateway refactor". Without messages, stashes pile up as cryptic stash@{0}, stash@{1} entries and become almost impossible to manage after a long sprint.
io/thecodeforge/git/StashWorkflow.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# io.thecodeforge — GitStashWorkflow
# ─── SCENARIO ──────────────────────────────────────────────────────────────
# You're halfway through refactoring the payment module when your lead
# asks you to jump on branch 'hotfix/order-total-rounding' immediately.
# ───────────────────────────────────────────────────────────────────────────
# Check what you currently have in progress
git status
# Output shows: modified payment_gateway.rb, new file: stripe_adapter.rb
# StashEVERYTHING — tracked modifications AND untracked new files
# -u flag = --include-untracked (critical — stripe_adapter.rb is new)
# -m flag = a human-readable label so you can find this stash later
git stash push -u -m "wip: payment gateway refactor — stripe adapter half done"
# Confirm the working tree is now clean
git status
# Output: nothing to commit, working tree clean
# Switch to the hotfix branch safely
git checkout hotfix/order-total-rounding
# ... do your hotfix work, commit it, done ...
# Come back to your feature branch
git checkout feature/payment-gateway
# List all stashes to find the right one (you might have multiple)
git stash list
# stash@{0}: On feature/payment-gateway: wip: payment gateway refactor — stripe adapter half done
# Pop the stash — restores files AND removes the stash entry from the stack
# Use'apply' instead of 'pop'if you want to keep the stash as a safety copy
git stash pop
# Verify your files are back exactly where you left them
git status
# Output: modified: payment_gateway.rb, new file: stripe_adapter.rb
Output
# After git stash push -u -m "..."
Saved working directory and index state On feature/payment-gateway: wip: payment gateway refactor — stripe adapter half done
# After git status (on the feature branch, post-stash)
⚠ Watch Out: Stash Pop Conflicts Are Silent Killers
If you committed changes to the same file while your stash was parked, git stash pop will hit a merge conflict — but it still drops the stash entry from the stack before you've resolved anything. Use git stash apply stash@{0} instead; it restores the changes WITHOUT removing the stash, giving you a safety net while you sort out the conflicts.
📊 Production Insight
The biggest production failure with stash: developers stash without -u, then run git clean on the wrong branch thinking it will remove build artifacts. git clean removes all untracked files — including the untracked files that were not stashed. The work is gone. There is no reflog for untracked files. The fix: always use stash -u when you have new files. And never run git clean -f without first running git clean -n (dry run) to see what will be deleted.
🎯 Key Takeaway
Stash is local scratch space — not a branch, not a commit, not synced to remote. Always use -u to include untracked files. Always use -m to label stashes. Use apply over pop when conflicts are possible.
thecodeforge.io
Git Stash Cherry Pick
Managing Multiple Stashes — When One Isn't Enough
Real projects generate real interrupt-driven work. You might be juggling an in-progress feature, an experimental spike, and a half-finished code review all at once. The stash stack can hold all of them — but only if you're disciplined about labelling and retrieving them correctly.
The stack is LIFO (last in, first out), so stash@{0} is always the most recent. If you stash three things without labels, you'll spend five minutes running git stash show -p stash@{2} trying to remember what each one contains. Don't do that to yourself.
To apply a specific stash without popping it — useful for inspecting before committing — use git stash apply stash@{1}. To permanently delete a stash entry you no longer need, use git stash drop stash@{1}. To nuke the entire stash stack: git stash clear. That last command is irreversible, so use it deliberately.
One underused power move:git stash branch <new-branch-name> stash@{0}. This creates a brand new branch from the commit where you originally stashed, then pops the stash onto it. It's the cleanest escape hatch when your stash has grown into something that deserves its own branch rather than a quick pop.
io/thecodeforge/git/StashMultiple.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# io.th in gitecodeforge — ManagingMultipleStashes
# ─── SCENARIO ──────────────────────────────────────────────────────────────
# You have two separate in-progress tracks stashed. You need to
# inspect, apply the right one, and clean up the other.
# ───────────────────────────────────────────────────────────────────────────
# See all stashes with their index positions
git stash list
# stash@{0}: On feature/user-auth: wip: JWT refresh token logic
# stash@{1}: On feature/user-auth: wip: email validation spike
# Preview what's inside stash@{1} before applying it
# -p flag shows the actual diff (patch format)
git stash show -p stash@{1}
# ApplyONLY the email validation spike (stash@{1}) without removing it yet
git stash apply stash@{1}
# After confirming the apply looks good, remove it from the stack explicitly
git stash drop stash@{1}
# List again — note that indexes shift after a drop
git stash list
# stash@{0}: On feature/user-auth: wip: JWT refresh token logic
# ─── POWERMOVE ────────────────────────────────────────────────────────────
# TheJWT stash has grown into a real feature — give it its own branch
# This creates 'feature/jwt-refresh' from the original stash point
# and pops stash@{0} onto it automatically
git stash branch feature/jwt-refresh stash@{0}
# Confirm the new branch has the stashed changes applied and stash is gone
git status
git stash list # Empty — stash was consumed by branch creation
Output
# git stash list
stash@{0}: On feature/user-auth: wip: JWT refresh token logic
stash@{1}: On feature/user-auth: wip: email validation spike
Stash only specific chunks of a file, leave the rest in working directory
Use when a single file has two unrelated changes you want to separate
Slow for large changesets — use git stash push -- <path> for file-level control
📊 Production Insight
Stashes that survive more than 3 days should be converted to branches. The reason: stashes are invisible to git branch, git log, and git status. They do not appear in any standard workflow. They are not synced to the remote. If your machine dies or you clone fresh, they are gone. git stash branch <name> <stash> converts a stash into a proper branch that appears branch - be a branch.
🎯 Key Takeaway
Label every stash with -m or they become mystery boxes. Use git stash show -p to inspect before applying. Convert long-lived stashes to branches with git stash branch. Stashes > 3 days old should be branches, not stashes.
Git Cherry-Pick — Transplanting Exactly the Commit You Need
Cherry-pick takes one or more commits from anywhere in your Git history and replays them onto your current branch. It doesn't move the original commits — it creates new commits with the same changes but different commit SHAs. Think of it as 'apply this diff' rather than 'merge this branch.'
The most common real-world trigger is a hotfix workflow: a critical bug is fixed on main, and you need that fix on the release/2.4 branch without pulling in the three feature commits that came after it. One git cherry-pick <sha> and you're done.
The second trigger is salvaging work from an abandoned branch. Someone started a feature, it got cancelled, but buried in the commit history is a beautifully written utility function you can reuse. Cherry-pick extracts just that commit.
Crucially, cherry-pick creates a NEW commit SHA on the target branch. The two commits (original and cherry-picked) have the same diff but different identities. This matters for merge conflict detection — Git may not recognise they represent the same change, which can cause duplicate conflicts down the line if those branches ever merge. This is the main reason cherry-pick is a scalpel, not a Swiss Army knife.
io/thecodeforge/git/CherryPickWorkflow.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# io.thecodeforge — GitCherry-PickWorkflow
# ─── SCENARIO ──────────────────────────────────────────────────────────────
# A critical SQL injection fix was committed to 'main' as commit abc1234.
# The'release/3.1' branch is already cut and needs this fix NOW,
# but the 2 commits after abc1234 on main are incomplete features
# that must NOT go into the release.
# ───────────────────────────────────────────────────────────────────────────
# First, find the exact SHA of the fix commit on main
git log main --oneline
# abc1234 fix: sanitize user input in search query builder
# def5678 wip: new dashboard widget (incomplete)
# ghi9012 wip: migrate analytics to ClickHouse (incomplete)
# Switch to the release branch
git checkout release/3.1
# Cherry-pick ONLY the security fix commit by its SHA
# Git will replay that commit's diff onto the current branch
git cherry-pick abc1234
# Verify the fix landed — note the NEWSHA (different from abc1234)
git log --oneline -3
# xyz9999 fix: sanitize user input in search query builder <-- newSHA!
# aaa1111 chore: bump version to 3.1.0
# bbb2222 feat: order confirmation email template
# ─── CHERRY-PICKING A RANGE ────────────────────────────────────────────────
# If you need commits abc1234 ANDdef5678 (but NOT ghi9012), use dot-dot notation.
# The range abc1234..def5678 means: commits AFTER abc1234 up to AND including def5678.
# ToINCLUDE abc1234 itself, use the caret on the start: abc1234^..def5678
git cherry-pick abc1234^..def5678
# ─── CHERRY-PICKWITHEDIT ─────────────────────────────────────────────────
# --edit (-e) opens the commit message editor before finalising
# Useful when you want to note it was cherry-picked from main
git cherry-pick --edit abc1234
# Opens editor — you can append: "(cherry picked from commit abc1234 on main)"
Output
# git cherry-pick abc1234
[release/3.1 xyz9999] fix: sanitize user input in search query builder
Date: Mon Oct 14 09:23:41 2024 +0000
1 file changed, 4 insertions(+), 1 deletion(-)
# git log --oneline -3
xyz9999 fix: sanitize user input in search query builder
aaa1111 chore: bump version to 3.1.0
bbb2222 feat: order confirmation email template
# git cherry-pick abc1234^..def5678
[release/3.1 lmn1234] fix: sanitize user input in search query builder
[release/3.1 opq5678] wip: new dashboard widget (incomplete)
Cherry-pick changes the parent, so the SHA changes even with identical diff
Same reason rebasing changes SHAs: different parent = different hash
This is why Git may not recognise cherry-picked commits as the same change during future merges
📊 Production Insight
Cherry-pick without --edit is a production anti-pattern. When you cherry-pick a security fix from main to release/3.1 and do not annotate the source SHA, nobody can trace the backport three weeks later. During the next quarterly merge of main into release/3.1, Git will see a duplicate conflict in the same lines. The team will spend hours tracing the history. Always use git cherry-pick --edit <sha> and append (cherry picked from commit abc1234 on main) to the commit message.
🎯 Key Takeaway
Cherry-pick creates a new SHA — the original commit is untouched. Git may not recognise the two as the same change during future merges, causing duplicate conflicts. Always annotate cherry-picked commits with the source SHA using --edit.
thecodeforge.io
Git Stash Cherry Pick
Handling Cherry-Pick Conflicts and Knowing When Not to Use It
Cherry-pick conflicts happen when the target branch has diverged enough from the source that Git can't cleanly apply the diff. The conflict resolution process is identical to a merge conflict — you edit the files, stage the resolution, then run git cherry-pick --continue. If you decide it's too messy, git cherry-pick --abort restores the branch to its pre-cherry-pick state cleanly.
There's also git cherry-pick --no-commit (or -n), which applies the changes from one or more commits to your working directory and staging area WITHOUT creating a commit. This is perfect when you want to cherry-pick changes from several commits and squash them into one clean commit with a better message.
Now the honest advice about when NOT to cherry-pick: if you find yourself regularly cherry-picking the same fix from one long-lived branch to another, that's a workflow smell. The underlying problem is usually branch strategy — your release branches are too isolated from main, or your hotfix process doesn't feed back into all active branches automatically. Cherry-pick is a patch for a workflow problem, not a solution to it. Use it for one-off emergencies, not as a standing process.
io/thecodeforge/git/CherryPickConflict.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# io.thecodeforge — Cherry-PickConflictResolution
# ─── SCENARIO ──────────────────────────────────────────────────────────────
# Cherry-picking commit abc1234 hits a conflict in search_query_builder.rb
# because the release branch edited that same function independently.
# ───────────────────────────────────────────────────────────────────────────
git cherry-pick abc1234
# Git stops and reports a conflict:
# error: could not apply abc1234... fix: sanitize user input in search query builder
# hint: After resolving the conflicts, mark them with
# hint: git add <pathspec>, then run git cherry-pick --continue
# See exactly which files have conflicts
git status
# both modified: app/queries/search_query_builder.rb
# Open the file and resolve the conflict markers manually
# <<<<<<< HEAD = your current release/3.1 version
# ======= = separator
# >>>>>>> abc1234... = the incoming cherry-picked version
# After editing the file to the correct merged state:
git add app/queries/search_query_builder.rb
# Continue the cherry-pick — Git will create the commit
git cherry-pick --continue
# Editor opens for commit message — save and close to finalise
# ─── ALTERNATIVE: BAILOUTCLEANLY ─────────────────────────────────────────
# If the conflict is too complex and you want to reconsider your approach:
git cherry-pick --abort
# Restores the branch exactly as it was before you started — no residue
# ─── NO-COMMITMODE: COMBINEMULTIPLECHERRY-PICKSINTOONECOMMIT ─────────
# Apply changes from two commits without committing either one yet
git cherry-pick --no-commit abc1234
git cherry-pick --no-commit def5678
# Now both sets of changes sit in the staging area
git status
# Changes to be committed: modified: search_query_builder.rb, modified: query_sanitizer.rb
# Create one clean, well-described commit from both changes combined
git commit -m "fix: apply comprehensive input sanitization across query layer (backport from main)"
Output
# git cherry-pick abc1234 (with conflict)
error: could not apply abc1234... fix: sanitize user input in search query builder
hint: After resolving the conflicts, mark them with
hint: git add <pathspec>, then run git cherry-pick --continue
Conflict in app/queries/search_query_builder.rb
# After resolving and git add:
# git cherry-pick --continue
[release/3.1 xyz9999] fix: sanitize user input in search query builder
1 file changed, 5 insertions(+), 2 deletions(-)
# git cherry-pick --abort
On branch release/3.1
nothing to commit, working tree clean
# After --no-commit x2 then git commit:
[release/3.1 pqr3344] fix: apply comprehensive input sanitization across query layer (backport from main)
2 files changed, 9 insertions(+), 3 deletions(-)
⚠ Watch Out: Never Cherry-Pick Merge Commits Blindly
Running git cherry-pick on a merge commit SHA will fail with 'is a merge but no -m option was given.' Merge commits have two parents, so Git doesn't know which parent's diff to replay. You need git cherry-pick -m 1 <merge-sha> where -m 1 means 'treat parent 1 (main line) as the base.' This is advanced territory — if you're here, strongly consider whether a regular merge or rebase makes more sense.
📊 Production Insight
Cherry-pick is a patch for a workflow problem, not a solution. If you find yourself cherry-picking the same fix to multiple release branches every sprint, the underlying problem is branch strategy. Your release branches are too isolated from main. Your hotfix process does not feed back automatically. Fix the workflow: merge hotfixes to main first, then merge main into release branches. Cherry-pick should be a one-off emergency tool, not a standing process.
🎯 Key Takeaway
Cherry-pick conflicts resolve the same as merge conflicts. Use --no-commit to combine multiple cherry-picks into one clean commit. Never cherry-pick merge commits without -m. If you cherry-pick regularly, redesign your branch strategy.
● Production incidentPOST-MORTEMseverity: high
Cherry-Pick Without Source Annotation: Duplicate Conflicts During Release Merge
Symptom
During the quarterly merge of main into release/3.1, Git reported a conflict in search_query_builder.rb. The conflict was in the security fix had already addressed via cherry-pick 3 weeks earlier. The team could not understand why the fix was conflicting with itself. The release was blocked for 4 hours while the team traced the commit history.
Assumption
The team assumed that once a fix was cherry-picked to a branch, it would be recognized as already applied during a future merge. They did not realize that cherry-pick creates a new commit with a different SHA, and Git treats the two commits as unrelated changes that happened to touch the same lines.
Root cause
1. A SQL injection fix was committed to main as commit abc1234.
2. A developer cherry-picked abc1234 to release/3.1, creating a new commit xyz9999 with the same diff but a different SHA.
3. The developer did not use --edit to note the source SHA in the commit message.
4. Three weeks later, during the quarterly merge, main was merged into release/3.1.
5. Git saw commit abc1234 from main touching the same lines as xyz9999 on release/3.1.
6. Because the SHAs were different, Git treated them as two independent changes to the same file.
7. A merge conflict appeared in the exact lines the cherry-pick had already fixed.
8. The team spent 4 hours tracing the history to understand what happened.
Fix
1. Immediate: resolve the conflict by keeping the existing fix (the cherry-picked version was correct).
2. Going forward: always use git cherry-pick --edit <sha> and append (cherry picked from commit abc1234 on main) to the commit message.
3. Team convention: added a commit message template that includes a 'Cherry-picked-from:' footer for all cherry-picks.
4. Considered git merge --strategy=ours for the future to let Git know the fix was already applied.
Key lesson
Cherry-pick creates a new SHA. Git does not recognise the cherry-picked commit as the same change during future merges.
Always annotate cherry-picked commits with the source SHA using --edit. This is critical for debugging and audit trails.
If you cherry-pick a fix to a release branch and later merge main into that branch, expect a duplicate conflict.
Cherry-pick is a scalpel for one-off emergencies. If you are cherry-picking the same fix to multiple branches regularly, redesign your branch strategy.
Production debug guideSystematic recovery paths for lost stashes, cherry-pick conflicts, and wrong-branch operations.5 entries
Symptom · 01
Stash pop hit a merge conflict — stash is gone from the stack
→
Fix
1. git stash pop deletes the stash even on conflict. The stash is no longer in git stash list.
2. Check reflog: git reflog — find the stash application entry.
3. The stash commit object still exists: git fsck --no-reflogs | grep dangling — find dangling commit objects.
4. Recover: git stash apply <hash> using a hash that looks like your stash.
5. Prevention: use git stash apply when conflicts are possible. Then git stash drop manually after resolving.
Symptom · 02
Cherry-picked commit causes duplicate conflict during later merge
→
Fix
1. The cherry-picked commit has a different SHA from the original. Git treats exact same lines that the them as unrelated changes.
2. Check if the conflict is in the same lines as the cherry-pick: git log --oneline --all --grep='fix'.
3. Resolve by keeping the existing fix (the cherry-picked version is already on the branch).
4. If this happens regularly: use git merge --strategy=ours to tell Git the changes are already applied.
5. Prevention: always annotate cherry-picks with source SHA for traceability.
Symptom · 03
Cannot find which stash has the changes I need
→
Fix
1. List all stashes: git stash list — read the messages (this is why you always use -m).
2. If messages are unhelpful: git stash show -p stash@{N} — full diff of each stash.
3. Search stashes for a specific change: git stash show -p stash@{N} | grep 'search-term' for each N.
4. Or: git log --all --oneline --grep='search-term' — stash entries appear in the log.
Symptom · 04
Cherry-pick failed with 'could not apply' — conflict in progress
→
Fix
1. Run git status to see which files have conflicts.
2. Resolve conflicts in each file — same as merge conflict resolution.
3. Stage resolved files: git add <file>.
4. Continue: git cherry-pick --continue.
5. If too messy: git cherry-pick --abort to return to pre-cherry-pick state.
Symptom · 05
Cherry-pick failed with 'is a merge but no -m option was given'
→
Fix
1. You tried to cherry-pick a merge commit. Merge commits have two parents.
2. Use -m flag: git cherry-pick -m 1 <merge-sha> — parent 1 is the main line.
3. If the result is too complex: consider whether a regular merge or rebase makes more sense.
4. Cherry-picking merge commits is advanced territory — avoid unless you understand the parent structure.
★ Git Stash and Cherry-Pick Triage Cheat SheetFast recovery for stash losses, cherry-pick conflicts, and wrong-branch operations.
Stash pop hit a merge conflict — stash is gone from the stack−
Immediate action
Find the stash commit in reflog before it expires (30 days).
Commands
git reflog | grep stash (find the stash application entry)
Handling Cherry-Pick Conflicts and Knowing When Not to Use I
Key takeaways
1
Git stash is a local-only, history-invisible parking lot for unfinished work
always use -u to include untracked files and always use -m to label your stashes or you'll regret it during a busy sprint.
2
Cherry-pick creates a new commit with a new SHA
the original commit on the source branch is untouched, and Git may not recognise the two as 'the same change' during a future merge, which can cause unexpected conflicts.
3
Use git stash apply over git stash pop whenever a conflict is possible
apply keeps the stash entry intact as a safety copy until you've confirmed the restoration succeeded cleanly.
4
Cherry-pick is a precision scalpel for one-off backports
if you're doing it repeatedly for the same fix across multiple branches, that's your workflow architecture asking to be redesigned, not a sign to cherry-pick more.
5
Stashes > 3 days old should be converted to branches with git stash branch. Stashes are invisible to git branch and git log
if your machine dies, they are gone.
6
Always annotate cherry-picked commits with source SHA using --edit. Without annotation, duplicate conflicts during future merges are untraceable.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
FAQ · 5 QUESTIONS
Frequently Asked Questions
01
Does git stash work across branches?
Yes — a stash entry is stored in the repository, not tied to a specific branch. You can stash on branch A, switch to branch B, and apply the stash there. Just be aware that if the stashed changes touch files that differ significantly on branch B, you may hit merge conflicts when applying.
Was this helpful?
02
Can I cherry-pick multiple commits at once?
Yes. You can list individual SHAs separated by spaces — git cherry-pick abc1234 def5678 — or use a range with git cherry-pick abc1234^..def5678 to pick all commits from abc1234 to def5678 inclusive. Add --no-commit (-n) to stage all the changes first and squash them into a single commit manually.
Was this helpful?
03
What's the difference between git stash pop and git stash apply?
Both restore your stashed changes, but pop removes the stash entry from the stack after applying it, while apply leaves the stash entry intact. If pop hits a merge conflict, it still removes the stash entry — meaning your safety copy is gone while your working directory is in a conflicted state. Use apply when there's any chance of a conflict, and only drop the stash manually once you've confirmed everything looks right.
Was this helpful?
04
Can I recover a stash I accidentally dropped or lost after a pop conflict?
Sometimes. Run git fsck --no-reflogs | grep commit to find dangling commit objects (stash entries are commits internally). You can then run git stash apply <hash> on any hash that looks like your lost stash. This works within the gc.reflogExpire window (default 30 days) as long as you haven't run git gc.
Was this helpful?
05
Why does a cherry-picked commit get a new SHA?
A commit's SHA is a hash of its content, author, timestamp, AND its parent commit. Since the parent on the target branch is different from the parent on the source branch, the hash is different — even if the diff is byte-for-byte identical. This is the same reason rebasing changes SHAs.