Resolving conflicts when popping a stash Jump to heading

A stash applies as a merge, so it can conflict — and when it does, the situation is more confusing than an ordinary merge conflict because there is no branch involved and the usual abort commands do not obviously apply. Worse, whether the stash entry survives the failed pop has varied between Git versions, so the first instinct of trying again may find nothing to try. The procedure below is version-independent and starts by establishing what still exists, within stashing and work-in-progress recovery.

When to use this approach Jump to heading

  • git stash pop reported a conflict and you are unsure what state you are in.
  • A stash is several days old and the branch has moved underneath it.
  • The pop half-applied and you want to get back to a clean tree.
  • You need the stash entry back after a failed pop.
  • If the pop succeeded and you simply dislike the result, git checkout -- . after re-stashing is a different and simpler problem.

Step 1 — Establish what still exists before touching anything Jump to heading

# Did the entry survive the failed pop?
git stash list
# What state is the working tree in?
git status --short
git diff --name-only --diff-filter=U        # the conflicted paths
# Verification: conflicted files contain markers; everything else applied cleanly
grep -rl '^<<<<<<<' . --exclude-dir=.git | head
Three states a failed pop can leaveIf the entry survives, nothing is at risk and you can abort freely. If it was dropped, the work exists only in the conflicted working tree and in the stash reflog. If the tree is clean and the entry is gone, the pop succeeded and something else is wrong.Does git stash list still show the entry?yesSafeabort freelyno, tree conflictedCarefulwork is only in the treeno, tree cleanIt appliedthe conflict was resolvedestablishing this first is what stops an abort from discarding the only copy

Step 2 — Resolve the conflicts normally Jump to heading

A stash conflict is an ordinary merge conflict and resolves the same way.

# With zdiff3, the common ancestor is visible, which makes the decision concrete
git config merge.conflictStyle zdiff3
git diff --diff-filter=U
# Resolve each file, then stage it
$EDITOR src/payments/refund.ts
git add src/payments/refund.ts
# Verification: no markers remain anywhere
grep -rl '^<<<<<<<\|^>>>>>>>' . --exclude-dir=.git | wc -l
git diff --name-only --diff-filter=U | wc -l
# Then drop the entry, if it survived
git stash drop

Note that a conflicted pop does not stage the resolution for you the way a merge does — the files are left conflicted in the working tree and the index holds the three stages, so git add after resolving is the step that finishes it.

Step 3 — Abort cleanly if the resolution is not worth it Jump to heading

# Only safe if the entry still exists — check Step 1 first
git stash list | head -1
# Discard the half-applied state, returning to the pre-pop tree
git checkout --merge -- .
git status --short
# Verification: the working tree is clean and the entry is intact
git diff --stat; git stash list | head -1

SAFETY WARNING — do not run git reset --hard to clean up a conflicted pop without first confirming the stash entry still exists. If the pop dropped the entry, the only copy of that work is the conflicted working tree, and a hard reset destroys it with no reflog to recover from. Check git stash list first, every time.

Step 4 — Use stash branch when the base has moved Jump to heading

A stash taken three weeks ago conflicts because the branch has moved, not because the work is wrong. Applying it to its original base removes the conflict entirely.

git stash branch recovered/refund-window stash@{0}
# The branch is created at the commit the stash was taken from, so the apply is clean
git log --oneline -1
git status --short
# Then rebase onto the current branch, resolving once, in a normal rebase
git rebase origin/main
# Verification: the work is on a branch and up to date with the default branch
git merge-base --is-ancestor origin/main HEAD && echo "rebased cleanly"
Why an old stash conflicts and how stash branch avoids itThe stash was taken at an old commit. Popping it onto the current tip asks Git to merge across everything that has landed since. Creating a branch at the original base applies it cleanly, and the rebase that follows is an ordinary one with better tooling around it.apply at the base, then rebasemainBCDEstash taken atBstash branchBWafter rebaseWthe conflict does not disappear — it becomes a rebase conflict, with abort and range-diff available

Step 5 — Recover the entry if the pop dropped it Jump to heading

git reflog stash
# Apply the pre-pop entry from the reflog
git stash apply "$(git reflog stash --format='%H' | head -1)"
# If the reflog is empty too, search unreachable commits
git fsck --unreachable --no-reflogs | awk '$2=="commit" {print $3}' | while read -r c; do
  git log -1 --format='%h %s' "$c" | grep -E 'WIP on|On ' && echo "  → $c"
done
# Verification: the recovered tree contains what you expect
git show --stat "<recovered>"

The full recovery procedure is in recovering a dropped stash; the short version is that the commits survive and the reflog usually still points at them.

The order that cannot lose workCheck whether the entry survived, resolve or abort accordingly, and prefer stash branch when the base has moved far enough that the conflict is really a rebase. Each step is reversible as long as the first one was done.Check the stackentry survived?Resolve or abortonly if safestash branchif the base movedRebase forwardordinary conflictskipping the first box is the only way this procedure loses anything

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

Why does the entry sometimes survive a conflicted pop and sometimes not? Jump to heading

The behaviour has changed across Git versions: a conflicted pop is treated as a failed operation and leaves the entry in current versions, while some older ones dropped it regardless. Rather than remembering which version does what, check the list — it takes a second and the answer is authoritative.

Should I use apply instead of pop routinely? Jump to heading

For anything that might conflict, yes. apply never drops the entry, so the worst case is a stale entry you drop deliberately afterwards. The convenience of pop is not worth the version-dependent behaviour when the apply is uncertain.

Can I preview whether a stash will conflict? Jump to heading

Roughly: git stash show -p stash@{0} | git apply --check - reports whether the patch applies cleanly to the current tree. It is not identical to what the pop will do — a pop performs a merge rather than a patch application — but a failure there is a reliable warning.