141

I am trying to apply changes I stashed earlier with git stash pop and get the message:

Cannot apply to a dirty working tree, please stage your changes

Any suggestion on how to deal with that?

Alexis King
  • 43,109
  • 15
  • 131
  • 205
avernet
  • 30,895
  • 44
  • 126
  • 163

12 Answers12

207

When I have to apply stashed changes to a dirty working copy, e.g. pop more than one changeset from the stash, I use the following:

$ git stash show -p | git apply -3 && git stash drop

Basically it

  1. creates a patch
  2. pipes that to the apply command
  3. if there are any conflicts they will need to be resolved via 3-way merge
  4. if apply (or merge) succeeded it drops the just applied stash item...

I wonder why there is no -f (force) option for git stash pop which should exactly behave like the one-liner above.

In the meantime you might want to add this one-liner as a git alias:

$ git config --global --replace-all alias.unstash \
   '!git stash show -p | git apply -3 && git stash drop'
$ git unstash

Thanks to @SamHasler for pointing out the -3 parameter which allows to resolve conflicts directly via 3-way merge.

muhqu
  • 12,329
  • 6
  • 28
  • 30
  • Is `git stash show -p | git apply` different than `git stash apply`? – Factor Mystic Jan 31 '11 at 19:52
  • 1
    Jo Factor, `git stash apply` will not apply the stashed changes if you have a dirty working copy. So you can see `git stash show -p | git apply` as some sort of forced stash apply. – muhqu Mar 21 '11 at 15:41
  • 1
    doesn't help But help: git reset HEAD and unstash changes after that. – Roger Alien Feb 24 '12 at 01:43
  • This command launched vimdiff for me, which gave me the error "Vim: Warning: Output is not a terminal". This might be because I'm using a diff wrapper script like this: http://technotales.wordpress.com/2009/05/17/git-diff-with-vimdiff/ – Joakim Jun 28 '12 at 17:17
  • @Joakim Yes, you just need to comment out the diff wrapper in .gitconfig and you're good. Remember to uncomment it after applying your changes if you want to continue using vimdiff. – Snowcrash Oct 03 '12 at 14:14
  • I've been using this solution for awhile. Generally it works, but sometimes there can be icky issues applying patches, especially if the patch or underlying code base has changed a lot since the patch was created. Now that I'm more familiar with git, I see the beauty of sergey_mo's "git add, git stash, git reset" solution below – Kirby Nov 19 '13 at 21:26
  • 4
    I get "error: patch failed...patch does not apply" for one of the files. I wish it gave a merge conflict. – Aleksandr Dubinsky Jun 04 '14 at 18:04
  • @AleksandrDubinsky I got around that by doing `git stash show -p | git apply -3` which falls back to 3 way merge. Another option would be to use `--reject` which leaves rejected hunks in *.rej files. – Sam Hasler Jul 11 '14 at 11:10
  • @SamHasler awesome! thanks for pointing that out. I did not yet knew about the `-3` option of `git apply`. thanks. – muhqu Jul 28 '14 at 21:45
  • Wow git is stupid here. I'm trying to pop a stash that has modified file that isn't modified currently, you'd think it would just work.. – Jonathan. Jul 15 '16 at 12:41
  • Why would you want to drop a stash when applying it?! – Iulian Onofrei Mar 17 '17 at 08:51
  • 2
    This solution didn't work for me, it failed with `error: does not match index` for every modified file. However, [another solution](https://stackoverflow.com/a/11627453/1247274) worked. – silvenon Nov 03 '17 at 15:58
64

I do it in this way:

git add -A
git stash apply

and then (optionaly):

git reset
Sergii Mostovyi
  • 1,361
  • 1
  • 15
  • 19
  • 2
    +1! This is simpler than the other solutions that involve generating patches or amending commits, and it keeps your local changes safely isolated from the applied stash changes until you're sure the changes were merged properly. – peterflynn Feb 07 '13 at 20:25
  • I get error "... already exists, no checkout...Could not restore untracked files from stash" – Aleksandr Dubinsky Jun 04 '14 at 18:06
  • 6
    I used `git add -u`, which is like `-A` except it doesn't add untracked files. – Brad Cupit Oct 07 '15 at 01:53
9

You can do this without having to stash your current changes by exporting the stash you want as a patch file and manually applying it.

For example, say you want to apply stash@{0} to a dirty tree:

  1. Export stash@{0} as a patch:

    git stash show -p stash@{0} > Stash0.patch
    
  2. Manually apply the changes:

    git apply Stash0.patch
    

