Is there a way to re-order Git stashes?
As in Whymarrh's answer and Donnie's comment, I think you're probably better served by just committing. I will note, though, that:
If you really wanted to keep using stashes and reorder those, you could adjust
refs/stash
as you work ...
It's possible to do this without using git stash pop
at all. It's just tricky. (Edit: I see on re-reading that this was the idea in Whymarrh's answer.)
The reflog file, .git/logs/refs/stash
, holds reflog entries 1 through N (however many exist). The stash
reference itself holds entry zero.
A drop
operation consists of removing the specific reflog entry (git reflog delete
knows how to handle the special zero case):
drop_stash () {
assert_stash_ref "$@"
git reflog delete --updateref --rewrite "${REV}" &&
say "$(eval_gettext "Dropped \${REV} (\$s)")" ||
die "$(eval_gettext "\${REV}: Could not drop stash entry")"
# clear_stash if we just dropped the last stash entry
git rev-parse --verify --quiet "$ref_stash@{0}" >/dev/null ||
clear_stash
}
(where clear_stash
deletes refs/stash
itself). The $REV
argument is refs/stash@{N}
, or refs/stash
if you didn't specify a particular one.
The store
operation inserts the entry at zero, using git update-ref
:
[snip]
w_commit="$1"
if test -z "$stash_msg"
then
stash_msg="Created via \"git stash store\"."
fi
git update-ref --create-reflog -m "$stash_msg" $ref_stash $w_commit
ret=$?
test $ret != 0 && test -z "$quiet" &&
die "$(eval_gettext "Cannot update \$ref_stash with \$w_commit")"
return $ret
It's therefore possible, albeit a bit tricky, to achieve a "roll" operation (if you're familiar with Forth or Postscript). To roll the bottom three entries up one step, for instance, changing:
E stash@{4}
D stash@{3}
C stash@{2}
B stash@{1}
A stash@{0}
into:
E stash@{4}
D stash@{3}
B stash@{2}
A stash@{1}
C stash@{0}
you would just copy C
to the bottom, as if via a new store
, then drop stash@{3}
(which moved up because of the insertion at zero).
In fact, you can do this by running git stash -q store
and git stash -q drop
, with appropriate arguments.
It's therefore possible, albeit a bit tricky, to achieve a "roll" operation (if you're familiar with Forth or Postscript).
To roll the bottom three entries up one step, you would just copy C to the bottom, as if via a new store, then drop stash@{3} (which moved up because of the insertion at zero).
If you do this, make sure to use Git 2.36 (Q2 2022), as it would be too slow if you were to roll out a large number of commits.
"git stash drop
"(man) is reimplemented as an internal call to reflog_delete()
function, instead of invoking "git reflog delete
"(man)via run_command()
API.
So instead of a subshell for each stash drop
=> reflog delete
, all those stash drop
calls remain in the same process, using internal functions.
See commit 758b4d2, commit 7d3d226, commit 76bccbc (02 Mar 2022) by John Cai (john-cai
).
(Merged by Junio C Hamano -- gitster
-- in commit a2fc9c3, 16 Mar 2022)
reflog
: libify delete reflog function and helpersHelped-by: Ævar Arnfjörð Bjarmason
Signed-off-by: John Cai
Currently stash shells out to reflog in order to delete refs.
In an effort to reduce how much we shell out to a subprocess, libify the functionality that stash needs intoreflog.c
.Add a
reflog_delete
function that is pretty much the logic in the while loop inbuiltin/reflog.c
cmd_reflog_delete()
.
This is a function thatbuiltin/reflog.c
andbuiltin/stash.c
can both call.
Not out of the box—I don't think stash was really meant for that workflow.
That said, if you switch to temporary commits, you could reorder those commits as you saw fit and cherry-pick
commits (e.g. git cherry-pick $tempbranch
as a replacement for git stash pop
).
If you really wanted to keep using stashes and reorder those, you could adjust refs/stash
as you work (via some scripting). From the git-stash
documentation:
The latest stash you created is stored in
refs/stash
; older stashes are found in the reflog of this reference and can be named using the usual reflog syntax (e.g.stash@{0}
is the most recently created stash,stash@{1}
is the one before it,stash@{2.hours.ago}
is also possible). Stashes may also be referenced by specifying just the stash index (e.g. the integern
is equivalent tostash@{n}
).
If you decide to write a script for your workflow you also have git stash create
and git stash store
at your disposal:
create
Create a stash (which is a regular commit object) and return its object name, without storing it anywhere in the ref namespace. This is intended to be useful for scripts. It is probably not the command you want to use; see "save" above.
store
Store a given stash created via git stash create (which is a dangling merge commit) in the stash ref, updating the stash reflog. This is intended to be useful for scripts. It is probably not the command you want to use; see "save" above.