开发者

Why does hg update command merges in some scenarios but not all?

开发者 https://www.devze.com 2023-03-28 08:23 出处:网络
Case 1: Updating the Working Directory $ hg update [-r REV] This switches the working directory to the specified revision. However if my working directory has modified changes, the changes are merg

Case 1: Updating the Working Directory

$ hg update [-r REV]

This switches the working directory to the specified revision. However if my working directory has modified changes, the changes are merged back with REV. I realize I c开发者_开发技巧an use the -C flag to discard my changes but I am trying to put across my concern to the behavior of update command in different scenarios.

Case 2: Switching to a Branch

$ hg update <bname>

This switches my working directory to <bname> branch. However my uncommitted changes are not merged until I explicitly use the merge command.

Case 3: Updating pulled change sets from a Remote Repository

$ hg pull
$ hg update

This again merges my working directory with the change sets from the remote repository after a recent pull.


Mercurial 1.9.1

It has to do with the relationships between changesets. If there is a direct path between the parent changeset of the working directory and the target changeset you're updating to, Mercurial will try to transfer the changes in the working directory with a merge operation. So if the changeset you're on is either a direct descendant or direct ancestor of the changeset you want to update to, it will usually work.

In the following diagrams, letters represent branch names and the numbers are the sequential revision numbers. wd is the working directory.

When Mercurial will merge uncommitted changes:

  • Update on the same branch:

    --A1----A3----A5---wd
       \          /
        A2------A4
    

    Above, changes have been made based on A5. If you update to A4, Mercurial will merge the uncommitted changes to transfer them.

    --A1----A3----A5---A6---wd
       \          /
        A2------A4
    

    Also, if there are additional changesets (such as A6) this will still work, because A4

  • Update to different branch (this time, updating to B4):

    --A1----A3----A5---wd
       \          /
        B2------B4
    

    Above, revisions 2 and 4 are on a different branch B, which has been recently merged back to branch A. Mercurial will also transfer uncommitted changes, because A5 and B4 are so closely related. And also:

    --A1----A3----A5---A6---wd
       \          /
        B2------B4
    
  • Likewise, when you pull new changes from the remote repo, usually they will be descendants of the changeset that is the parent of your working directory, so that provides the direct relation that makes the merge of uncommitted changes possible:

    --A1----A3----A5---A6---wd
       \          /     \
        A2------A4       A7---A8---A9   (A7 through A9 pulled)
    

When Mercurial will not merge uncommitted changes:

  • Update on the same branch:

    --A1----A3----A5
       \          /
        A2------A4---A6---wd
    

    Above, changes have been made based on A6. If you update to A5, Mercurial will refuse, saying either "outstanding uncommitted changes" or "crosses branches". This is because you're trying to merge uncommitted changes from one head to another head, and they are (by definition) not ancestors or descendants of each other. The same occurs with named branches, of course:

    --A1----A3----A5
       \          /
        B2------B4---B6---wd
    

Getting around it

There's a few different ways you can move your changes to a new parent when Mercurial won't automatically try to merge the uncommitted changes:

  • Shelve the changes, update, then unshelve (manually handling conflicts).
  • Making a patch in MQ will do the same thing, as shelving uses the same patches, just not a queue of them. You'll refresh the patch, pop it, update to the other branch, and then push the patch (manually handling conflicts).
  • Commit the changeset, rebase it to the other branch (you will have to go through a merge process), and then import it into MQ so that it isn't a changeset anymore but a patch.


Forget about branch names, they are nothing more than metadata on the changesets. Your changes will be merged if you update to a revision which is either a descendant or ancestor of your current working parent, and they won't be merged otherwise.

Thus, you can update from A to B, if there is a way to get from A to B, moving along either parents only, or children only. E.g.:

 -- A -- 1 -- 2 -- B --

Here, you can update from A to B and from B to A because they are descendant and ancestor of each other.

 -- A -- 1 -- 2 -- C --
               \
                4 -- B --

Here, you also can update from A to B (or from B to A), even if they are on different branches. You cannot, however, update from B to C, because to do so, you'll first have to go backward, then forward.

Note you can work around it by doing the backward-forward maneuver yourself:

(on revision B)
$ hg up 2
$ hg up C
0

精彩评论

暂无评论...
验证码 换一张
取 消