Merging a Feature Branch

From GeeklogWiki
Jump to: navigation, search

What's a Branch?

It is important to realize that the term "branch" in Mercurial does not (always) refer to the same thing as in other version control systems (such as Subversion).

When you clone an existing repository (such as Geeklog's) and commit a change to your local repository, you have now created a branch (in Mercurial terms). When you try to push back your changes to the parent repository, you may be lucky: If nobody else pushed any changes in the meantime, then your branch simply becomes the main branch again (called "default" on a standard Mercurial repository, but "HEAD" in case of Geeklog's repository).

If, however, someone else got lucky before you, you will now face the problem of having to merge. Here's how ...

What NOT to do

Don't do hg push -f, even though Mercurial suggests it. This would push your branch to the parent repository as-is. Someone else pulling from that repository would only get your changes when switching to your branch and would at the same time miss all the other changes.

For Geeklog, we sometimes create branches deliberately. But those are named branches, used for security and bugfix releases (and the equivalent of a branch in Subversion). Creating such a named branch is the only time where it's fine to use hg push -f.


Where to merge

Suppose you have two local repositories: One repository named "geeklog", which is a clone of the current version of the main Geeklog respository, and one repository called "myfeature" which is an older local copy that contains the changes that you want to push back to the main repository.

You now have two options: You could either go into your "geeklog" repository and pull the changes from "myfeature". Or you could go into "myfeature" and pull from "geeklog".

You should be doing the latter:

cd myfeature
hg pull .../geeklog

The reason for doing it this way is to ensure that changes made in "geeklog" will not be lost, i.e. reverted to the older code that is in "myfeature".


The above hg pull command will probably end with a message such as this:

added 516 changesets with 2489 changes to 562 files (+1 head)
(run 'hg heads' to see heads, 'hg merge' to merge)

If you perform the suggested hg heads, you will get a list of all the heads in the repository. Usually, you will be interested in the first two heads listed. You should recognize the second one - it's usually your last commit to the "myfeature" repository. The other head is the latest commit to "geeklog".

So what you need to do now is to merge these two heads.


Each of the listed heads will include a line such as this:

changeset:   7598:7ff48f0151aa

(be careful to pick the "changeset" line - there may be other entries that look similar, e.g. "parent")

Identify the head you want to merge with and pick either of the two numbers (before or after the ':') to use as the revision number for the hg merge command, e.g.

hg merge 7598

This command will then display a list of files that Mercurial attempted to merge.

If you're lucky, Mercurial will do all the work for you and you only need to commit the merged changes (after which step you can finally push your changes to the parent repository).

However, things aren't always so easy and chances are that you are getting messages such as

merging public_html/lib-common.php
warning: conflicts during merge.
merging public_html/lib-common.php failed!
521 files updated, 20 files merged, 3 files removed, 12 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon

This now means that Mercurial encountered problems in some of the files (12 in the above example) and needs manual intervention.

Resolving Conflicts

You can always get the current status with hg resolve -l ('l' for "list"). This command will present a list of all the files that needed merging. Files that have been merged successfully are prefixed with a 'R' (for resolved). Those that need your attention are prefixed with a 'U' (for unresolved):

R public_html/index.php
U public_html/lib-common.php

Open the file to be resolved. Search for "<<<<<". You will find a section of the code that looks like this:

<<<<<<< local
        if(( $_CA_CONF['personalcalendars'] == 1 ) && !empty( $_USER['uid'] )) {
        if (($_CA_CONF['personalcalendars'] == 1) && !COM_isAnonUser()) {
>>>>>>> other

You need to concentrate on the section between the "local" and the "other" markers. The first section (up to the '=======' marker) is what Mercurial found in the local copy of the files, i.e. in your "myfeature" repository. The second section is the code as it looks in the "geeklog" repository.

You now need to decide which of the two sections to keep. You can then remove the code you don't want to keep. Don't forget to remove the three marker lines as well!

Search for further occurences of the "<<<<<" marker - there may be more than one conflict in the same file!

Once you've resolved all the conflicts in a file and saved your changes, you can tell Mercurial that you now consider this conflict resolved:

hg resolve -m public_html/lib-common.php

('m' for "mark as resolved" - adjust filename as necessary, of course)

Once you have resolved all the conflicts in all of the files, you can commit the changes and finally push everything back to the parent repository.