Intermediate 4 min · March 06, 2026

Git Cherry-Pick Duplicate Conflict — Missing Source SHA

Cherry-pick creates a new SHA, causing duplicate merge conflicts during later merges.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • 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
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 — 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 — Git Stash Workflow

# ─── 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

# Stash EVERYTHING — 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)
On branch feature/payment-gateway
nothing to commit, working tree clean
# After git stash list
stash@{0}: On feature/payment-gateway: wip: payment gateway refactor — stripe adapter half done
# After git stash pop
On branch feature/payment-gateway
Changes not staged for commit:
modified: payment_gateway.rb
Untracked files:
stripe_adapter.rb
Dropped stash@{0} (a3f1c2d...)
Watch Out: Stash Pop Conflicts Are Silent Killers
  • pop deletes the stash from the stack before you resolve conflicts
  • If the apply fails, you have no stash backup — the entry is gone
  • Use apply when conflicts are possible. Then drop manually after resolving.
  • This is one of the most common Git footguns in production.
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.

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 — Managing Multiple Stashes

# ─── 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}

# Apply ONLY 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

# ─── POWER MOVE ────────────────────────────────────────────────────────────
# The JWT 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
# git stash show -p stash@{1} (abbreviated)
diff --git a/validators/email_validator.js b/validators/email_validator.js
index 3a2c1f0..8b4e9d2 100644
--- a/validators/email_validator.js
+++ b/validators/email_validator.js
@@ -14,6 +14,11 @@ function validateEmailFormat(email) {
+ // RFC 5322 compliant check added
+ const rfcPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
# git stash branch feature/jwt-refresh stash@{0}
Switched to a new branch 'feature/jwt-refresh'
On branch feature/jwt-refresh
Changes not staged for commit:
modified: auth/token_manager.js
Dropped stash@{0} (b7d3a1e...)
Pro Tip: Stash Partial Changes With --patch
  • git stash push -p: interactive hunk-by-hunk selector, like git add -p
  • 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 — Git Cherry-Pick Workflow

# ─── 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 NEW SHA (different from abc1234)
git log --oneline -3
# xyz9999 fix: sanitize user input in search query builder  <-- new SHA!
# aaa1111 chore: bump version to 3.1.0
# bbb2222 feat: order confirmation email template

# ─── CHERRY-PICKING A RANGE ────────────────────────────────────────────────
# If you need commits abc1234 AND def5678 (but NOT ghi9012), use dot-dot notation.
# The range abc1234..def5678 means: commits AFTER abc1234 up to AND including def5678.
# To INCLUDE abc1234 itself, use the caret on the start: abc1234^..def5678
git cherry-pick abc1234^..def5678

# ─── CHERRY-PICK WITH EDIT ─────────────────────────────────────────────────
# --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)
Interview Gold: SHA Changes After Cherry-Pick
  • Commit SHA = hash(content + author + timestamp + parent SHA)
  • 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.

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-Pick Conflict Resolution

# ─── 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: BAIL OUT CLEANLY ─────────────────────────────────────────
# 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-COMMIT MODE: COMBINE MULTIPLE CHERRY-PICKS INTO ONE COMMIT ─────────
# 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
  • git cherry-pick <merge-sha> fails: 'is a merge but no -m option was given'
  • Use -m 1 to specify parent 1 (main line) as the base
  • Use -m 2 to specify parent 2 (merged branch) as the base
  • If result is too complex: consider regular merge or rebase instead
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)
git fsck --no-reflogs | grep dangling (find dangling commit objects)
Fix now
git stash apply <hash> to recover. Prevention: use apply instead of pop when conflicts are possible.
Cherry-pick conflict — 'could not apply'+
Immediate action
Resolve conflicts, stage, then continue.
Commands
git status (see conflicted files)
git cherry-pick --continue (after resolving and staging)
Fix now
If too messy: git cherry-pick --abort to return to pre-cherry-pick state.
Cherry-pick failed on merge commit — 'no -m option given'+
Immediate action
Merge commits have two parents. Specify which parent to use.
Commands
git cat-file -p <merge-sha> (see parent SHAs)
git cherry-pick -m 1 <merge-sha> (use parent 1 as base)
Fix now
If result is too complex: consider regular merge or rebase instead.
Cannot find which stash has my changes+
Immediate action
Search stash diffs for the specific change.
Commands
git stash list (read messages — this is why you always use -m)
git stash show -p stash@{N} | grep 'search-term' (search each stash diff)
Fix now
Always label stashes: git stash push -m 'description'. Unnamed stashes are mystery boxes.
Stashed changes on wrong branch — working directory has wrong files+
Immediate action
Do not commit. Reset the branch to clean state.
Commands
git reset --hard HEAD (undo the stash application)
git checkout <correct-branch> (switch to where you need the stash)
Fix now
git stash apply stash@{0} on the correct branch. If stash is gone: recover via reflog.
Git Stash vs Cherry-Pick Compared
Feature / Aspectgit stashgit cherry-pick
PurposeTemporarily park in-progress workCopy a specific commit to another branch
Creates a commitNo — stores in a local stash stackYes — creates a new commit with a new SHA
Visible in git logNo — stash is hidden from historyYes — appears as a regular commit
Synced to remoteNo — stash is local onlyYes — cherry-picked commit pushes normally
ScopeWorking directory + staging areaEntire commit (all changed files in that commit)
ReversibleYes — pop, apply, or drop cleanlyHarder — requires a revert commit or reset
Primary use caseContext-switching mid-featureBackporting a hotfix to a release branch
Conflict riskLow (restoring to same branch)Medium-High (branches may have diverged)
Survives branch deletionYes — stash outlives branchesN/A — cherry-pick is an action, not a storage
Works across reposNo — local repo onlyNo — but you can fetch a remote branch first

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?
02
Can I cherry-pick multiple commits at once?
03
What's the difference between git stash pop and git stash apply?
04
Can I recover a stash I accidentally dropped or lost after a pop conflict?
05
Why does a cherry-picked commit get a new SHA?
🔥

That's Git. Mark it forged?

4 min read · try the examples if you haven't

Previous
Git Rebase vs Merge
4 / 19 · Git
Next
Git Workflows — GitFlow