Skip to content

Instantly share code, notes, and snippets.

@senthilmurukang
Last active May 10, 2024 15:50
Show Gist options
  • Save senthilmurukang/29b55a0c0e8694c406991799153f3c43 to your computer and use it in GitHub Desktop.
Save senthilmurukang/29b55a0c0e8694c406991799153f3c43 to your computer and use it in GitHub Desktop.
shell script to copy stash from one folder to another. Example usage: ./stash-copy.sh /path/to/git/old/folder /path/to/git/new/folder
src=$1
dest=$2
current_directory=$(pwd)
cd $src
stashes=$(git stash list)
IFS=$'\n'
stash_messages=()
for stash in $stashes; do
stash_number=$(echo $stash | cut -d ':' -f 1 | sed 's/^stash@{\([0-9][0-9]*\)}/\1/g')
stash_message=$(echo $stash | cut -d ':' -f 2- | xargs)
stash_messages+=($stash_message)
git --no-pager stash show "stash@{$stash_number}" -p >"patch_$stash_number"
done
IFS=$' '
cd $dest
echo "Number of stashes: ${#stash_messages[@]}"
for ((i = ${#stash_messages[@]} - 1; i >= 0; i--)); do
git apply "$src/patch_$i"
git stash push -m "${stash_messages[$i]}" > /dev/null
rm "$src/patch_$i"
done
cd $current_directory
@KaranVishnani
Copy link

the line 14 only stash the first available stash.
git --no-pager stash show -p >"patch_$stash_number"

you have to pass the stash_number to create patch file of that paticular stash like below:
git --no-pager stash show "stash@{$stash_number}" -p >"patch_$stash_number"

@senthilmurukang
Copy link
Author

thanks for pointing out! I'll update the gist.

@senthilmurukang
Copy link
Author

the code was updated on 20th Jun 2021

@ryanesrapado
Copy link

ryanesrapado commented May 26, 2022

@senthilmurukang Thanks for the script, now, I also need to export in the same file untracked files that were stashed along with the tracked ones, can you help me with this, I can show them with:
git show stash@{0}^3
But I do not know how to include them along the tracked and stashed ones in the same file and do the reverse process...
git show stash@{0}^3 >> "patch_$stash_number" ?

@ryanesrapado
Copy link

@senthilmurukang
Got it
1- Save staged changes without include untracked changes
git --no-pager stash show stash@{1} -p > patch_1
2- Save staged changes only untracked changes
git diff 4b825dc642cb6eb9a060e54bf8d69288fbee4904 stash@{1}^3 >> patch_1(diff against an empty tree object)
3- Apply staged save in patch_1 fixing trailing whitespaces
git apply --reject --whitespace=fix patch_1

Alternative for step 2 recommended in case git changes its hash algorithm:
git diff $(git hash-object -t tree /dev/null) stash@{1}^3 >> patch_1

Explanation:
4b825dc642cb6eb9a060e54bf8d69288fbee4904 -> Git always has an empty tree in every repository whose ID is the magic number 4b825dc642cb6eb9a060e54bf8d69288fbee4904
stash@{1}^3 -> Untracked Files that were staged
printf "tree 0\0" | sha1sum
git hash-object -t tree /dev/null
git diff $(printf "tree 0\0" | sha1sum | awk '{print $1}') stash@{1}^3 >> patch_1

Source:
https://ericbouchut.com/2021/07/22/git-stash-internals/
https://ah.thameera.com/4b825dc642cb6eb9a060e54bf8d69288fbee4904/

git apply --reject --whitespace=fix patch_1
--whitespace=fix ensures whitespace errors are fixed before path is applied
--reject ensures atomicity (so no working directory files are modified if patch will not apply)

Source:
https://git-scm.com/docs/git-apply(check out for *.rej files with --reject param)

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