How do I name and retrieve a Git stash by name?
Asked Answered
G

28

2415

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.

Grill answered 29/6, 2012 at 21:33 Comment(3)
git stash push -m stashname is the current syntax. git stash save stashname has been deprecated.Emptor
Simple custom git command (link to gist). Usage: git bottle name and then later git apply name.patch, see my answer if you want a fuller explanation and usage samples.Ledezma
Funny that most of the answers seem to have nothing to do with the question. Cameron's answer is the closest as it provides a work around with a detailed explanation of why it works. However the answer to the question is obviously no. You cannot do what the OP is asking, but there is a work around that allows you to apply a stash using its descriptive comment. That's probably why no answer was accepted as an answer or the OP just forgot to pick one. It was a good question which I appreciated since I was just searching for the answer when I found this.Oddball
P
2268

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 nth 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 nth 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}')

Pyrometer answered 4/3, 2013 at 8:18 Comment(17)
OP is explicitly trying to avoid the awkwardly named stash@{n} names for custom name. git stash apply <custom-name>Donley
git stash push -m my_stash is the current syntax. git stash save my_stash has been deprecated.Emptor
this is confusing. Only @Haruspicy answered the questionFoolscap
One important update, every time you do a stash pop, index number changes. Don't do a stash pop before checking the current list!Voltaic
if you are using windows power-shell, stash apply might throw error. So keep it in quotes. git stash apply "stash@{n}"Paramour
For anyone confused, git stash push -m name only tags the stash, which you will retrieve after checking git stash list (it will show you the git stash number and your tag) and git stash apply stash@{number} which corresponds to that tag shown in git stash list.Lithuanian
And there is how you can rename your stashes https://mcmap.net/q/12075/-how-can-i-rename-a-git-stashChristianize
I created a stash using 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.Evangelize
in the current latest version you can just use git stash save <stash name> to save the stash with a name, but this only allows you to quickly recognize the stashes you have distinctly, this doesn't allow for applying/popping stash with the name, for that you''' have to use correct index which you can now easily find by git stash list with your stash names in front!Shrive
For those who wants to stash a particular file with a specific path git stash push -m my_stash path-to-file/my-stash-file.htmlNonintervention
If you are using Powershell when you need to pop/apply a stash you should wrap the stash name like this "stash@{n}" where n is the index of stashEtka
Calling git stash without any arguments is equivalent to git stash push. (no need for push)Boult
When I do git stash pop stash^{/edit_cell} I get: error: 'stash^{/edit_cell}' is not a stash reference. Why is that? Also, I couldn't find any documentation about the syntax stash^{}. Can I get a link to it? OK, I tried with apply instead of pop and it works...Tarpaulin
zsh users will need to escape the ^: git stash apply stash\^{/my_stash_name}Colloid
@Tarpaulin git stash pop does not allow referencing the stash using (always errors out) stash^{/my_stash_name} only git stash apply allows that.Superordinate
git stash apply stash@{/my_stash_name} (In windows, this is what worked for me to apply stash by name.)Cosma
To apply a stash, just use the index Ex. git stash apply 0Assignable
A
760

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

