Search code examples
gitgit-stashgit-bundle

git bundle stashed code


I have a specific set of code stashed in git and would like to bundle it up in order to transfer it to a different clone on a separate PC, but I have not figured out how to reference the stash in the bundle command.

stash@{0}: On issue/789: Something I do not want bundled
stash@{1}: WIP on issue/456: Something I do want bundled
stash@{2}: On issue/123: Something else I do not want bundled

I have tried:

git bundle create My-WIP.bundle stash@{1}

but get the following error:

error: Refusing to create empty bundle.

I can confirm that stash@{1} is not empty. Does the bundle command not support the stash? Is it possible to do what I'm trying to do?


Solution

  • First, a quick note: each stash is actually just a set of commits, in a particular format (a "stash bag") that is not on any branch. (The easiest thing to do here is probably to convert the stash to a branch, which makes it all much simpler. See the git stash branch section of this answer for details.)

    Does the bundle command not support the stash?

    This is correct: it does not—at least, not in the way you are trying to use it. But there is an easy(ish) fix.

    As noted in the git bundle documentation, the <git-rev-list-args> arguments is:

    A list of arguments, acceptable to git rev-parse and git rev-list (and containing a named ref, see SPECIFYING REFERENCES below)

    (boldface mine). The section they refer to goes on to say:

    git bundle will only package references that are shown by git show-ref: this includes heads, tags, and remote heads. References such as master~1 cannot be packaged ...

    Although their example uses master~1, anything that is not an actual reference name falls afoul of this problem, including reflog references like stash@{1}.

    The solution, then, if you really want to do it like this, is to give the hash ID a proper reference name, such as a branch or tag name. Let's use a tag name here:

    git tag temp-tag stash@{1}
    

    Now you have a tag and can create a bundle (or, simpler, just push or fetch the tag across the network so that you need not compute an appropriate basis or set of bases). To avoid making an enormous bundle you can give some appropriate base as a stop point, e.g.:

    git bundle create foo.bundle temp-tag ^master
    

    (assuming ^master is an appropriate stop point).

    You can now delete the tag locally:

    git tag -d temp-tag
    

    and transfer the bundle and run git fetch on it on the other system, to create the tag there. (Or, again, instead of messing with git bundle, just fetch or push the tag using a network protocol such as git:// or ssh:// between the two computers, or to a server.)

    You now have a tag, temp-tag, that works as a stash. The regular git stash commands work fine when given this tag:

    git stash apply temp-tag
    

    for instance. Deleting the tag deletes the name for this set of commits.