smeeb
smeeb

Reputation: 29567

Mercurial commands for merging both conflicting and non-conflicting changes

Mercurial 3.4.1 on Mac Yosemite (10.10.5) here. I don't know why I find hg so confusing. I cloned a repo several weeks ago and have been pecking away at it here and there. I'm now ready to push all my changes to the remote hg server but several other developers have made changes (both conflicting and non-conflicting) in the meantime. This project uses pure mainline development (no branching) against default.

I ran hg add . and then hg commit -m "Fixing x, y and z.", and now I need to merge my local default HEAD with the default HEAD on the remote/origin hg server. So I need:

Not sure that it makes a difference, but a lot of my changes also refactored the basic project structure (deleted/renamed/moved both source files and directories). So these changes should be pretty significant.

Reading the hg merge doc, I'm now even more confused than before! No where does that doc specify how to explicitly merge my local default HEAD with the remote default HEAD. Furthermore, the doc mentions:

"hg resolve" must be used to resolve unresolved files.

What are unresolved files?!? Do I have to run this command prior to hg merge? How does it affect/interact with the merging process?

Upvotes: 0

Views: 1222

Answers (2)

Reimer Behrends
Reimer Behrends

Reputation: 8740

The hg merge command merges the files in the current working directory with the changes in the revision specified by the -r argument (if the current working directory is the checkout of a head of a branch and the branch has exactly one other head, then the other revision to merge with is inferred automatically). The result of the merge can then be committed and (upon commit) becomes a child revision of these two revisions. What you usually do is therefore:

hg update ORIGINAL_REVISION
hg merge -r NEW_REVISION

Both ORIGINAL_REVISION and NEW_REVISION can be specified as described in hg help revisions or hg help revsets.

The result of hg merge will be the result of combining the changes in NEW_REVISION with ORIGINAL_REVISION. Whenever Mercurial can combine the changes without any apparent conflicts, it will do that. Note that hg merge will not commit the combined changes, but only update the working directory; committing them to create a merge commit is a separate step.

What happens if there is a conflict? If there is a merge tool available (Mercurial will try to be smart about available merge tools and select one from a list it knows about if one is available, but you may have to specify it explicitly, e.g. via the --tool option; see hg help mergetools for more details), this tool will be started and you can resolve the conflict in there. If no tool from its list is available and you haven't specified one (via your .hgrc, the HGMERGE environment variable, or the --tool option), Mercurial will fall back to its internal conflict resolution tool (equivalent to --tool :merge), which will simply add conflict markers to the file that can then be resolved either manually inside your editor of choice or with a tool that knows how to handle such conflict markers.

You can use hg resolve to review and update the list of files with conflicts. Specifically, hg resolve -l will list the files that had conflicts, prefixed by R if the conflict has been resolved (e.g. by a merge tool or because you marked it as resolved) or U if the conflict remains unresolved. You can use hg resolve -m FILE to mark FILE as resolved or hg resolved -u FILE to mark it as unresolved (you can also provide a list of files or -a to mark all files). You can use hg resolve --tool TOOL FILE or hg resolve FILE to redo the merge for a specific file.

Once hg resolve -l shows no more unresolved conflicts, you can then commit the merge.

If at any point during the merge your working directory ends up in a state that you cannot seem to recover from, hg update -C will abort the merge and undo the entire merge (careful: you will lose any merging resolutions that you have done so far).

If (as you indicated) you also renamed or deleted files, additional effort may be necessary. Normally, you should use hg mv to rename files, hg cp to copy them, and hg rm or hg forget to remove them. This will inform hg merge what their common ancestor is and allows changes from both branches to the same file to be combined, even if both branches have them ending up in different files. If you didn't do that, you can use hg addremove -s PERCENTAGE to try and let Mercurial smartly discover renames and copies (mind you, this still has to be done before you commit or merge the changes). The -s/--similarity argument is a percentage (by default 100) that indicates how similar files have to be in order to be seen as a rename/copy of one another. You can use -n or --dry-run to just have hg addremove list what it would do without actually doing it.

Upvotes: 3

planetmaker
planetmaker

Reputation: 6044

A merge is always a local operation where you merge one revision into another from another branch or head.

When you used the internal merge tool, it will add conflict markers to the places where it needs internal intervention. You usually visit those files, fix the conflict and then mark the conflicts resolved within those file(s) explicitly by using hg resolve --mark FILE. You cannot commit the merge before not all those merge conflicts have been marked as handled. You can mark all conflicts as handled at once: hg resolve --mark --all - but be sure that you actually handled all merge conflicts or your files will be committed with merge conflict indicators remaining which likely is not what you want.

Upvotes: 1

Related Questions