How to reverse apply a stash?

前端 未结 11 2016
忘掉有多难
忘掉有多难 2020-11-29 14:32

I have a small patch saved away in my git stash. I\'ve applied it to my working copy using git stash apply. Now, I\'d like to back out those changes by revers

相关标签:
11条回答
  • 2020-11-29 15:09

    This is long over due, but if i interpret the problem correctly i have found a simple solution, note, this is an explanation in my own terminology:

    git stash [save] will save away current changes and set your current branch to the "clean state"

    git stash list gives something like: stash@{0}: On develop: saved testing-stuff

    git apply stash@{0} will set current branch as before stash [save]

    git checkout . Will set current branch as after stash [save]

    The code that is saved in the stash is not lost, it can be found by git apply stash@{0} again.

    Anywhay, this worked for me!

    0 讨论(0)
  • 2020-11-29 15:09

    You can follow the image i shared to unstash if u accidentally tapped stashing.

    0 讨论(0)
  • 2020-11-29 15:10
    git checkout -f
    

    will remove any non-commit changes.

    0 讨论(0)
  • 2020-11-29 15:14
    git stash show -p | git apply --reverse
    

    Warning, that would not in every case: "git apply -R"(man) did not handle patches that touch the same path twice correctly, which has been corrected with Git 2.30 (Q1 2021).

    This is most relevant in a patch that changes a path from a regular file to a symbolic link (and vice versa).

    See commit b0f266d (20 Oct 2020) by Jonathan Tan (jhowtan).
    (Merged by Junio C Hamano -- gitster -- in commit c23cd78, 02 Nov 2020)

    apply: when -R, also reverse list of sections

    Helped-by: Junio C Hamano
    Signed-off-by: Jonathan Tan

    A patch changing a symlink into a file is written with 2 sections (in the code, represented as "struct patch"): firstly, the deletion of the symlink, and secondly, the creation of the file.

    When applying that patch with -R, the sections are reversed, so we get: (1) creation of a symlink, then (2) deletion of a file.

    This causes an issue when the "deletion of a file" section is checked, because Git observes that the so-called file is not a file but a symlink, resulting in a "wrong type" error message.

    What we want is: (1) deletion of a file, then (2) creation of a symlink.

    In the code, this is reflected in the behavior of previous_patch() when invoked from check_preimage() when the deletion is checked.
    Creation then deletion means that when the deletion is checked, previous_patch() returns the creation section, triggering a mode conflict resulting in the "wrong type" error message.

    But deletion then creation means that when the deletion is checked, previous_patch() returns NULL, so the deletion mode is checked against lstat, which is what we want.

    There are also other ways a patch can contain 2 sections referencing the same file, for example, in 7a07841c0b ("git-apply: handle a patch that touches the same path more than once better", 2008-06-27, Git v1.6.0-rc0 -- merge). "git apply -R"(man) fails in the same way, and this commit makes this case succeed.

    Therefore, when building the list of sections, build them in reverse order (by adding to the front of the list instead of the back) when -R is passed.

    0 讨论(0)
  • 2020-11-29 15:20

    According to the git-stash manpage, "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," and git stash show -p gives us "the changes recorded in the stash as a diff between the stashed state and its original parent.

    To keep your other changes intact, use git stash show -p | patch --reverse as in the following:

    $ git init
    Initialized empty Git repository in /tmp/repo/.git/
    
    $ echo Hello, world >messages
    
    $ git add messages
    
    $ git commit -am 'Initial commit'
    [master (root-commit)]: created 1ff2478: "Initial commit"
     1 files changed, 1 insertions(+), 0 deletions(-)
     create mode 100644 messages
    
    $ echo Hello again >>messages
    
    $ git stash
    
    $ git status
    # On branch master
    nothing to commit (working directory clean)
    
    $ git stash apply
    # On branch master
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #       modified:   messages
    #
    no changes added to commit (use "git add" and/or "git commit -a")
    
    $ echo Howdy all >>messages
    
    $ git diff
    diff --git a/messages b/messages
    index a5c1966..eade523 100644
    --- a/messages
    +++ b/messages
    @@ -1 +1,3 @@
     Hello, world
    +Hello again
    +Howdy all
    
    $ git stash show -p | patch --reverse
    patching file messages
    Hunk #1 succeeded at 1 with fuzz 1.
    
    $ git diff
    diff --git a/messages b/messages
    index a5c1966..364fc91 100644
    --- a/messages
    +++ b/messages
    @@ -1 +1,2 @@
     Hello, world
    +Howdy all
    

    Edit:

    A light improvement to this is to use git apply in place of patch:

    git stash show -p | git apply --reverse
    

    Alternatively, you can also use git apply -R as a shorthand to git apply --reverse.

    I've been finding this really handy lately...

    0 讨论(0)
  • 2020-11-29 15:23

    In addition to @Greg Bacon answer, in case binary files were added to the index and were part of the stash using

    git stash show -p | git apply --reverse
    

    may result in

    error: cannot apply binary patch to '<YOUR_NEW_FILE>' without full index line
    error: <YOUR_NEW_FILE>: patch does not apply
    

    Adding --binary resolves the issue, but unfortunately haven't figured out why yet.

     git stash show -p --binary | git apply --reverse
    
    0 讨论(0)
提交回复
热议问题