Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating patch file from an old stash

Tags:

git

I wish to create a .patch file based on the diff of an old stash that I can view with git stash show -p stash@{2}

I tried this, but no luck:

git format-patch stash@{2} --stdout > file.patch

I assumed it would work like a normal commit? Apologies for being most likely uber-thick.

Thanks!

like image 483
Matt Fletcher Avatar asked Sep 30 '14 09:09

Matt Fletcher


People also ask

How do I pull files from stash?

Retrieve Stashed Changes To retrieve changes out of the stash and apply them to the current branch you're on, you have two options: git stash apply STASH-NAME applies the changes and leaves a copy in the stash. git stash pop STASH-NAME applies the changes and removes the files from the stash.

How do I apply a git stash patch?

You can reapply stashed changes with the commands git stash apply and git stash pop . Both commands reapply the changes stashed in the latest stash (that is, stash@{0} ). A stash reapplies the changes while pop removes the changes from the stash and reapplies them to the working copy.


2 Answers

The output of git stash show -p is itself a valid patch. You can use it directly:

git stash show -p stash@{2} > file.patch
like image 142
John Zwinck Avatar answered Sep 21 '22 01:09

John Zwinck


Per the git format-patch documentation, if you specify a single commit,1 then:

  1. A single commit, since, specifies that the commits leading to the tip of the current branch that are not in the history that leads to the since to be output.

Thus, format-patch tries to find "commits leading to the tip of the current branch" (HEAD) that are neither themselves stash@{2} nor ancestors of stash@{2}. It's hard to say precisely which commits these will be without knowing the actual commit graph, but if the graph looks something like this:

... - o - o - * - *   <-- HEAD=branch
          |\
          i-w   <-- stash@{2}

then format-patch would make a patch containing the two commits marked *: they are the only ancestors of HEAD that are not removed by starting at the w commit and working backwards.

If the graph looks more like this:

              *   <-- HEAD=branch
            /
... - o - o - o - o   <-- anotherbranch
              |\
              i-w   <-- stash@{2}

then once again you would get the commit marked * (one commit this time, just to be a bit different).

(In fact, you get precisely the same commits as for stash@{2}..HEAD, since this gitrevisions syntax means what's in item 1 of the format-patch documentation).

One solution is to proceed to item 2 in the format-patch documentation:

  1. Generic revision range expression (see "SPECIFYING REVISIONS" section in gitrevisions(7)) means the commits in the specified range.

Here you need only specify the commits from "just before the w commit in the stash-bag" to "the w commit itself", which is simply stash@{2}^..stash@{2}:

git format-patch [additional options like --stdout here] stash@{2}^..stash@{2}

Since this is a single commit, the only difference between this and just using git show (as John Zwinck suggested) is the precise formatting of the patch (format-patch makes mailbox style patches by default).


Alternatively, you can always turn a stash into a "real branch" using git stash branch. This turns the index commit i of the stash into a real commit if needed, and restores the work directory state (and the untracked or all-files state as well, if one of those was included in the stash) after creating a new branch starting at the parent commit, i.e., the one the stash-bag is attached to. Commit the resulting work-tree and you have an ordinary branch, which you can manipulate with all the ordinary branch operations (including format-patch).


1See some of my other descriptions about git "stash bags" to see that a stash is a small clump of commits, but note that the name stash@{2} identifies a single commit, specifically the work-tree commit in the "stash bag".

like image 42
torek Avatar answered Sep 24 '22 01:09

torek