Mercurial - backout an old merge

前端 未结 6 1640
礼貌的吻别
礼貌的吻别 2021-02-13 02:24

I have a branch that looks like this:

A->B->C->D->...->Z
     ^
1->2-^

where C is a merge from 2 an

相关标签:
6条回答
  • 2021-02-13 02:56

    You could use the thg backout tool.

    1. Update to the merge change set (C)
    2. thg backout
    3. Pick which parent you want to backout (whatever the revision for (2) is) - Note you actually pick on the dialog the parent whos changes you want to keep not backout.
    4. Click Next
    5. Click Commit

    This will create a new head which you will need to merge with Z or rebase on to Z.

    0 讨论(0)
  • 2021-02-13 02:59

    Merge is public and there are public commits on this merge

    Assume we have this published history of commits (top is the newest):

                      revZ
                       |
                      ...  
                       |
                      revD
                       |
                      revC     <- unwated merge commit (rev2 to revB)
                       |   \    
    wanted branch ->  revB  rev2    <- unwanted branch
                       |     |
    

    Instead, we would like to have top state as if we had this history:

                      revZ'
                       |
                      ...  
                       |
                      revD'
                       |       
    wanted branch ->  revB  rev2    <- unwanted branch
                       |     |
    

    How to achive this (step by step)

    1. Callapse the history after merge commit (revD - revZ) into one commit

      $ hg update -r revC                # Update to merge commit
      $ hg revert --all -r revZ          # revert to the newest commit
      $ hg commit -m "collapsed commits" # Create new commit (revTmp1)
      
                         revZ
                          |  
                         ...
                          |  
                 revTmp1 revD
                       \ /
                       revC
                        |  \    
                      revB  rev2
                        |    |
      
    2. Copy changes after merge (revTmp1) to wanted branch (revB)

      $ hg update -r revB    # Update to the last "wanted" commit before merge
      $ hg graft -r revTmp1  # Copy changes from revTmp1 (create revTmp2 commit)
      
                         revZ
                          |  
                         ...
                          |  
                 revTmp1 revD
                       \ /
              revTmp2  revC
                    \  / \    
                   revB  rev2
                     |     |
      
    3. Create a "backout" commit

      $ hg update -r revZ                   # Update to the top commit
      $ hg revert --all -r revTmp2          # Copy state revTmp2
      $ hg commit -m "reverted revC merge"  # Create revZ' commit
      
                         revZ'
                          |
                         revZ
                          |  
                         ...
                          |  
                 revTmp1 revD
                       \ /
              revTmp2  revC
                    \  / \    
                    revB  rev2
                     |     |
      
    4. Clean the temporary commits

      $ hg strip revTmp1 revTmp2
      
                        revZ'          <- reverted revC merge
                         |  
                        revZ
                         |  
                        revD
                         |
                        revC     <- unwated merge commit (rev2 to revB)
                         |   \    
      wanted branch ->  revB  rev2    <- unwanted branch
                         |     |
      
    0 讨论(0)
  • 2021-02-13 03:06

    A little bit late, but I had the same situation a while ago. This worked for me smoothly:

    hg update -C -r "revision-C"
    hg revert --all -r "revision-B"
    hg commit -m 'UNDO blah blah whatever the merge did'
    hg update -C -r "revision-Z-or-whatever-the-current-head-is"
    hg merge -r "the-new-revision-created-in-step-3"
    

    Basically, this is exactly what backout does.

    DISCLAIMER: Please note however that if you later in the future want to merge the 1->2 branch again, you will most probably run into some issues. And "some issues" is a somewhat euphemestic term here. In fact, even BIG PROBLEMS may appear in such a case. This scenario is dangerous mainly because the problems may arise much later and totally unexpected. It is highly recommended to abandon the "1" branch completely to avoid these risks. (Also see the comments below.)

    For details, see Backout wiki page.

    0 讨论(0)
  • 2021-02-13 03:06

    You can rebase D to Z onto B. The documentation for rebase even discusses some similar situations. This should be doable in one command.

    0 讨论(0)
  • 2021-02-13 03:10

    Use backout tool, but be aware of what you are doing:

    1. Update to the merge change set (C)
    2. Right click on that change set -> click Backout
      • After you do backout on branch, you don't need to commit it immediately. Better check before, if there (among changes that arose after chosing Backout option) aren't some changes from other branches that you don't want to back out. If so, uncheck them before commit.
    3. Click Commit
      • If you would merge branch 1-2 (or "numbered branch") into branch A-Z now (or later), you will lose all changes from "numbered branch" before changeset 2 (including) - that's what warning in @Marvin's answer is about.
      • To avoid that, you need to propagate this backout into "numbered branch" and redo backed out changes (later steps).
    4. If branch A-Z is not direct ancesstor of "numbered branch", then find first descendant branch between A-Z and 1-2 and update workbench to its tip.
    5. Right click on the latest revision in A-Z (= backout) -> click Merge with local
      • If there are more branches between A-Z and 1-2, repeat steps 4. and 5.
      • Don't merge anything into branch 1-2 yet.
      • Note: Always merge any branch only into the one from which it origins! Otherwise you risk losing some changes after future merges.
    6. Update to the tip of "numbered branch".
    7. Find all files (on filesystem) that were changed by backout and copy them to some temp directory.
    8. Right click on the latest revision of numbered branch's ancesstor -> click Merge with local
    9. Copy files from step #7 back to filesystem.
    10. Check changes in worbench and uncheck all changes, that are not from branch 1-2 (for example changes from revisions D - Z).
      • Unfortunately this has to be checked manualy. But it's the only safe way how to correct both branches.
    11. Click commit

    Tip: To be really sure what files were affected by any merge, right click on that revision and click Diff to parent

    This is basically scenario that we used today, when we find out that one branch (which was still in development) was accidentally merged into default (instead of another one, which had the same color in revisions graph :). (Both branches had pushed changes after this merge.) It might seems time-consuming, but still better than backout merge only and find numerous unexpected errors days (or weeks) later. (Own experience.)

    0 讨论(0)
  • 2021-02-13 03:10

    Mercurial does allow backing out a merge revision; however, the functionality is deprecated. The danger is that backout does nothing but perform a reverse commit; if you change your mind and want to re-add the removed merge, you can't do this by merging the branch again. (Hg will refuse to perform a merge with an ancestor of the current revision; or, if there were some other commits on the branch after the merge, it will only merge the following commits.)

    The command syntax is:

    hg backout --rev MergeRevision --parent ParentRevision

    Where ParentRevision is the parent of the merge revision on the original branch (i.e. not on the merged branch); usually, this is the first parent of the merge.

    The command is not available in TortoiseHg Workbench.

    After performing the backout (and resolving potential conflicts), make sure to review the new revision and amend it if necessary.

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