I have a stash with an incorrect name. I would like to fix the name so it's accurate.
How can I rename a stash?
I have a stash with an incorrect name. I would like to fix the name so it's accurate.
How can I rename a stash?
Let's assume your stash list looks like this:
$ git stash list
stash@{0}: WIP on master: Add some very important feature
stash@{1}: WIP on master: Fix some silly bug
First, you must remove stash entry which you want to rename:
$ git stash drop stash@{1}
Dropped stash@{1} (af8fdeee49a03d1b4609f294635e7f0d622e03db)
Now just add it again with new message using sha of commit returned after dropping:
$ git stash store -m "Very descriptive message" af8fdeee49a03d1b4609f294635e7f0d622e03db
And that's it:
$ git stash list
stash@{0}: Very descriptive message
stash@{1}: WIP on master: Add some very important feature
This solution requires git 1.8.4 or later, and yes, it works with dirty working directory too.
Unless you do it manually or contribute an improvement to Git, you can use an alias:
git config --global alias.stash-rename '!_() { rev=$(git rev-parse $1) && git stash drop $1 || exit 1 ; git diff-index --quiet HEAD; s=$?; [ $s != 0 ] && git stash save "tmp stash from stash-rename"; git stash apply $rev && shift && git stash save "$@" && [ $s != 0 ] && git stash pop stash@{1}; }; _'
Usage: "git stash-rename <stash> [save options] [<message>]
"
With [save options]
any option of git stash save
: [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked] [-a|--all]
Example:
$ git stash list
stash@{0}: On master: Pep8 format
stash@{1}: On master: co other than master with local changes
stash@{2}: On master: tests with deployAtEnd
# Let's say I want to rename the stash@{2} adding an issue reference:
$ git stash-rename stash@{2} NXP-13971-deployAtEnd
$ git stash list
stash@{0}: On master: NXP-13971-deployAtEnd
stash@{1}: On master: Pep8 format
stash@{2}: On master: co other than master with local changes
That will work even if you have local unstaged changes :)
Simplified script, credits to qzb, https://stackoverflow.com/a/35549615/515973
git config --global alias.stash-rename '!_() { rev=$(git rev-parse $1) && git stash drop $1 || exit 1 ; git stash store -m "$2" $rev; }; _'
Usage: "git stash-rename <stash> [<message>]
"
For the benefit of the reader, here is an extension to the currently accepted and correct answer.
If you not only want to correct the stash message and also want to correct the commit message of the stash, such that
git stash list
and
git log --oneline -1 stash
both agree to what is shown, you need a bit more. There might be a better way to do it, but this recipe here is easy to understand, I hope.
To be able to do git commit --amend
you need to be on the TIP of a branch. Hence the solution is:
git checkout -b scratch stash@{1}
git stash drop stash@{1}
git commit --amend -m "$MESSAGE"
git stash save -m "$MESSAGE" HEAD
git checkout master
git branch -D scratch
Explained:
git commit --amend
to replace the commit message, this changing the SHA of the "stash in question"Drawbacks:
This switches branches temporarily. So this recipe can only be applied when git status --porcelain
is clean (read: does not output anything)
It renumbers the stashes, so the changed stash becomes stash@{0}
You need to enter the $MESSAGE
twice or use some environment variable (in the example: MESSAGE
)
You need to find an unused branch name
There are ways to do this without switching branches, but this is beyond the scope of this answer.
git init scratch
cd scratch
for a in A B C D; do date >$a; git add $a; git commit -m $a; done
for a in X Y; do echo $a > Z; git stash save --all; done
git log --oneline --graph --decorate --all; git stash list
Output
*-. e0e281b (refs/stash) WIP on master: 8bdcc32 D
|\ \
| | * 4d62f52 untracked files on master: 8bdcc32 D
| * 096f158 index on master: 8bdcc32 D
|/
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: WIP on master: 8bdcc32 D
stash@{1}: WIP on master: 8bdcc32 D
Now without changing commit (note: the SHA in following will be different at your side):
git stash drop stash@{1}
git stash store -m ...changed... 2fbf9007dfdfb95ae269a19e13b8b9ca3e24181c
git log --oneline --graph --decorate --all; git stash list
Output
*-. 2fbf900 (refs/stash) WIP on master: 8bdcc32 D
|\ \
| | * 246dc5c untracked files on master: 8bdcc32 D
| * 80c5ea0 index on master: 8bdcc32 D
|/
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: ...changed...
stash@{1}: WIP on master: 8bdcc32 D
As you can see, stash@{0}
still is shown as 2fbf900 (refs/stash) WIP on master: 8bdcc32 D
in git log
. If you look carefully, you will see, that several commits have changed SHA. This is due to how stashes are handled (parents are included of the SHA, and stashes have their stashes as parent).
Fix that:
git checkout -b scratch stash
git stash drop
git commit --amend -m ...changed...
git stash store -m ...changed... HEAD
git checkout master
git branch -D scratch
git log --oneline --graph --decorate --all; git stash list
Output
*-. 4d55186 (refs/stash) ...changed...
|\ \
| | * 246dc5c untracked files on master: 8bdcc32 D
| * 80c5ea0 index on master: 8bdcc32 D
|/
* 8bdcc32 (HEAD, master) D
* c84c659 C
* 49bb2da B
* b1852c6 A
stash@{0}: ...changed...
stash@{1}: WIP on master: 8bdcc32 D
As you also can see, refs/stash
has a changed SHA, too.
I don't think it is possible to do so. There has been a proposal for stash renaming, but it has not been implemented yet.
My general idea is:
Implement a new
git reflog update
command that updates the message associated with a specific reflog entry. To do this, a newupdate_reflog_ent()
function (in reflog.c) would change the message associated with the specific reflog entry to update. Anupdate_reflog()
function would usefor_each_reflog_ent()
withupdate_reflog_ent
to actually do the change.A
git stash rename
command would then only need to callgit reflog update
with the appropriate ref and new message.
Or you could, of course, pop the stash and do a git stash save [message]
Simplest way: pop your stash with git stash pop then save it again with git stash save your-name
Here is a modified version of Julien's alias that lets you properly deal with the On <branch>
prefix usually prepended to stash names:
git config --global alias.stash-rename '!_() { newmsg="$1" && stash=${2:-"stash@{0}"} && newbranch="$3" && sha=$(git rev-parse "$stash") && olddesc="$(git stash list --format=%gs -1 "$stash")" && newdesc="$(if [[ "$newbranch" = "." ]]; then echo "$newmsg"; else if [[ -n "$newbranch" ]]; then echo "On $newbranch: $newmsg"; else if [[ "$olddesc" =~ ":" ]]; then echo "$(echo "$olddesc" | cut -f1 -d":"): $newmsg"; else echo "$newmsg"; fi; fi; fi)" && git stash drop "$stash" > /dev/null || exit 1; git stash store -m "$newdesc" "$sha" && git stash list; }; _'
Syntax:
git stash-rename <new-name> [<stash> [<new-branch-name> | .]]
Example usage:
repo[master] % touch tmp && git add tmp && git stash save first
Saved working directory and index state On master: first
HEAD is now at bd62064 Initial commit
repo[master] % touch tmp && git add tmp && git stash save second
Saved working directory and index state On master: second
HEAD is now at bd62064 Initial commit
repo[master] % git stash list
stash@{0}: On master: second
stash@{1}: On master: first
repo[master] % git stash-rename renamed
stash@{0}: On master: renamed
stash@{1}: On master: first
repo[master] % git stash-rename also-renamed stash@{1}
stash@{0}: On master: also-renamed
stash@{1}: On master: renamed
repo[master] % git stash-rename branch-changed stash@{0} new-branch
stash@{0}: On new-branch: branch-changed
stash@{1}: On master: renamed
repo[master] % git stash-rename branch-name-persists
stash@{0}: On new-branch: branch-name-persists
stash@{1}: On master: renamed
repo[master] % git stash-rename no-branch stash@{0} .
stash@{0}: no-branch
stash@{1}: On master: renamed
repo[master] % git stash-rename renamed
stash@{0}: renamed
stash@{1}: On master: renamed
repo[master] % git stash-rename readd-branch stash@{0} develop
stash@{0}: On develop: readd-branch
stash@{1}: On master: renamed
Most of the command is for parsing the arguments and figuring out what should be done to the branch name. The git
tools used are as follows:
git rev-parse <stash>
to find the SHA of the stash.git stash list --format=%gs -1 <stash>
to find the reflog subject of the stash. Note that this is different from the commit message of the stash, which is not changed by this command. The reflog subject is what shows up in git stash list
, and you can change the reflog subject without changing the hashes of the commits associated with the stashes. However, you can always find the original commit message, so don't use git stash-rename
to remove sensitive information!git stash drop <stash>
to drop the old reference to the stash (but we still have the SHA, so it's not lost).git stash store -m <new-message> <sha>
to save a new reference to the stash with the same commit information but a different reflog subject.git stash list
to list the stashes after the operation is finished. Note that new stashes are always pushed to the beginning of the list. It would be necessary to re-push all the stashes before the stash of interest in order to restore its original position.