Rebasing a Git merge commit

后端 未结 5 906
滥情空心
滥情空心 2020-11-27 09:10

Take the following case:

I have some work in a topic branch and now I\'m ready to merge back to master:

* eb3b733 3     [master] [origin/master]
| * b6         


        
相关标签:
5条回答
  • 2020-11-27 09:53

    It looks like what you want to do is remove your first merge. You could follow the following procedure:

    git checkout master      # Let's make sure we are on master branch
    git reset --hard master~ # Let's get back to master before the merge
    git pull                 # or git merge remote/master
    git merge topic
    

    That would give you what you want.

    0 讨论(0)
  • 2020-11-27 09:55

    There are two options here.

    One is to do an interactive rebase and edit the merge commit, redo the merge manually and continue the rebase.

    Another is to use the --rebase-merges option on git rebase, which is described as follows from the manual:

    By default, a rebase will simply drop merge commits from the todo list, and put the rebased commits into a single, linear branch. With --rebase-merges, the rebase will instead try to preserve the branching structure within the commits that are to be rebased, by recreating the merge commits. Any resolved merge conflicts or manual amendments in these merge commits will have to be resolved/re-applied manually."

    0 讨论(0)
  • 2020-11-27 09:59

    Ok, that's an old question and it already have accepted answer by @siride, but that answer wasn't enough in my case, as --preserve-merges forces you to resolve all conflicts second time. My solution based on the idea by @Tobi B but with exact step-by-step commands

    So we'll start on such state based on example in the question:

    *   8101fe3 Merge branch 'topic'  [HEAD -> master]
    |\  
    | * b62cae6 2                     [topic]
    | |
    | | * f5a7ca8 5                   [origin/master]
    | | * e7affba 4
    | |/  
    |/|   
    * | eb3b733 3
    |/  
    * 38abeae 1
    

    Note that we have 2 commits ahead master, so cherry-pick wouldn't work.

    1. First of all, let's create correct history that we want:

      git checkout -b correct-history # create new branch to save master for future
      git rebase --strategy=ours --preserve-merges origin/master
      

      We use --preserve-merges to save our merge commit in history. We use --strategy=ours to ignore all merge conflicts as we don't care about what contents will be in that merge commit, we only need nice history now.

      History will looks like that (ignoring master):

      *   51984c7 Merge branch 'topic'  [HEAD -> correct-history]
      |\  
      | * b62cae6 2                     [topic]
      * | f5a7ca8 5                     [origin/master]
      * | e7affba 4
      * | eb3b733 3
      |/  
      * 38abeae 1
      
    2. Let's get correct index now.

      git checkout master # return to our master branch
      git merge origin/master # merge origin/master on top of our master
      

      We may get some additional merge conflicts here, but that's would only be conflicts from files changed between 8101fe3 and f5a7ca8, but not includes already resolved conflicts from topic

      History will looks like this (ignoring correct-history):

      *   94f1484 Merge branch 'origin/master'  [HEAD -> master]
      |\  
      * | f5a7ca8 5                   [origin/master]
      * | e7affba 4
      | *   8101fe3 Merge branch 'topic'
      | |\  
      | | * b62cae6 2                     [topic]
      |/ /
      * / eb3b733 3
      |/  
      * 38abeae 1
      
    3. The last stage is to combine our branch with correct history and branch with correct index

      git reset --soft correct-history
      git commit --amend
      

      We use reset --soft to reset our branch (and history) to correct-history, but leave index and working tree as is. Then we use commit --amend to rewrite our merge commit, that used to have incorrect index, with our good index from master.

      In the end we will have such state (note another id of top commit):

      *   13e6d03 Merge branch 'topic'  [HEAD -> master]
      |\  
      | * b62cae6 2                     [topic]
      * | f5a7ca8 5                     [origin/master]
      * | e7affba 4
      * | eb3b733 3
      |/  
      * 38abeae 1
      
    0 讨论(0)
  • 2020-11-27 10:03
    • From your merge commit
    • Cherry-pick the new change which should be easy
    • copy your stuff
    • redo the merge and resolve the conflicts by just copying the files from your local copy ;)
    0 讨论(0)
  • 2020-11-27 10:06

    Given that I just lost a day trying to figure this out and actually found a solution with the help of a coworker, I thought I should chime in.

    We have a large code base and we have to deal with 2 branch heavily being modified at the same time. There is a main branch and a secondary branch if you which.

    While I merge the secondary branch into the main branch, work continues in the main branch and by the time i'm done, I can't push my changes because they are incompatible.

    I therefore need to "rebase" my "merge".

    This is how we finally did it :

    1) make note of the SHA. ex.: c4a924d458ea0629c0d694f1b9e9576a3ecf506b

    git log -1
    

    2) Create the proper history but this will break the merge.

    git rebase -s ours --preserve-merges origin/master
    

    3) make note of the SHA. ex.: 29dd8101d78

    git log -1
    

    4) Now reset to where you were before

    git reset c4a924d458ea0629c0d694f1b9e9576a3ecf506b --hard
    

    5) Now merge the current master into your working branch

    git merge origin/master
    git mergetool
    git commit -m"correct files
    

    6) Now that you have the right files, but the wrong history, get the right history on top of your change with :

    git reset 29dd8101d78 --soft
    

    7) And then --amend the results in your original merge commit

    git commit --amend
    

    Voila!

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