简体   繁体   中英

git undo merge to master, but keep the changes locally

I had a feature branch and a master branch. I did some work on the feature, merged into master, pushed the changes, and then deleted the feature branch, both remotely and locally. So far, so good.

After merging, I realized there was a problem with my feature changes. I'd like to undo the merge on master, but still keep the feature changes so I can work on them again. How can I do this?

What I had originally:

A---B---C---D   [master]
     \      
      E----F    [feature]

What I have now:

A---B---C---D---EF (squashed) [master]

What I want:

A---B---C---D      [master]
             \
              EF   [feature]

How do I accomplish this?

There are many command sequences that can do it. Here is one short one.

  1. Make sure everything is committed ( git status ), so that step 3 can't wreck anything. This is always a useful base step. :-)
  2. Run git branch feature .
  3. Run git reset --hard HEAD^ or git reset --hard HEAD~ (either spelling is fine, use whatever you prefer to type in).

Explanation:

  • Step 1 should be obvious.

  • Step 2 creates the new name feature , identifying the same squashed EF commit that master identifies. This gives you:

     A--B--C--D--EF <-- master (HEAD), feature

    The (HEAD) annotation shows which branch name is the current branch name, and therefore which commit is the current commit as well (in this case EF ).

  • Step 3 moves the current branch name to point to the selected commit. The current branch name is, as we see in the diagram, master . The selected commit is one first-parent hop back from commit EF : EF^ means "first parent of commit EF " and EF~ means "starting from EF , step back one first parent".

    The result is:

     A--B--C--D <-- master (HEAD) \\ EF <-- feature

    which is what you wanted.

Note that EF~2 would start at EF and count back twice, to D then to C , so that master (still HEAD ) would point to commit C instead of commit D . The --hard to git reset tells Git to replace the index content with that from the chosen commit, and to update your work-tree to match.

You need to reset --sort master branch to the commit before merge D this will make you master head on D commit and the EF commit will be local on your machine, make sure from this then force push the master to remove unneeded EF commit then create new feature branch and commit the local changes to it again

Steps:

  • git reset --soft YOUR_COMMIT_HASH

  • git status // to make sure that your files not gone

  • git stash // to make your is head clean

  • git push -f origin master

  • git checkout -b feature

  • git stash pop // to retrieve the removed commit changes

reference: https://git-scm.com/docs/git-reset#Documentation/git-reset.txt---soft

This could be accomplished in 3 steps with:

On master branch:

$ git reset --hard <Hash of D>    # D is now the tip of master branch
$ git switch -c feature   # Creates a new feature branch based on D and move to it

Now on the newly created feature branch:

$ git cherry-pick <Hash of EF> # Restores the EF commit

This is all that is required.

When a branch is deleted, any lost commits can be found in the reflog for a given period of time ( 30 days by default ), so the EF commit hash could be found there just in case:

$ git reflog

Note: The switch -c command is available from git 2.23.0+ and does the same as checkout -b .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM