Skip to content

Instantly share code, notes, and snippets.

@alexeds
Created September 5, 2012 18:00
Show Gist options
  • Save alexeds/3641372 to your computer and use it in GitHub Desktop.
Save alexeds/3641372 to your computer and use it in GitHub Desktop.
Move your stashes from one repo to another

Move your stashes from one repo to another


This was useful for me when we created a new branch for a new major release, but were still working on our current version as well. I cloned our repo again and kept the new project on our new branch, but also wanted to get my stashes there.

Download your stashes

git stash show -p > patch

You'll have to specify your stash and name your file whatevery you want. Do this for as all your stashes, and you'll have patch files in your pwd.

Apply your stashes

cd /new/project/dir
git apply /old/project/dir/patchfile
git stash
@abiemann
Copy link

abiemann commented Aug 8, 2019

I made a stash that included untracked files... this is the result :
error: cannot apply binary patch to 'blah_blah.aar' without full index line

@calerocalero
Copy link

Got errors...
$git apply patch
error: patch failed: .../public_html/WEB-INF/web.xml:220
error: .../public_html/WEB-INF/web.xml: patch does not apply

@Thilakeswar
Copy link

Is there a way to move all the stashes from one repo to another repo. I have around 50 stashes in my old repo which needs to be moved to my new repo. Any way I can move the all the stashes in one go?

@mjakubowski
Copy link

if your patch can't be applied, it might be because of color information being exported as well. in that case generate patch without color:
git stash show --no-color -p > patch

@applejag
Copy link

applejag commented Apr 1, 2020

To extend @mjakubowski's answer, if you have a custom pager (such as so-fancy/diff-so-fancy or dandavison/delta) then disabling the pager helps:

git --no-pager stash show -p > patch

@eerikmikael
Copy link

Thanks! This just works!

@suryakun
Copy link

Thank you, it save my time..

@dermoth
Copy link

dermoth commented Jun 18, 2020

While this works, it does not replicate stashes as-is. A stash is a special merge commit of the work tree between the base commit and the index. One way could be to save each as separate patches, checkout the stash first parent, restore the index and work tree from the two patches (I haven't checked this but it could be non-trivial) and finally restore the stash.

This is needed to fully recreate all information from the stash, and if you don't care about that you should at the very least checkout the stash's first parent before restoring to avoid conflicts and keep track of where the stash was created.

This is what I did to fully restore all stashes from one repo to another. If you can't have them on the same computer, you can save the stash tags in a bundle after creating them and copy the refs list and bundle to the target computer.

From the root of the original repo:

  1. Get the list of stash refs
  2. Tag your stash refs so you can retrieves them with git fetch (the tag names doesn't mater, change it if there is a conflict. I used stash_ + the number(s) in the logical stash ref)
  3. Convert the logical refs to sha1 hashes in reverse order - we'll use them later
  4. Save that repo path - also for later
refs=$(git stash list|cut -d: -f1)
for ref in $refs; do git tag stash_${ref//[^0-9]} $ref; done
refs=$(git rev-parse $refs|tac)
oldpath=$PWD

NB: This requires bash or compatible shell (ksh, zsh should do...) You could also increment a variable, ex stash_$((i++)) if your shell doesn't support ${param//pattern}

Now in the new repo, for each ref:

  1. Fetch the ref from the old repo (we don't even need to use the tag names, because we have tagged them we can retrieve them with git fetch)
  2. Re-import the stash from the ref, using that ref's subject as the stash message.
for ref in $refs; do git fetch $oldpath $ref; git stash store -m "$(git show -s --pretty=%s $ref)" $ref; done

@slaingod
Copy link

slaingod commented Jul 4, 2020

for ref in $refs; do git fetch $oldpath $ref; git stash store -m "$(git show -s --pretty=%s $ref)" $ref; done

Thank you so much @dermoth! This worked flawlessly when I switched from having 4 copies of my repo (repo sets actually, using mu-repo) to a single copy with worktrees, I needed to merge my stashes from the various copies. Worked like a charm in Git Bash, with one typo fix....needed to use 'do git tag' instead of 'do tag'.

@dermoth
Copy link

dermoth commented Jul 4, 2020

You're welcome @slaingod and thanks for pointing out the typo... I also posted in on StackOverflow for a similar question.

@13501275443
Copy link

Nice sharing!

@adrianosotos
Copy link

Thanks!! Works very well

@dallas
Copy link

dallas commented Nov 6, 2020

@dermoth, in zsh I needed to wrap the creation of the two refs arrays in (…), otherwise I just ended up with a single string element:

refs=($(git stash list | cut -d: -f1))
for ref in $refs; do git tag stash_${ref//[^0-9]} $ref; done
refs=($(git rev-parse $refs | tac))
oldpath=$PWD

Other than that, your solution works a treat! Thank you! 🙏 🙇

@mshafeeqkn
Copy link

I have one other solution.

  1. update both source and destination repository using git pull or git fetch
  2. copy the .git folder from the source repository to the destination repository.

This method will be more simple if you have multiple stashes. But may take more time to copy if your repo is too big.

@spielhoelle
Copy link

Super useful 🚀

@amazgarov
Copy link

Thank you very much @dermoth! Your solution was very helpful!

@astery
Copy link

astery commented Sep 24, 2021

If git fails to apply the patch, you can resolve conflicts manually by adding a -3 flag.

git apply -3 ./mypatch

@dlsso
Copy link

dlsso commented Jan 30, 2022

Thanks! Note that (at least as of 2.25.1) git saves the patch to patch (not patchfile) by default, so the instructions should read

git apply /old/project/dir/patch

@charris-msft
Copy link

I tried it on Windows and the apply didn't work until I opened the patch file in Notepad and saved it again with UTF-8 encoding instead of UTF-16LE.
After a little testing, this issue occurred because I ran the stash command from PowerShell.
Running the stash command from Command Prompt created it with UTF-8 encoding.

Otherwise, worked great!
Big thanks!

@TonyWhitley
Copy link

Thanks dermoth, that worked straight out of the box in Git Bash for Windows, after I broke out a couple of steps to verify them first.

@stuartbrussell-intuit
Copy link

Thank you!

@LukasBott
Copy link

Thank you. git apply is super useful. I feel a little bit more powerful with git now :-D

@coroa
Copy link

coroa commented Feb 16, 2023

@dermoth I wondered why you were even tagging the commits, since git fetch is able to retrieve individual commits, as long as you use full hashes.

To transfer all stashes from an old repository to a new one, you can (on zsh):

  1. Grab hashes of all references in the stash (in reverse order), on linux-alike,
cd /path/to/old/repo
hashes=($(git reflog --format=%H refs/stash | tac))

or on BSD-alike, like MacOSX,

cd /path/to/old/repo
hashes=($(git reflog --format=%H refs/stash | tail -r))
  1. Switch to new repository, fetch them and put them back into the stash reflog
cd /path/to/new/repo
git fetch /path/to/old/repo $hashes
for hash in $hashes; do git stash store -m "$(git show -s --format=%s $hash)" $hash; done

EDIT: Fixed erroneous command rev and replaced with tac and tail -r depending on the flavour.

@sc420
Copy link

sc420 commented May 2, 2023

If you want to include untracked files in the patch, you can use --include-untracked, for example to output the patch from stash stash@{2}:

git stash show --include-untracked --patch 2

There's also a counterpart option --only-untracked.
You can also set git config stash.showIncludeUntracked to true save this trouble:

git config --global stash.showIncludeUntracked true

or in .gitconfig:

[stash]
showIncludeUntracked = true

@marktefftech
Copy link

Great tip, thanks

@nhuphuoc-bic
Copy link

Awesome, thanks!!!

@jancimajek
Copy link

@dermoth & @dallas -- thanks, this worked perfectly!

@andy-shev
Copy link

andy-shev commented Jan 4, 2024

@dermoth, in zsh I needed to wrap the creation of the two refs arrays in (…), otherwise I just ended up with a single string element:

refs=($(git stash list | cut -d: -f1))
for ref in $refs; do git tag stash_${ref//[^0-9]} $ref; done
refs=($(git rev-parse $refs | tac))
oldpath=$PWD

Other than that, your solution works a treat! Thank you! 🙏 🙇

Much easier is to have

git stash list | cut -d: -f1 | while read ref; do ...

It will work in any shell.

@andredsp
Copy link

@coroa For macOS, I had to replace rev with tail -r. Otherwise, this worked great!

To transfer all stashes from an old repository to a new one, you can:

  1. Grab hashes of all references in the stash (in reverse order):
cd /path/to/old/repo
hashes=($(git reflog --format=%H refs/stash | rev))

macOS version:

hashes=($(git reflog --format=%H refs/stash | tail -r))
  1. Switch to new repository, fetch them and put them back into the stash reflog
cd /path/to/new/repo
git fetch /path/to/old/repo $hashes
for hash in $hashes; do git stash store -m "$(git show -s --format=%s $hash)" $hash; done

@coroa
Copy link

coroa commented Feb 23, 2024

@andredsp Glad it was of help! Thanks for the hint! Fixing it above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment