Is my stash
stack pushed to the remote repo
? Or is it completely ignored?
I'm just curious if I should tend to it every once in a while to drop some of it to save space on the server.
Is my stash
stack pushed to the remote repo
? Or is it completely ignored?
I'm just curious if I should tend to it every once in a while to drop some of it to save space on the server.
No. Stashes are local.
$ man git stash
:
Use git stash when you want to record the current state of the working directory and the index, but want to go back to a clean working directory. The command saves your local modifications away reverts the working directory to match the HEAD commit.
I wouldn't keep too many of them around locally though. You'll lose track of them over time and they'll become somewhat useless.
As a general rule, no. You could push it though, if you wanted.
Here's the thing about push (and, for that matter, fetch): these work based on "refspecs", where you name a local reference name—or, for push and specific cases, a raw commit-ID—and then also a remote reference name.
Most of the time, you name a branch reference, such as master
, or a "remote branch" like origin/master
. Confusingly, what git calls a "remote branch" is actually a local entity, not a branch on a remote but rather a branch in your repository under a special name.
A branch is really just a reference whose name starts with refs/heads/
. That's really almost all a branch is. (There's one other special thing about a branch: branches automatically move when you make new commits in them. That is, if you're on your master
branch and you make a new commit, git updates refs/heads/master
to point to the new commit.)
A "remote branch" is just a reference whose name starts with refs/remotes/
and then contains the name of the remote (usually origin
). So refs/remotes/origin/master
is a "remote branch": a local entity, a name in your repo, that your git uses to keep track of "where master
was on origin
last time git checked in with origin
". Whenever you fetch or push from/to origin
,1 git updates your origin/branch
names based on what it sees "over there".
Tags are simply references that start with refs/tags/
.
Normally you leave out all these prefixes and just write master
to mean your master branch in refs/heads/master
, origin/master
to mean refs/remotes/origin/master
, and v2.3
to mean refs/tags/v2.3
. Git figures out which one automatically, since it's obvious. The precise rules are described in gitrevisions. (Annoyingly, git checkout
and git branch
don't always exactly follow the gitrevisions rules: when they know something is meant to be a branch name they just assume the refs/heads/
part. Other git commands do work as described, though.)
The stash
script uses a reference that is simply spelled refs/stash
. So you can name this reference by writing stash
; git will find that it's not a branch, nor a remote branch, nor a tag, and will finally resort to using refs/stash
to resolve the name.2
This means that if you wrote:
$ git push origin stash:ssss
git would find your stash (just the one single stash) and attempt to push it to a remote reference named ssss
. This would most likely fail; here's what happened when I tried it:
error: unable to push to unqualified destination: ssss
The destination refspec neither matches an existing ref on the remote nor
begins with refs/, and we are unable to guess a prefix based on the source ref.
error: failed to push some refs to 'ssh://[redacted]/tmp/t'
Just for fun, I tried the next command, and got a different error:
$ git push origin stash:refs/ssss
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 485 bytes | 0 bytes/s, done.
Total 4 (delta 3), reused 0 (delta 0)
remote: error: refusing to create funny ref 'refs/ssss' remotely
To ssh://[redacted]/tmp/t
! [remote rejected] stash -> refs/ssss (funny refname)
error: failed to push some refs to 'ssh://[redacted]/tmp/t'
However, this worked:
$ git push origin stash:refs/heads/ssss
This time, it created a new branch on the remote, named ssss
. It would also work to push to a remote tag (refs/tags/tagname
).
A stash does not make much sense as either a branch or a tag, but you can push it as if it were one. All the remote knows, once you try this, is that you're sending some commit object(s) and their associated trees, blobs, etc., and that it should store the "tip-most" commit under the (full) name you supply.3 This is why you can push raw commit-IDs, e.g., to create a tag on the remote:
$ git push af7ec93:refs/tags/foo
(assuming there's a commit whose ID starts with af7ec93
of course).
The "stack" is made by using the reflog for the refs/stash
reference. When you write stash@{1}
, this uses the same gitrevisions rules to resolve to a commit-ID. Since git push
allows you to use anything that resolves to a valid ID, you could push these to remote names as well. But you probably shouldn't; just like the top-most stash item under refs/stash
, these do not make a lot of sense as regular commits. (Stashes are stored internally as merge commits, but their contents are oddly packaged, and trying to use them as ordinary commits produces not-so-useful results.)
1This is literally true in git since 1.8.2 or so; but older versions of git sometimes skip updating a remote-branch when fetching, particularly when git fetch
is invoked by git pull
.
2If you consult gitrevisions, you'll see that this is not quite accurate either: it will find stash
as refs/stash
before looking for a branch name.
3git push
usually builds the full name automatically: if you're pushing your master
, which is refs/heads/master
, it knows that this is a branch, so git push master:newbranch
creates refs/heads/newbranch
on the remote. However, you can spell out a full name, so as to create a tag on the remote instead, for instance. This also works for deletion operations, when you push an empty local reference to delete a remote-ref: git push :refs/tags/delete_me
, for example.
As bcmcfc already said, keeping a large pile of stashes tends to be a bad idea. What I do instead is keep a large pile of branches (which I avoid pushing unless I really want to save them on some remote(s)); these have names, and hence are a little more manageable (but only a little). There's no difference in efficiency, since stashes and branches both merely serve to contain commits—either the special stash merge commits, or ordinary commits. However, you may want to make sure your push.default
is configured to avoid pushing all your branches, if you use branches instead of stashes.