How do I save/apply a stash with a name? I don't want to have to look up its index number in git stash list
. I tried git stash save "my_stash_name"
, but that only changes the stash description, and the corresponding git apply "my_stash_name"
doesn't work.
git stash push -m stashname
is the current syntax. git stash save stashname
has been deprecated. - anyone git bottle name
and then later git apply name.patch
, see my answer if you want a fuller explanation and usage samples. - anyone To save a stash with a message:
git stash push -m "my_stash_name"
Alternatively (deprecated since v2.16):
git stash save "my_stash_name"
To list stashes:
git stash list
All the stashes are stored in a stack.
To pop (i.e. apply and drop) the n
th stash:
git stash pop stash@{n}
To pop (i.e. apply and drop) a stash by name is not possible with git stash pop
(see footnote-1).
To apply the n
th stash:
git stash apply stash@{n}
To apply a stash by name:
git stash apply stash^{/my_stash_name}
footnote-1:
See the man git-stash
section regarding apply
:
Unlike pop, may be any commit that looks like a commit created by stash push or stash create.
Possible workaround (tested on git version 2.27 and 2.31):
git stash pop $(git stash list --pretty='%gd %s'|grep "my_stash_name"|head -1|gawk '{print $1}')
Answered 2023-09-20 20:33:30
git stash apply <custom-name>
- anyone git stash push -m my_stash
is the current syntax. git stash save my_stash
has been deprecated. - anyone git stash apply "stash@{n}"
- anyone git stash push -m my_stash
, then did git stash apply my_stash
and it gave an error. git stash apply stash^{/my_stash}
did the job. Got this one from another answer by @Cameron McKenzie. - anyone git stash save
is deprecated as of 2.15.x/2.16, instead you can use git stash push -m "message"
You can use it like this:
git stash push -m "message"
where "message" is your note for that stash.
In order to retrieve the stash you can use: git stash list
. This will output a list like this, for example:
stash@{0}: On develop: perf-spike
stash@{1}: On develop: node v10
Then you simply use apply
giving it the stash@{index}
:
git stash apply 1
References git stash man page
Answered 2023-09-20 20:33:30
push
rather than save
syntax: git stash push - anyone git stash push
: stackoverflow.com/a/47231547/6309 - anyone git stash apply stash@{1}
in Powershell you will get a error: unknown switch 'e'
back. Instead use git stash apply --index 1
or git stash apply 'stash@{1}'
or escape }
and {
with a backtick `. - anyone stash@{1}
? This is really hard to type on command line. If we can type something like git stash show -p @1
would be much easier... - anyone If you are just looking for a lightweight way to save some or all of your current working copy changes and then reapply them later at will, consider a patch file:
# save your working copy changes
git diff > some.patch
# re-apply it later
git apply some.patch
Every now and then I wonder if I should be using stashes for this and then I see things like the insanity above and I'm content with what I'm doing :)
Answered 2023-09-20 20:33:30
git apply --3way some.patch
. This is more similar to the traditional git stash apply
approach. Otherwise, conflicts can cause the patch apply to fail - anyone You can turn a stash into a branch if you feel it's important enough:
git stash branch <branchname> [<stash>]
from the man page:
This creates and checks out a new branch named <branchname>
starting from the commit at which the <stash>
was originally created, applies the changes recorded in <stash>
to the new working tree and index, then drops the <stash>
if that completes successfully. When no <stash>
is given, applies the latest one.
This is useful if the branch on which you ran git stash save
has changed enough that git stash apply fails due to conflicts. Since the stash is applied on top of the commit that was HEAD at the time git stash was run, it restores the originally stashed state with no conflicts.
You can later rebase this new branch to some other place that's a descendent of where you were when you stashed.
Answered 2023-09-20 20:33:30
git stash apply
) - anyone git stash push -m 'name'
worked. - anyone I have these two functions in my .zshrc
file:
function gitstash() {
git stash push -m "zsh_stash_name_$1"
}
function gitstashapply() {
git stash apply $(git stash list | grep "zsh_stash_name_$1" | cut -d: -f1)
}
Using them this way:
gitstash nice
gitstashapply nice
Answered 2023-09-20 20:33:30
stashput = "!f() { git stash push -m "stash_name_$1"; }; f"
. stashget = "!f() { git stash apply $(git stash list | grep 'stash_name_$1' | cut -d: -f1); }; f"
. Then in your sh config (e.g. .bashrc or .bash_aliases). ## git stash by name. alias gsp="git stashput " alias gsg="git stashget "
. now you can use it on the CLI like: prompt# gsp localchanges
. prompt# gsg localchanges
. - anyone grep -m 1 "zsh_stash_name_$1"
just so it returns the first result if the same name was used multiple times: stackoverflow.com/a/5013198/4984618 - anyone So, I'm not sure why there's so much consternation on this topic. I can name a git stash
with both a push
and the deprecated save
, and I can use a regex to pull it back with an apply
:
$ git stash push -m "john-hancock"
$ git stash apply stash^{/john-hancock}
As it has been mentioned before, the save
command is deprecated, but it still works, so you can used this on older systems where you can't update them with a push
call. Unlike the push
command, the -m
switch isn't required with save
.
// save is deprecated but still functional
$ git stash save john-hancock
This is Git 2.2 and Windows 10.
Here's a beautiful animated GIF demonstrating the process.
The GIF runs quickly, but if you look, the process is this:
ls
command shows 4 files in the directorytouch example.html
adds a 5th filegit stash push -m "john-hancock" -a
(The -a
includes untracked files)ls
command shows 4 files after the stash, meaning the stash and the implicit hard reset workedgit stash apply stash^{/john-hancock}
runsls
command lists 5 files, showing the example.html file was brought back, meaning the git stash apply
command worked.To be frank, I'm not sure what the benefit of this approach is though. There's value in giving the stash a name, but not the retrieval. Maybe to script the shelve and unshelve process it'd be helpful, but it's still way easier to just pop a stash by name.
$ git stash pop 3
$ git stash apply 3
That looks way easier to me than the regex.
Answered 2023-09-20 20:33:30
Stashes are not meant to be permanent things like you want. You'd probably be better served using tags on commits. Construct the thing you want to stash. Make a commit out of it. Create a tag for that commit. Then roll back your branch to HEAD^
. Now when you want to reapply that stash you can use git cherry-pick -n tagname
(-n
is --no-commit
).
Answered 2023-09-20 20:33:30
named commit
hanging out somewhere. Only mild annoyance is that it doesn't get committed upon cherry pick and stays in the diff, which means it will need to be manually not checked in during the next commit. - anyone --no-stage
option! Related: stackoverflow.com/questions/32333383/… - anyone git reset @
is pretty painless. - anyone use git stash push -m aNameForYourStash
to save it. Then use git stash list
to learn the index of the stash that you want to apply. Then use git stash pop --index 0
to pop the stash and apply it.
note: I'm using git version 2.21.0.windows.1
Answered 2023-09-20 20:33:30
git stash {push,save}
- anyone What about this?
git stash save stashname
git stash apply stash^{/stashname}
Answered 2023-09-20 20:33:30
git stash apply stash^{/<regex>}
doesn't work (it doesn't actually search the stash list, see the comments under the accepted answer). - anyone git stash list
that shows me the stashes along with their associated index number I then go 2. git stash apply 0
- where 0 is the index number I would have looked up from the first command - anyone $ git stash push -m "say-my-name"
$ git stash apply stash^{/say-my-name}
Answered 2023-09-20 20:33:30
Stash can be custom commented using following command.
PS D:\git-example> git stash -m "your comment"
list the stash
PS D:\git-exapmle> git stash list
stash@{0}: On master: first stash
stash@{1}: On master: second stash
we can pick any stash, we have to pass the stash@{x}, bellow I am picking second stash which is 1.
PS D:\git-example> git stash pop 1
Answered 2023-09-20 20:33:30
push
doesn't mean the same thing here as git push
. Stashes are always local. You are "pushing" the stash on the top of the stash stack. And later you "pop" it off the top. - anyone sapply = "!f() { git stash apply \"$(git stash list | awk -F: --posix -vpat=\"$*\" \"$ 0 ~ pat {print $ 1; exit}\")\"; }; f"
git sapply "<regex>"
Edit: I sticked to my original solution, but I see why majority would prefer Etan Reisner's version (above). So just for the record:
sapply = "!f() { git stash apply \"$(git stash list | grep -E \"$*\" | awk \"{ print $ 1; }\" | sed -n \"s/://;1p\")\"; }; f"
Answered 2023-09-20 20:33:30
awk -F: '{print $1}'
would eliminate the need for the sed entirely. Also why wrap this in a function? And using awk -F: -vpat="$*" '$0 ~ pat {print $1}'
should allow dropping the grep as well. Though might require slightly different quoting for the pattern. - anyone {print $1; exit}
to quit after the first matched line. - anyone It's unfortunate that git stash apply stash^{/<regex>}
doesn't work (it doesn't actually search the stash list, see the comments under the accepted answer).
Here are drop-in replacements that search git stash list
by regex to find the first (most recent) stash@{<n>}
and then pass that to git stash <command>
:
# standalone (replace <stash_name> with your regex)
(n=$(git stash list --max-count=1 --grep=<stash_name> | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash show "$n" ; else echo "Error: No stash matches" ; return 1 ; fi)
(n=$(git stash list --max-count=1 --grep=<stash_name> | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash apply "$n" ; else echo "Error: No stash matches" ; return 1 ; fi)
# ~/.gitconfig
[alias]
sshow = "!f() { n=$(git stash list --max-count=1 --grep=$1 | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash show "$n" ; else echo "Error: No stash matches $1" ; return 1 ; fi }; f"
sapply = "!f() { n=$(git stash list --max-count=1 --grep=$1 | cut -f1 -d":") ; if [[ -n "$n" ]] ; then git stash apply "$n" ; else echo "Error: No stash matches $1" ; return 1 ; fi }; f"
# usage:
$ git sshow my_stash
myfile.txt | 1 +
1 file changed, 1 insertion(+)
$ git sapply my_stash
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: myfile.txt
no changes added to commit (use "git add" and/or "git commit -a")
Note that proper result codes are returned so you can use these commands within other scripts. This can be verified after running commands with:
echo $?
Just be careful about variable expansion exploits because I wasn't sure about the --grep=$1
portion. It should maybe be --grep="$1"
but I'm not sure if that would interfere with regex delimiters (I'm open to suggestions).
Answered 2023-09-20 20:33:30
Alias This might be a more direct syntax for Unix-like systems without needing to encapsulate in a function. Add the following to ~/.gitconfig under [alias]
sshow = !sh -c 'git stash show stash^{/$*} -p' -
sapply = !sh -c 'git stash apply stash^{/$*}' -
ssave = !sh -c 'git stash save "${1}"' -
Usage: sapply regex
Example: git sshow MySecretStash
The hyphen at the end says take input from standard input.
Answered 2023-09-20 20:33:30
This answer owes much to Klemen Slavič. I would have just commented on the accepted answer but I don't have enough rep yet :(
You could also add a git alias to find the stash ref and use it in other aliases for show, apply, drop, etc.
[alias]
sgrep = "!f() { ref=$(git --no-pager stash list | grep "$1" | cut -d: -f1 | head -n1); echo ${ref:-<no_match>}; }; f"
sshow = "!f() { git stash show $(git sgrep "$1") -p; }; f"
sapply = "!f() { git stash apply $(git sgrep "$1"); }; f"
sdrop = "!f() { git stash drop $(git sgrep "$1"); }; f"
Note that the reason for the ref=$( ... ); echo ${ref:-<no_match>};
pattern is so a blank string is not returned which would cause sshow, sapply and sdrop to target the latest stash instead of fail as one would expect.
Answered 2023-09-20 20:33:30
Use git stash save NAME
to save.
Then... you can use this script to choose which to apply (or pop):
#!/usr/bin/env ruby
#git-stash-pick by Dan Rosenstark
# can take a command, default is apply
command = ARGV[0]
command = "apply" if !command
ARGV.clear
stashes = []
stashNames = []
`git stash list`.split("\n").each_with_index { |line, index|
lineSplit = line.split(": ");
puts "#{index+1}. #{lineSplit[2]}"
stashes[index] = lineSplit[0]
stashNames[index] = lineSplit[2]
}
print "Choose Stash or ENTER to exit: "
input = gets.chomp
if input.to_i.to_s == input
realIndex = input.to_i - 1
puts "\n\nDoing #{command} to #{stashNames[realIndex]}\n\n"
puts `git stash #{command} #{stashes[realIndex]}`
end
I like being able to see the names of the stashes and choose. Also I use Zshell and frankly didn't know how to use some of the Bash aliases above ;)
Note: As Kevin says, you should use tags and cherry-picks instead.
Answered 2023-09-20 20:33:30
git stash save
is deprecated in favour of git stash push
. - anyone Use a small bash script to look up the number of the stash. Call it "gitapply":
NAME="$1"
if [[ -z "$NAME" ]]; then echo "usage: gitapply [name]"; exit; fi
git stash apply $(git stash list | grep "$NAME" | cut -d: -f1)
Usage:
gitapply foo
...where foo is a substring of the name of the stash you want.
Answered 2023-09-20 20:33:30
here my aliases for the community: wip
and wip-apply
.
When you git wip
you stash also untracked files and come back to the previous commit state.
git config --global alias.wip '!f() { git stash save $1 -u ; }; f'
git config --global alias.wip-apply '!f() { temp=$(git stash list | cut -d ':' -f 3 | grep -n -w $1 | cut -d ':' -f 1) ; stashnum=$((temp-1)) ; stashname=$(echo stash@{$stashnum}) ; git stash apply $stashname ; }; f'
Usage:
git wip "featureA"
git wip-apply "featureA"
Answered 2023-09-20 20:33:30
This is one way to accomplish this using PowerShell:
<#
.SYNOPSIS
Restores (applies) a previously saved stash based on full or partial stash name.
.DESCRIPTION
Restores (applies) a previously saved stash based on full or partial stash name and then optionally drops the stash. Can be used regardless of whether "git stash save" was done or just "git stash". If no stash matches a message is given. If multiple stashes match a message is given along with matching stash info.
.PARAMETER message
A full or partial stash message name (see right side output of "git stash list"). Can also be "@stash{N}" where N is 0 based stash index.
.PARAMETER drop
If -drop is specified, the matching stash is dropped after being applied.
.EXAMPLE
Restore-Stash "Readme change"
Apply-Stash MyStashName
Apply-Stash MyStashName -drop
Apply-Stash "stash@{0}"
#>
function Restore-Stash {
[CmdletBinding()]
[Alias("Apply-Stash")]
PARAM (
[Parameter(Mandatory=$true)] $message,
[switch]$drop
)
$stashId = $null
if ($message -match "stash@{") {
$stashId = $message
}
if (!$stashId) {
$matches = git stash list | Where-Object { $_ -match $message }
if (!$matches) {
Write-Warning "No stashes found with message matching '$message' - check git stash list"
return
}
if ($matches.Count -gt 1) {
Write-Warning "Found $($matches.Count) matches for '$message'. Refine message or pass 'stash{@N}' to this function or git stash apply"
return $matches
}
$parts = $matches -split ':'
$stashId = $parts[0]
}
git stash apply ''$stashId''
if ($drop) {
git stash drop ''$stashId''
}
}
Answered 2023-09-20 20:33:30
git stash apply
also works with other refs than stash@{0}
. So you can use ordinary tags to get a persistent name. This also has the advantage that you cannot accidentaly git stash drop
or git stash pop
it.
So you can define an alias pstash
(aka "persistent stash") like this:
git config --global alias.pstash '!f(){ git stash && git tag "$1" stash && git stash drop; }; f'
Now you can create a tagged stash:
git pstash x-important-stuff
and show
and apply
it again as usual:
git stash show x-important-stuff
git stash apply x-important-stuff
Answered 2023-09-20 20:33:30
in my fish shell
function gsap
git stash list | grep ": $argv" | tr -dc '0-9' | xargs git stash apply
end
use
gsap name_of_stash
Answered 2023-09-20 20:33:30
There are many answers here but I believe the desired equivalent functionality that the OP is after isn't fully encapsulated by any one answer or comment.
By combining git add
, git diff
, git rm
, and git reset
into a custom git command we can quickly aggregate changes into a patch file which we can easily reference later on by name:
Here are the commands used in the above custom git command (also available as a gist) - please note the use of the --hard
flag which will reset your current branch as well remove all changes to your local files:
#!/usr/bin/env bash
if [ $# -eq 1 ] ; then
NAME=$1
else
echo "Please pass exactly one argument, which is the name of the patch file"
exit 1
fi
git add .
# if previous patch file with the same name exists untrack it
if [ -f "$NAME.patch" ] ; then
git rm --cached $NAME.patch
fi
# warning: this will diff all changes into a file called NAME.patch and do a hard reset of the current branch
git diff --staged > $NAME.patch
git reset --hard $HEAD
git bottle hello
to create a hello.patch
file.git apply hello.patch
The trick is to first track all files so that we can take advantage of the staged (or cached) option of the diff command. With some tweaking you could extend the custom command to output the patch file somewhere outside of your working directory, i.e. maybe in some Patches folder on your hard drive, or you could update your .gitignore
file to ignore it.
Credit where it's due: this answer inspired my own which describes the patch approach but neglects to mention changes in new files will be left out of the diff display.
Caveat: since this command relies on git add
it will not bottle up changes from any file git is already ignoring.
Answered 2023-09-20 20:33:30
git rm
to safely untrack and delete the file. Added that in to ensure that we don't accidentally track and stage the patch file and then immediately delete it with the hard reset - anyone Late to the party here, but if using VSCode, a quick way to do so is to open the command palette (CTRL / CMD + SHIFT + P) and type "Pop Stash", you'll be able to retrieve your stash by name without the need to use git CLI
Answered 2023-09-20 20:33:30
I don't think there is a way to git pop a stash by its name.
I have created a bash function that does it.
#!/bin/bash
function gstashpop {
IFS="
"
[ -z "$1" ] && { echo "provide a stash name"; return; }
index=$(git stash list | grep -e ': '"$1"'$' | cut -f1 -d:)
[ "" == "$index" ] && { echo "stash name $1 not found"; return; }
git stash apply "$index"
}
Example of usage:
[~/code/site] on master*
$ git stash push -m"here the stash name"
Saved working directory and index state On master: here the stash name
[~/code/site] on master
$ git stash list
stash@{0}: On master: here the stash name
[~/code/site] on master
$ gstashpop "here the stash name"
I hope it helps!
Answered 2023-09-20 20:33:30
For everything besides the stash creation, I'd propose another solution by introducing fzf as a dependency. I recommend taking 5 minutes of your time and get introduced to it, as it is over-all great productivity booster.
Anyway, a related excerpt from their examples page offering stash searching. It's very easy to change the scriptlet to add additional functionality (like stash application or dropping):
fstash() {
local out q k sha
while out=$(
git stash list --pretty="%C(yellow)%h %>(14)%Cgreen%cr %C(blue)%gs" |
fzf --ansi --no-sort --query="$q" --print-query \
--expect=ctrl-d,ctrl-b); do
mapfile -t out <<< "$out"
q="${out[0]}"
k="${out[1]}"
sha="${out[-1]}"
sha="${sha%% *}"
[[ -z "$sha" ]] && continue
if [[ "$k" == 'ctrl-d' ]]; then
git diff $sha
elif [[ "$k" == 'ctrl-b' ]]; then
git stash branch "stash-$sha" $sha
break;
else
git stash show -p $sha
fi
done
}
Answered 2023-09-20 20:33:30
If you're using ZSH, this alias combination is pretty lethal:
zstyle ':completion:*' completer _expand_alias _complete _ignored
alias gs="git stash push -u -m "
alias gsp='git stash pop'
Basically you can use tab to autocomplete your aliases, and then you can easily name and search your git stashes by name. This push alias will also include any untracked files, which I've found helpful as a default.
Answered 2023-09-20 20:33:30
I suspect that if you are using too many stashes (say more than three), then you are doing something wrong: Stashes are typically used for interruptions of work, not for implementing features (you would use feature branches to do so).
Say you are working on some feature A, and then you discover some issue B that has to be fixed (to implement feature A). What you might do is this then:
git add --interactive
to patch
the parts for feature A, ignoring the fixes for issue B.git commit
the interactive selection to the current branch.git stash
the non-committed changes (fixing issue B)git stash pop
the fixes for issue B in the current branch and commit them. Possibly git stash drop
if the stash required manual merge.You could also commit the fixes for issue B first, then then stash the changes for feature A, but you get the idea.
Answered 2023-09-20 20:33:30
this is a quick setup I made and works for me, hope it will also work for you:
Let's say I have a custom/local script in my package.json project file that i dont want to push to remote repo
{
// ... package.json stuff
"scripts": {
"custom": "ts-node a_ts_test_file.ts"
}
}
So I decide to stash this change when I want to push my branch or something like that and pop the stash until my next "git push".
So ...
# dev is the "stash tag"
# To stash current working directory
git config --global alias.sh "stash -m 'dev'"
~.bashrz
or ~.zshrc
if you're using zsh or oh-my-zsh, add the following alias:# Apply stash "tagged" $(X) where X is substring of "git stash list" output filtered by output that contains "dev".
# I didn't use git stash apply because "dev" tag isn't unique, so it's a need to pop the stash and ensure to create a new one alias set on first step
alias gitsh="git stash pop $(git stash list | grep 'dev' | cut -d ':' -f 1) || echo 'nope'"
To push your work directory with tag "dev": git sh
To pull your stashed changed from stash tagged "dev": sitsh
( Its a little script I made in five minutes and works for me, if it fails ... fix it! 😉 )
Answered 2023-09-20 20:33:30