Git version 2.511
was released some week ago and is packed with upgrades to its plumbing and
performance, with better indexes for some packfiles, noticeably improved
fetch/push speed, deprecation2 of whatchanged and promotion
of switch and restore out of experimental status (though checkout is not
going anywhere).
Yet, to the diphasic3 end-user, the unassuming highlight of this release is the ability to share your stashes through your remote: let's check it out!
⚓ Obligatory TL;DR
This creates a new ref called my-stash under refs/stashes/ and pushes it
upstream (to a remote whose name is origin).
On another machine, fetch all remote stashes and import the one you want:
The fetch command uses a
refspec to fetch
all stashes under refs/stashes/ and store them locally under the same path:
<remote-ref>:<local-ref>. The + is equivalent to --force, to overwrite
any existing local ref or the same name.
⚓ Stashes were inherently local
Until now, your stashes lived only as reflog under a single ref/stash
reference, which is not only fairly impractical for programmatic manipulation,
but also means that all but the latest one essentially only existed locally on
your host.
If you wanted to move them elsewhere, you had to resort to savvy (let's not call them "awkward") workarounds: patch files, stash branches, cherry-picking... Anything would go, with the exception of outright copying entire files or trees on your file system, I'm sure.
⚓ Aren't they just usable commits under the hood?
"Jein" ("yes and no"), as my German colleagues would say; you could always git show stash@{0} and see it in all its splendour to find out:
cd $(mktemp -d): you may follow along by copy-pasting without riskHere, I create a repository with a single commit containing a single empty file,
file. I add two lines to it, then stage the first one but not the second. I
also create an untracked file, other-file, then I stash all my changes.
What have we done?! Here's the monstrosity:
a196b1a (refs/stash) WIP on master: d4d8585 Create file
diff --cc file
index e69de29,3be9c81,0000000..c82de6a
mode 100644,100644,000000..100644
--- a/file
+++ b/file
@@@@ -1,0 -1,1 -1,0 +1,2 @@@@
+ +Line 1
+++Line 2
diff --cc will show the "combined diff", when a commit has several parents (a "merge commit")⚓ One stash, several commits
Let's not go today over how precisely to decipher the content of an octopus commit4, when a picture may well be worth a thousand words:
*-. a196b1a (refs/stash) WIP on master: d4d8585 Create file
|\ \
| | * 15f2a4d untracked files on master: d4d8585 Create file
| * aa4fa9e index on master: d4d8585 Create file
|/
* d4d8585 (HEAD -> master) Create file
Would you look at that! Your stash isn't one commit, it's possibly three: one for each of your staged, your unstaged, and your untracked changes, respectively.
⚓
A fourth parent with 2.51
Do you know what the stash commit needs? More parents, of course!
With Git 2.51, you may opt into a new representation of your stashes, which
will have one more parent. It's actually only a bit of a joke5,
since in reality we're talking of an extra commit with two parents, on top of
your current commit with three parents.
The export subcommand to git stash lets you use that new format. With it,
you need to use one of the --print or --to-ref <ref> options, to either
display the hash of the new stash commit or save it under a specific ref,
respectively.
3e57536c189d73308254f5e3f233b9b97e016d11
export --printLet's open it up and see what it hides:
* 3e57536 git stash: WIP on master: d4d8585 Create file
|\
| *-. a196b1a (refs/stash) WIP on master: d4d8585 Create file
| |\ \
| | | * 15f2a4d untracked files on master: d4d8585 Create file
| | * aa4fa9e index on master: d4d8585 Create file
| |/
| * d4d8585 (HEAD -> master) Create file
* 73c9bab
a196b1a commit (second parent) is the regular, historical "stash commit", stash@This is the same command as before, except that where I would before use
stash@{0} as the reference to log, I now use $(git stash export --print stash@{0}) instead, to use the new model.
The additional commit introduced under this new format is 3e57536, whose
parents are a196b1a (the "regular", historical stash commit) and 73c9bab.
What is 73c9bab? Just an entire secondary history to your
repository!
This alternative initial commit is only a dummy one, to mark the base of your
stash stack:
commit 73c9bab443d1f88ac61aa533d2eeaaa15451239c
Author: git stash <git@stash>
Date: Mon Sep 17 00:00:00 2001 +0000
As a fun tidbit, that date is essentially some sort of quirky
"Git epoch". It's not Git's birthday (despite an attempt to
have it as such),
but is here to stay regardless. See format-patch's
documentation.
⚓ Your stash stack
Finally, we arrive at the point of this entire article: stashes that used to only
be available through the reflog of refs/stash now properly exist as a
bunch of references that you can actually push and fetch. You may even move
around your entire stack, or any subset of it, at once.
Let's push another stash:
That new stash (whose message I set, to avoid confusion) is now the top of our stash stack:
* 157c3dc (refs/stash) On master: A new stash
|\
| * d94cc67 index on master: d4d8585 Create file
|/
* d4d8585 (HEAD -> master) Create file
157c3dc, is at the top of the stack, stash@{0}, or refs/stashAs a reminder, here's the earlier stash, now at stash@{1}:
*-. a196b1a WIP on master: d4d8585 Create file
|\ \
| | * 15f2a4d untracked files on master: d4d8585 Create file
| * aa4fa9e index on master: d4d8585 Create file
|/
* d4d8585 (HEAD -> master) Create file
a196b1a, is now the second entry on the stack, stash@{1}, but no more refs/stashThe new model for stashes allow us to refer to our entire stash stack directly, since they'll be parents of one another, provided that you want this behaviour.
Note that you may pass a list of stashes to git stash export --print or omit
them altogether to export the stack in its entirety:
* ba4fea2 git stash: On master: A new stash
|\
| * 157c3dc (refs/stash) On master: A new stash
| |\
| | * d94cc67 index on master: d4d8585 Create file
| |/
* | 3e57536 git stash: WIP on master: d4d8585 Create file
|\ \
| | \
| | \
| *-. \ a196b1a WIP on master: d4d8585 Create file
| |\ \ \
| | |_|/
| |/| |
| | | * 15f2a4d untracked files on master: d4d8585 Create file
| | * aa4fa9e index on master: d4d8585 Create file
| |/
| * d4d8585 (HEAD -> master) Create file
* 73c9bab
Try to focus on the leftmost branch: that's your stash stack, with ba4fea2 at
the top, 3e57536 next, and 73c9bab (the dummy initial "stash stack" commit)
at the bottom.
Voilà! You need only your one reference from git stash export --print, and
can carry around your entire stash stack.
⚓ So what?
There's a counterpart to the --print option: --to-ref <ref> lets you export
your stash stack (in its newly introduced model) to a proper Git ref, which you
can then push and fetch like any other reference:
There we go, refs/my-stash is there. You can lose and recover it all with
ease:
stash@{0}: On master: A new stash
stash@{1}: WIP on master: d4d8585 Create file
<no output>
stash@{0}: On master: A new stash
stash@{1}: WIP on master: d4d8585 Create file
And of course, you can push and fetch refs/my-stash to and from any remote
repository, just like any other ref.
Then, on another machine:
Though I should point out that the emerging consensus suggests to keep things a
bit more organised, and use refs/stashes/<name> instead of refs/<name>; I'll
adopt this convention going forward.
⚓ A note on garbage collection
Remember that these are dangling refs, and as such are subject to garbage collection, if you've skilfully set up your repository. Chances are that your Git host provider does by default end up pruning these after a while: nobody wants to keep around stale references forever that aren't reachable from any branch or tag.
Have fun!
-
Git
2.51(release notes) was released on August 18, 2025. ↩ -
With 2.51,
git whatchangedshall only function when paired when invoked with the--i-still-use-thisflag, just likepack-redundantwas, 2 years ago. That's some pretty hard deprecation: I like it. It's scheduled to be removed in Git 3.0. ↩ -
"Having two phases" (Merriam-Webster). I refer here to the migration to your personal computer after work. ↩
-
I call an octopus commit that, because it has many arms! Sometimes I call them hydra, with greater reverence, when they are particularly hard to tame. Neither term is part of the customary Git vernacular, but "octopus" is used to refer to a specific merge strategy. ↩
-
I thought the joke about stash-commits having four parents would make the solution scarier than it is, but I have some doubts now that I actually describe the reality aloud. ↩