If the second step fails, you will have to edit the Stash0.patch file to fix any errors and then try git apply again.

Michael
  • 8,362
  • 6
  • 61
  • 88
Ishan
  • 1,346
  • 9
  • 11
  • This is practical and workable for the case that, I made refactoring on a dir (removed it, and created a symlink with its name). Git couldn't tell what were my working copy changes. – yclian Jul 16 '10 at 05:20
  • 1
    This worked great. I wasn't able to apply a stash even though I'm pretty sure my working tree is clean. – Shiki Aug 12 '10 at 14:14
  • Yes, I had to remove lines about a binary file. – Dorian Apr 15 '12 at 15:47
8

Either clean your working directory with git reset, commit the changes, or, if you want to stash the current changes, try:

$ git stash save "description of current changes"
$ git stash pop stash@{1}

This will stash the current changes, and then pop the second stash from the stash stack.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
6

Mathias's solution is definitely the closest to a git stash pop --force (and really, c'mon Git devs, let's get this option already!)

However, if you want to do the same thing using only Git commands, you can:

  1. git commit -a -m "Fixme"
  2. git stash pop
  3. git commit -a --amend
  4. git reset HEAD~

In other words, make a commit (which we will never push) of your current changes. Now that your workspace is clean, pop your stash. Now, commit the stash changes as an amendment to your previous commit. Having done that you now have both sets of changes combined in a single commit ("Fixme"); just git reset (--soft NOT --hard so nothing is actually lost) your checkout to "one before that commit", and now you have both sets of changes, completely uncommitted.

EDIT

I just realized it's actually even easier; you can completely skip step 3, so ...

  1. git commit -a -m "Fixme"
  2. git stash pop
  3. git reset HEAD~

(Commit current changes, pop off the stashed changes, reset that first commit to get both sets of changes combined in an uncommitted state.)

Michael
  • 8,362
  • 6
  • 61
  • 88
machineghost
  • 33,529
  • 30
  • 159
  • 234
4

None of these answers actually work if you find yourself in this situation as I did today. Regardless of how many git reset --hard's I did, it got me nowhere. My answer (not official by any means was):

  1. Figure out the stash's hash use git reflog --all
  2. Merge that hash with the branch you're interested in
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
  • 1
    Thanks a lot Yar. I was frustrated by how Git strangely behaved on my local repo just now, the same problem you described. – yclian Jan 19 '11 at 09:17
4

I also found Mathias Leppich's solution to work great so I added an alias for it to my global .gitconfig

[alias]
        apply-stash-to-dirty-working-tree = !git stash show -p | git apply && git stash drop

Now I can just type

git apply-stash-to-dirty-working-tree

which works great for me.

(Your mileage may vary on this long alias name. But I like a dose of verbosity when it comes with bash completion.)

Community
  • 1
  • 1
mat
  • 369
  • 6
  • 10
3

You can apply a stash to a "dirty" tree by doing a git add to stage any changes you've made, thus cleaning up the tree. Then you can git stash pop and apply the stashed changes, no problem.

Chris Vandevelde
  • 1,431
  • 17
  • 23
2

You have files that have been modified but not committed. Either:

git reset --hard HEAD (to bring everything back to HEAD)

or, if you want to save your changes:

git checkout -b new_branch
git add ...
git commit
git checkout -b old_branch
git stash pop
brool
  • 2,105
  • 18
  • 8
0

I was unable to get most of these to work; for some reason it always thinks I have local changes to a file. I can't apply a stash, patches won't apply, checkout and reset --hard fail. What finally worked was saving the stash as a branch with git stash branch tempbranchname, and then doing a normal branch merge: git checkout master and git merge tempbranchname. From http://git-scm.com/book/en/Git-Tools-Stashing :

If you want an easier way to test the stashed changes again, you can run git stash branch, which creates a new branch for you, checks out the commit you were on when you stashed your work, reapplies your work there, and then drops the stash if it applies successfully

Reese
  • 1,746
  • 1
  • 17
  • 40
0

That's my take on the problem that worked for me without problems.

git stash show | patch -p1

Of course it partially resorts to a command outside the git commands family.

Mohammed Safwat
  • 191
  • 2
  • 8
0

I had the same problem but git had zero changed files. Turns out I had a index.lock file that was lying around. Deleting it solved the problem.

boxed
  • 3,895
  • 2
  • 24
  • 26