Skip to content

Instantly share code, notes, and snippets.

@here
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save here/4f3af6dafdb4ca15e804 to your computer and use it in GitHub Desktop.
Save here/4f3af6dafdb4ca15e804 to your computer and use it in GitHub Desktop.
How to resolve git stash pop merge conflict with unstaged changes
# trying to replicate and solve this situation:
# http://stackoverflow.com/questions/8515729/aborting-a-stash-pop-in-git/
# tl;dr, if you didn't have any staged changes, this should work:
git diff --name-only --cached|xargs git checkout --ours HEAD
git ls-tree stash@{0}^3 --name-only|xargs rm
# If there were no untracked files introduced from the stash
# then the second command will fail with
# fatal: Not a valid object name stash@{0}^3
# this is expected.
# Questions:
# Q: Is it possible to have merge conflicts in a file with unstaged changes?
# A: I don't think so since the git stash pop will fail as shown below.
# Q: Does this fail in some cases with staged changes?
# A: tbd... (See end, and stackoverflow answers)
# Without staged changes
# Setup and resolution
# Use `setopt interactivecomments` to ask shell to ignore # comments
git init
touch a
touch m
git add .
git commit -m "a m"
echo one > a
touch b
git add b
git commit -am "a=one b"
echo stash > m
echo stash > b
echo stash > c
git stash save -u "m=stash b=stash c=stash"
echo one > b
# git stash pop
# fails with "Your local changes to the following files would be overwritten by merge"
# fails with "Please, commit your changes or stash them before you can merge."
git commit -am "b=one"
# touch c
# git stash pop
# fails with "c already exists, no checkout"
echo two > a
touch d
git stash pop
# Result:
# Merge succeeded in m (theirs)
# Conflict in b
# Unstaged in a
# Untracked in c and d
# Goal:
# Reverse changes to successful merge m
# Keep our version in merge conflict b
# Keep our unstaged a
# Keep our untracked d
# Delete stashed untracked c
# Step 1
# List all staged or conflicting files by name
# Checkout each of these files using --ours HEAD which will:
# - undo successful merges to HEAD with old version
# - resolve any conflicted files with old version
# - leave any unstaged or untracked files untouched
git diff --name-only --cached | xargs git checkout --ours HEAD
# Unstaged and modified
# No action needed, they are all ours or the stash pop would fail
# Untracked files
# Goal: delete untracked files which were introduced by the stash pop
# see also: http://stackoverflow.com/questions/12681529/in-git-is-there-a-way-to-show-untracked-stashed-files-without-applying-the-stas
#
# List all untracked files from the stash
# Delete each of these files using xargs rm
git ls-tree stash@{0}^3 --name-only | xargs rm
#########
# Staged changes:
# If you have staged files, it is possible to end up in a situation where it is more difficult to tell if a
# change originated from the stash. A modified and staged file may contain changes existing in both the
# stash and the pre-stash state.
#
# In the following case, a=two both before and after the stash.
#
# I believe the above commands will still work in most of these cases, but I am suspect of clever evasion.
git init
echo one > a > b
git add a b
git commit -a -m "a=one b=one"
echo two > a
echo three > b
git stash
echo two > a > b
git add a b
git stash pop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment