gitgit-stashgit-apply

Pull non-binary files from git stash


I'm pretty new to git. On one computer I ran

git stash save myfeature
git stash show -p > myfeaturepatch

I copied myfeaturepatch to a second computer and ran

git apply myfeaturepatch

I made some changes which included adding some font files (binaries) and then ran

git stash save myfeature2
git stash show -p > myfeaturepatch2

When I try to apply this second version back to my first computer, I get

error: cannot apply binary patch to 'myfont.ttf' without full index line

My guess is I needed to run git stash save --binary myfeature2 when I made the stash. Unfortunately, since git stash deletes the changes it saves to the file, and since I can't apply my patch to either computer due to the above error, I don't currently have access to the changes I made.

I've tried a bunch of different git apply and git stash commands, but I don't have a complete enough understanding of what's going on and what the arguments mean to pull out just the non-binary files from my patch file. I assume there's a way to do this.


Solution

  • My guess is I needed to run git stash save --binary myfeature2 when I made the stash.

    No, this is unnecessary ... and not even an option anyway: there is no save --binary.

    What git stash does is commit your work. It just does this in a weird way, using two separate commits,1 that are on no branch.

    As long as you still have the stash, you still have the commits.

    The easiest way to deal with a stash that you still have, that requires picking apart, is to convert it to ordinary commits on a new branch:

    git stash branch newbranchname [<stash>]
    

    Of course, this requires that you do it on the machine that has the stash,2 but once done, you are on a new branch, with the index the way it was when you ran git stash save, and the work-tree the way it was when you ran git stash save. (The new branch's current commit is the commit that was current when you ran git stash save, as well.) You can now finish git add-ing any unstaged files, git reset any files you don't want staged, and git commit the resulting index (and then make more commits from more work-tree files until everything is safely saved in ordinary non-stash-y commits).


    1The two commits are for the current index, and the work-tree. Remember that the index is where you are building the next commit you will make, by git add-ing and/or git rm-ing things to copy the latest version from the work-tree. Either or both of the index and work-tree can therefore be different from the current commit, so git stash save saves both, separately, so that it can restore them separately later, if you want that later. You can tell it to save a third commit containing untracked files, or all files, too.

    2Of course, before you git stash branch, you should have a clean index and work-tree. If you do not, you will need to commit or stash first. If you decide to stash again, this pushes your previous stash "up" one level, so if it used to be stash@{2} it is now stash@{3}. I find that keeping many stashes active is a recipe for madness: instead, commit on a new branch.