Attainment answered 29/3, 2018 at 15:8 Comment(10)
docs showing push rather than save syntax: git stash pushEmptor
This is the real answer. Unfortunately, there are a ton of old answers above it.Ocular
For more on the newer git stash push: https://mcmap.net/q/11475/-what-39-s-the-difference-between-git-stash-save-and-git-stash-pushMagma
source (on latest current doc) for the deprecation notice: git-scm.com/docs/git-stash/2.24.0#Documentation/…Retrogress
FWIW: When runninggit 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 `.Revenue
@malan88 How is this different from the most voted answer?Persuasive
@Persuasive the most voted answer uses git stash save which is deprecated, you can use git stash push -m "message" insteadAttainment
Why does git choose an awkward naming style like 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...Laurustinus
since you used git stash push -m "message", when you list them would the entry be stash@{0}: message ?Windowshop
This suffers the same problem as the most voted answer. It doesn't actually answer the question. The question is about retrieval not storage. How do you retrieve by name? Cameron has the best answer to this question.Carnay
M
234

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 :)

Mannerheim answered 10/11, 2017 at 16:6 Comment(6)
This is it! Thank you. I have also updated my .gitignore to ignore .patch files and I am all set to have as many patches as I want.Typewriter
I can see the intent behind the question, which is to have apply some local changes every time you take out a branch from master and not commit them. So, perhaps the question should have been corrected and this answer should have been accepted as the solution. Simple as well.Calorimeter
Nice alternative to stashSharolynsharon
I think we may want to augment this answer with a git apply --3way some.patch. This is more similar to the traditional git stash apply approach. Otherwise, conflicts can cause the patch apply to failTremayne
I don't believe this does new files.Bounty
New files will not be included if you don't stage them, which is true for both git stash and git diff. If you stage them before stashing, they will be included.Pontifex
H
146

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.

Hageman answered 29/6, 2012 at 22:34 Comment(4)
Since branches are pretty cheap in git, this suggestion is most useful to me.Ruthful
Sure, but this doesn't help if you want to keep re-applying this stash in different branches later on, like the OP is asking. You would have to cherry-pick its head.Donley
@AdamDymitruk Is there any way to perform this while keeping the stash without poping. (like in git stash apply)Potful
Strangely, when I tried this I got an error message that one of my files would be overwritten when checking out and I should commit or stash (!) my changes. git stash push -m 'name' worked.Urbana
T
92

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
Thanasi answered 6/6, 2018 at 18:53 Comment(7)
What is "zsh_stash_name_"?Ambulacrum
@SamHasler just some random unique string. In case you want to know the stash was created with regular git stash or with these functionsThanasi
Elegant solution for alias fansMediator
These are great! FWIW, you can throw these directly in .gitconfig: 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.Funambulist
I would do grep -m 1 "zsh_stash_name_$1" just so it returns the first result if the same name was used multiple times: https://mcmap.net/q/12384/-how-do-i-limit-the-number-of-results-returned-from-grepBlossom
This answer should go to the top!!! This is the best answer!!Nelsen
very useful and save the timeCommencement
A
70

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 method to use a name to 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.

Visual Proof

Here's a beautiful animated GIF demonstrating the process.

Animated GIF showing a git stash apply using an identifiable name.

Sequence of events

The GIF runs quickly, but if you look, the process is this:

  1. The ls command shows 4 files in the directory
  2. touch example.html adds a 5th file
  3. git stash push -m "john-hancock" -a (The -a includes untracked files)
  4. The ls command shows 4 files after the stash, meaning the stash and the implicit hard reset worked
  5. git stash apply stash^{/john-hancock} runs
  6. The ls command lists 5 files, showing the example.html file was brought back, meaning the git stash apply command worked.

Does this even make sense?

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.

Atli answered 4/6, 2020 at 12:24 Comment(7)
Your answer is (more comprehensive) duplicate of this one which was itself a restatement of the now-deleted originally accepted answer. (See comments)Enloe
Embarrassed if I've posted something incorrect. I can't see the deleted originally accepted answer, likely because it's been deleted. Big problem is that I can get this to work consistently, as you can see by the animated GIF. I'll go back to the drawing board and see if I can figure out why it works when it shouldn't.Atli
what happends when two stash names are the same ? 1.both the stashs will apply ? 2.recent stash will apply ? 3.oldest stash will apply ?Sanitarium
How did you create that animated GIF from your terminal session?Epiclesis
I recorded the window using Camtasia, and it has as "Save as Animated GIF" option. I feel animated GIFs are the forgotten gem of the 1998 Internet.Atli
git stash push -m "john-hancock" -a did not worked for me, instead git stash push -m "john-hancock" --include-untracked worked for including untracked / newly added files as well in the stash. Cheers.Prosperus
@CameronMcKenzie I for one am very glad that you posted this answer regardless of whether part of your solution was already posted. In truth, your suggested solution to the problem is not found elsewhere on this thread, and your explanation is very useful, far moreso than "What about this?" + 2 lines of code.Siamang
A
67

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).

Anni answered 29/6, 2012 at 21:39 Comment(4)
Definitely like this approach, feels a bit cleaner to just have a 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.Frightened
This is the closest. I think I'll make some aliases for this. I don't like using the description as a "name".Donley
Shame it adds to index and you have to reset, someone should patch a --no-stage option! Related: #32333883Woodworm
@CiroSantilliOurBigBook.com thought the same, but git reset @ is pretty painless.Beeves
C
54

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

Campball answered 5/9, 2019 at 13:40 Comment(1)
Your answer is nominally what the top-rated answer would be, taking into account this comment on the current syntax for git stash {push,save}Enloe
H
43

What about this?

git stash save stashname
git stash apply stash^{/stashname}
Haruspicy answered 7/5, 2019 at 9:40 Comment(4)
It sounds like something like that used to be the accepted answer, but has since been deleted.Enloe
Hm, then why it was deleted?Haruspicy
I don't know, since I did not post the answer and do not have 10,000 reputation, but I presume it has something to do with the comments saying it doesn't work: 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).Enloe
for retrieving I go 1. 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 commandShuman
S
28

save a git stash with name

$ git stash push -m "say-my-name"

perform a git stash apply by name

$ git stash apply stash^{/say-my-name}
Scend answered 23/9, 2021 at 11:37 Comment(0)
P
12

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
Parous answered 4/10, 2021 at 13:43 Comment(6)
This is basically the same as an earlier answerEnloe
I think you meant -> git stash push -m "your comment"Perineum
@Michael yah, but this one bit different, I never pushed the stash, it always stays in the local git. This is how I used to follow and it works!Parous
@Perineum without "push" just stash the commit like this; git stash -m "your comment"Parous
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.Enloe
@Michael this one uses git stash pop 1 and git stash apply stash@{1} have minor different, theserverside.com/video/….Parous
H
9

Alias

sapply = "!f() { git stash apply \"$(git stash list | awk -F: --posix -vpat=\"$*\" \"$ 0 ~ pat {print $ 1; exit}\")\"; }; f"

Usage

git sapply "<regex>"

  • compatible with Git for Windows

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"
Holds answered 26/11, 2013 at 22:51 Comment(8)
Using 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.Venable
@EtanReisner: your snippet outputs more than one line.Cloudless
Make the action {print $1; exit} to quit after the first matched line.Venable
@EtanReisner: After some testing I could get rid of the sed, but wrapper and grep stays.Cloudless
You do not need the grep though like I said the pattern quoting might differ without it. I'm assuming by wrapper you mean the shell function? You never explained why you think you need that so I can't comment on whether you actually do but I believe you quite likely don't. (You might need to manually invoke a shell instead of git stash directly but possibly not even that.)Venable
@EtanReisner: It would be easier if you have tested your suggestions, but to name few differences: A) grep -E "" matches any line while awk -vpat=""... don't; this affects how git sapply behaves (grep does it the right way). B) Wrapping the code in function somehow make it better for git alias; and it's not just escaping quotes. C) To make awk work the same way as my snippet will result in longer and more complicated command actually. But if you can resolve those issues and provide actual working alias that would be great (unlike this spoon feeding over comments).Cloudless
I do test my suggestions and I already admitted that grep and awk might have different pattern behaviour (around quoting of patterns metacharacters at least). Using GNU awk 3.1.5 grep -E "" and awk -vpat="" both match every stash line for me. Quick testing shows that function wrapping means you get to avoid manually executing a shell (handling $0) and some extra quoting. So leave the function, that's fine. I'm still unclear what else is wrong with the awk-only option. sapply = "!f() { git stash apply \"$(git stash list | awk -F: -vpat=\"$*\" '$0 ~ pat {print $1; exit}')\"; }; f"Venable
@EtanReisner: You are right, the awk matches any line with empty pattern; I confused myself by replacing $0 ~ pat{... with /pat/{... as I thought it's equal. My apologies. Anyway I had to add --posix to enable some advanced regex features though.Cloudless
B
9

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).

Breadfruit answered 9/8, 2018 at 20:58 Comment(0)
C
6

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.

Corri answered 22/8, 2014 at 17:0 Comment(0)
A
6

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.

Albanian answered 11/1, 2018 at 1:30 Comment(1)
This works for me while the accepted answer doesn't seem to work (see my commend on the accepted answer)Marplot
D
5

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"
Dwaindwaine answered 20/12, 2021 at 9:5 Comment(3)
git wip-apply throw an error when using it: git wip-apply "25903" 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: 2 3: syntax error in expression (error token is "3")Mylesmylitta
the script is UNIX, are you using it on windows?Dwaindwaine
Hi ! Thx for your answer. I'm using Mac OS v12.0.1Mylesmylitta
E
4

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.

Erechtheum answered 8/6, 2017 at 15:56 Comment(2)
git stash save is deprecated in favour of git stash push.Boohoo
@wranvaud: Still works in 2022 (but man shows it's deprecated). I'll update the answer when this becomes unavailable. Thanks!Erechtheum
G
4

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.

Ginni answered 19/2, 2018 at 12:56 Comment(0)
C
3

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''
    }
}

More details here

Caviness answered 20/7, 2017 at 19:35 Comment(0)
P
3

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
Protestant answered 31/1, 2019 at 20:53 Comment(1)
This is the most convenient solution for me so far, since I don't mind having some extra tags in any of my repos.Isotone
P
2

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

Polly answered 26/12, 2018 at 8:18 Comment(0)
L
2

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:

git-bottle-demo

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
  • You can now simply do git bottle hello to create a hello.patch file.
  • Apply it with 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.

Ledezma answered 31/8, 2021 at 12:8 Comment(2)
A previous version of this answer did not check for old patch file existence and use 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 resetLedezma
Cool hack I may use it - but is there a reason you moved away from actual stashes which OP asked about?Geodetic
R
1

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
}
Racemose answered 10/9, 2016 at 11:58 Comment(0)
B
1

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

Bearberry answered 29/11, 2018 at 13:45 Comment(0)
N
1

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!

Napiform answered 11/12, 2019 at 14:54 Comment(0)
M
1

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.

Mallemuck answered 13/1, 2022 at 22:38 Comment(0)
E
0

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:

  1. git add --interactive to patch the parts for feature A, ignoring the fixes for issue B.
  2. git commit the interactive selection to the current branch.
  3. git stash the non-committed changes (fixing issue B)
  4. Go back to the master or main branch, possibly checking out a new branch to fix issue B.
  5. 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.
  6. Go back to the feature A branch and rebase it on the branch that has the fix for issue B. Then you have no more stashes left, but still have feature A and the fixes for issue B on different branches.

You could also commit the fixes for issue B first, then then stash the changes for feature A, but you get the idea.

Epiclesis answered 17/5, 2022 at 8:25 Comment(0)
M
-2

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 ...

  1. You need to create a new git alias:
# dev is the "stash tag"
# To stash current working directory
git config --global alias.sh "stash -m 'dev'"
  1. You need to edit your ~.bashrz or ~.zshrcif 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'"
  1. Enjoy 🙂

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! 😉 )

Marzipan answered 14/4, 2021 at 17:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.