85

This is a pipeline on branch frontend over the last two weeks.

| Stash@{3} is all code since Stash@{1} (excluding the two tiny commits)
| Tiny Commit
| Tiny commit
| Huge bulk commit two weeks ago, now rebased and moved to Stash@{1}

My working tree is currently clean.
Stash@{1} is the contents from a bulk commit of general development code two weeks ago (this should have been stashed in the first place). This commit was undone and moved to stash.
Stash@{3} is the newest work on that tree since Stash@{1} (minus a couple of changes that have been committed).

I need to combine these two stashes together in my working tree so I can make a number of commits from this huge pool of work.

I ran git stash apply stash@{1} then I tried:

git stash apply stash@{3}
git stash show -p | git stash apply stash@{3}

but I get 'dirty working tree' in both cases. How can I merge this work together? Because stash@{3} is newer, I want it to supersede stash@{1} wherever there are conflicts.

sscirrus
  • 55,407
  • 41
  • 135
  • 228

5 Answers5

150

It's a little involved, but this almost always works:

  1. Pop the first stash

    $ git stash pop
    
  2. Temporarily commit the changes from the first stash

    $ git add . && git commit -am 'WIP'
    
  3. Pop the second stash

    $ git stash pop
    
  4. Undo the temporary commit, keeping the changes it introduced

    $ git reset --soft HEAD^
    
bkeepers
  • 2,135
  • 2
  • 16
  • 9
  • 10
    Took me awhile to appreciate the beauty of this. It works much better than trying to apply a patch, which often fails due to whitespace or file path changes – Kirby Jan 24 '14 at 17:34
  • 2
    Don't forget to reset your file after it to see the unified change in `git diff`, because currently the reseted change is staged and seen separately as `git diff --staged`. – Nakilon Nov 06 '15 at 11:33
  • 2
    This seems like the best solution, but I still don't understand why we can't simply pop an existing stash while we have unstaged changes. For example, it would be nice to simply run `git stash pop` followed by `git stash pop`. Perhaps I'm missing something about the git stash internals. – modulitos Apr 04 '17 at 18:17
  • If popping the second stash gives merge conflicts (which is when two consecutive pops don't work), you also need a `git add ` after fixing the conflicts. – Sameer Jul 12 '17 at 19:53
  • 2
    @Nakilon alluded to this, but I would add the following as step 5 (entered from the project's root directory): `git reset HEAD .` – Grant Humphries Jan 10 '19 at 21:09
  • Doesn't work too well if you have changes... – Att Righ May 16 '23 at 11:20
55

You can only apply a stash if there are no conflicts with modified files in the working tree, so, first, ensure there are no modified files in git status, if there are, commit them. Then do:

git stash apply stash@{1}
git commit -a
# Enter your commit message
git stash apply stash@{3}

Then you can either make a new commit, or amend the previous one to combine them. You may need to resolve merge conflicts after each apply.

Also, if you ever decide to use git stash pop rather than apply, note that stash@{3} would become stash@{2} since the first one was popped off.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • 4
    The two stashes are large and contain a lot of overlapping work, which is why I wanted to avoid the commits. Is it possible to just combine them in the working tree, or am I forced to commit these large chunks and then combine 2 crappy commits and split them into ~10 good commits in vim? – sscirrus Feb 04 '12 at 19:45
  • The other thing is: _I don't want to commit all this code_. Significant chunks of it are still for development-only. – sscirrus Feb 04 '12 at 19:48
  • 9
    What's the difference between combining them in the working tree and amending? Or doing a `git reset HEAD^` after the second stash is applied? You cannot apply a stash on a dirty working tree, so you *must* commit before applying one, but that doesn't mean you can't undo that commit after you've applied. – Andrew Marshall Feb 04 '12 at 19:50
  • @AndrewMarshall "You can only apply a stash to a clean working tree" .... is this still up to date and accurate? – Bradley Thomas Dec 01 '16 at 20:22
16

This worked for me.

  1. stage the current changes (if nothing in unstaged, skip this step)

    git add .
    
  2. apply the stash you wish

    git stash apply stash@{0}
    
  3. stage the current changes

    git add .
    

    or git add <stashed_filename>

  4. Continue step 2&3 multiple times

  5. then un stage everything

    git reset 
    

DONE!

NIKHIL C M
  • 3,873
  • 2
  • 28
  • 35
15

A better way is to just use git stash show -p stash@{whatever} > stash-{whatever}.diff and then use git apply for each one.

siride
  • 200,666
  • 4
  • 41
  • 62
  • 1
    This is by far the most straightforward if the changes don't overlap. I feel silly to have to make commits just to merge the content. – Marcelo Diniz Dec 22 '13 at 11:06
  • 1
    @MarceloDiniz: there always has to be a commit if the content changes. Not silly at all. – siride Dec 22 '13 at 16:12
  • Applying a stash as a patch will work if the stash is fairly trivial but won't work if there have been intermediate, non-trivial whitespace changes or changes in file paths – Kirby Jan 24 '14 at 17:35
  • @Kirby: you could apply the stashes in a different order and only use the patch method on the simpler one. Better would be to take care not to have large numbers of stashes with complex changes. That's not a safe workflow. – siride Jan 25 '14 at 06:09
  • 3
    No need for an intermediate file, just pipe right into `git apply`: `git stash show stash@ | git apply -`. – Andrew Marshall Nov 11 '14 at 00:38
  • 4
    For four and a half years I had "stask" in there and nobody noticed until now. – siride Nov 11 '14 at 01:11
  • I think you mean with a -p like this: git stash show -p stash@{whatever} > stash-{whatever}.diff. Other than that your answer is the best one – Moataz Elmasry Dec 12 '14 at 13:44
  • git apply doesn't seem to work on the output of `stash show -p` output: `error patch failed` however using `patch -p1 stash-{whatever}.diff` worked well, finally a sane'ish way to do this, ai ai. – rogerdpack May 13 '16 at 20:57
  • Be sure to be in the top-level directory or the `git apply` will silently fail, as I discovered... – Jeff Trull Jan 04 '21 at 20:41
3

I had a similar problem and solved it like this.

Use git stash pop to apply one of the stashes. Then create a patch of this stash with git diff -p > ../stash.diff. You can then reset your working tree (or stash the changes again), and pop the other stash with git stash pop stash@{1}. If you apply your patch at this moment you can 'merge' the two different stashes.

You'll probably have some conflicts to resolve. If all goes well you can then drop the stashed changes.

Henridv
  • 766
  • 12
  • 23
  • Or just pull stash@{1} out as a diff and apply that locally (for example siride's answer and comments) but this works too, thanks! – rogerdpack May 13 '16 at 20:58