How would I extract a single file (or changes to a file) from a git stash?

前端 未结 9 1491
一生所求
一生所求 2020-11-28 00:14

I\'d like to know if it is possible to extract a single file or diff of a file from a git stash without popping the stash changeset off.

Might anyone be able to prov

相关标签:
9条回答
  • 2020-11-28 00:28

    If the stashed files need to merge with the current version so use the previous ways using diff. Otherwise you might use git pop for unstashing them, git add fileWantToKeep for staging your file, and do a git stash save --keep-index, for stashing everything except what is on stage. Remember that the difference of this way with the previous ones is that it "pops" the file from stash. The previous answers keep it git checkout stash@{0} -- <filename> so it goes according to your needs.

    0 讨论(0)
  • 2020-11-28 00:29

    Short answer

    To see the whole file: git show stash@{0}:<filename>

    To see the diff: git diff stash@{0}^1 stash@{0} -- <filename>

    0 讨论(0)
  • 2020-11-28 00:30

    Use the following to apply the changes to a file in a stash to your working tree.

    git diff stash^! -- <filename> | git apply
    

    This is generally better than using git checkout because you won't lose any changes you made to file since you created the stash.

    0 讨论(0)
  • 2020-11-28 00:31

    Edit: See cambunctious's answer, which is basically what I now prefer because it only uses the changes in the stash, rather than comparing them to your current state. This makes the operation additive, with much less chance of undoing work done since the stash was created.

    To do it interactively, you would first do

    git diff stash^! -- path/to/relevant/file/in/stash.ext perhaps/another/file.ext > my.patch
    

    ...then open the patch file in a text editor, alter as required, then do

    git apply < my.patch
    

    cambunctious's answer bypasses the interactivity by piping one command directly to the other, which is fine if you know you want all changes from the stash. You can edit the stash^! to be any commit range that has the cumulative changes you want (but check over the output of the diff first).

    If applying the patch/diff fails, you can change the last command to git apply --reject which makes all the changes it can, and leaves .rej files where there are conflicts it can;r resolve. The .rej files can then be applied using wiggle, like so:

    wiggle --replace path/to/relevant/file/in/stash.ext path/to/relevant/file/in/stash.ext.rej
    

    This will either resolve the conflict, or give you conflict markers that you'd get from a merge.


    Previous solution: There is an easy way to get changes from any branch, including stashes:

    $ git checkout --patch stash@{0} path/to/file
    

    You may omit the file spec if you want to patch in many parts. Or omit patch (but not the path) to get all changes to a single file. Replace 0 with the stash number from git stash list, if you have more than one. Note that this is like diff, and offers to apply all differences between the branches. To get changes from only a single commit/stash, have a look at git cherry-pick --no-commit.

    0 讨论(0)
  • 2020-11-28 00:35

    On the git stash manpage you can read (in the "Discussion" section, just after "Options" description) that:

    A stash is represented as a commit whose tree records the state of the working directory, and its first parent is the commit at HEAD when the stash was created.

    So you can treat stash (e.g. stash@{0} is first / topmost stash) as a merge commit, and use:

    $ git diff stash@{0}^1 stash@{0} -- <filename>
    

    Explanation: stash@{0}^1 means the first parent of the given stash, which as stated in the explanation above is the commit at which changes were stashed away. We use this form of "git diff" (with two commits) because stash@{0} / refs/stash is a merge commit, and we have to tell git which parent we want to diff against. More cryptic:

    $ git diff stash@{0}^! -- <filename>
    

    should also work (see git rev-parse manpage for explanation of rev^! syntax, in "Specifying ranges" section).

    Likewise, you can use git checkout to check a single file out of the stash:

    $ git checkout stash@{0} -- <filename>
    

    or to save it under another filename:

    $ git show stash@{0}:<full filename>  >  <newfile>
    

    or

    $ git show stash@{0}:./<relative filename> > <newfile>
    

    (note that here <full filename> is full pathname of a file relative to top directory of a project (think: relative to stash@{0})).


    You might need to protect stash@{0} from shell expansion, i.e. use "stash@{0}" or 'stash@{0}'.

    0 讨论(0)
  • 2020-11-28 00:41
    $ git checkout stash@{0} -- <filename>
    

    Notes:

    1. Make sure you put space after the "--" and the file name parameter

    2. Replace zero(0) with your specific stash number. To get stash list, use:

      git stash list
      

    Based on Jakub Narębski's answer -- Shorter version

    0 讨论(0)
提交回复
热议问题