You are on page 1of 22

What every programmer should know about merging branches in Mercurial

Sergey Kishchenko
Quickoffice

October 11, 2012

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

1 / 22

Branches
Two different branches Two different defaults

NOTE: Different repos cloned from one source are not actually different, they are essentially same repo. You can transfer changesets between them with push and pull IMPORTANT: Named branches in Mercurial are permanent!
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 2 / 22

Pull
First step in merge process: pulling remote changes > hg pull -b REMOTE_BRANCH REMOTE_REPO

Pulling change pulls also all its ancestors → unneeded changes Pulling changes may result in creating new heads → merge is needed Pulling branch pulls also all branches it’s based on → merge is needed
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 3 / 22

Solution attempt: ”early-fix” branch

Bad idea

Good idea

Having a specific fix branch allows pulling this branch without pulling other changes (Feature A) You should think about it in advance and you’re not a psychic

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

4 / 22

Solution attempt: Patch
IDEA: Why do we even need to use pull?

Fix A can be based on Feature A so patch will not apply smoothly SCM can’t guess that Fix A and Fix B are actually the same and should be used as base when merging Fix C
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 5 / 22

Solution attempt: graft
Using graft > hg graft --log GRAFT_REVISION

graft uses 3-way merge and deals fine with Fix A being based on Feature A SCM still can’t guess that Fix A and Fix A’ are actually the same and should be used as base when merging Fix C
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 6 / 22

Solution attempt: grafting from remote repo

graft doesn’t deal with changesets from the remote repo at the moment because it needs all of the changes to do 3-way merge. But it’s possible to strip changes when they are not needed anymore grafting from remote repository > hg incoming --template="{node} " REMOTE_REPO -q \ -r GRAFT_REVISION > TEMP_FILE > hg pull -r GRAFT_REVISION REMOTE_REPO > hg graft --log GRAFT_REVISION > hg strip ‘cat TEMP_FILE‘

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

7 / 22

Solution attempt: dealing with base issues with graft

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

8 / 22

Solution attempt: dealing with base issues with graft

Searching for grafted revisions
> hg log -r "ancestor(LOCAL_HEAD,OTHER_HEAD)::LOCAL_HEAD" \ -k "grafted" -v e.g. > hg log -r "ancestor(d5c1ff557965,927d19ecf38e)::d5c1ff557965" \ -k "grafted" -v

graft-aware merging > hg merge -R GRAFT_REVISION > hg merge

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

9 / 22

Solution attempt: Branches alternatives
Bookmarks: http://mercurial.selenic.com/wiki/Bookmarks Lightweight git-like branches, good for local hacking, distributed along with Mercurial. Several heads on default branch, no trail in history Local branches, lbranches: http://mercurial.selenic.com/wiki/LocalbranchExtension. Lightweight repo clones, good for local hacking Just a local feature Patch queues, mq: http://mercurial.selenic.com/wiki/MqExtension Patch series, editable history, distributed along with Mercurial Just a local feature
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 10 / 22

Merge
Merging different branches > hg co local_branch > hg merge remote_branch > hg ci -m merge Merging heads in default branch > hg merge (while in default branch) > hg ci -m merge

Looks easy, huh? But it is not easy at all because of possible conflicts
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 11 / 22

Merge problem: too many conflicts
Why occurs?
Synchronizing rarely Tight coupling of the components Too many developers for one component Storing autogenerated code in the tree

How to prevent?
Synchronize often Simplify connections between components Design clear and minimalistic API Notify other developers of the component when doing changes Don’t exceed the reasonable amount of developers for one component Do not store autogenerated code in the tree

How to deal with?
Use a good graphical merge tool that allows 3-way merging Learn how to use the resolve command
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 12 / 22

3-way merge
Base (B) line1 Local (L) line1 line2 Merged (M) line1 modified line2 Remote (R) line1 modified

Without base it’s hard to merge Local and Remote files: it’s hard to understand was it a removal of ”line2” and addition of ” modified” or removal of ” modified” and addition of ”line2” → use a 3-way graphical merge tool Subjective choice: http://mercurial.selenic.com/wiki/KDiff3
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 13 / 22

resolve command
Imagine you need to merge a lot of changes Bad idea > hg merge # non-stop merging, here I come! Good idea
> > > > hg hg hg hg merge -t "internal:merge" # does the best it can automatically resolve -l # shows merge state resolve FILE # runs conflict resolving for specific file resolve -a # runs conflict resolving for all unresolved files

IMPORTANT: Unfortunately, resolve command doesn’t save progress when interrupted. There is an issue for that: http://bz.selenic.com/show_bug.cgi?id=3638. Possible workaround: iterate through conflicts and call resolve for each file
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 14 / 22

Merge problem: hard to understand the conflict
Also known as ”I don’t know which change is correct” Why occurs?
Synchronizing rarely → forgetting what was going on Merging components without component knowledge

How to prevent?
Synchronize often Spread the components knowledge among developers → code cross-review

How to deal with?
Use help from those who have good component knowledge Learn how to use log (shows the history) and blame (shows who is the author of the changes) command

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

15 / 22

Merge problem: code was refactored
Also known as ”It seems the code was removed remotely so I can drop the local change” (immediately eaten by velociraptor) Why occurs?
Doing the refactoring and not merging it into all branches immediately Merging refactored components without component knowledge

How to prevent?
Spread the ongoing refactoring knowledge among developers → code cross-review Use ”early-fix” branch for refactoring and merge it immediately or notify everyone about it

How to deal with?
Use help from those who have good knowledge about the refactoring Use 3-way merge (check next slide) In case different refactoring was done in both local and remote versions, you’re DOOMed :(
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 16 / 22

Using 3-way merge for merging refactored code
1

2

3

Use 3-way merge graphical tool to see base(B), local(L) and remote(R) version of a file Let’s assume refactoring was done only in remote. It means that base-local difference is not large, it’s all about modifying names, adding params, issues fix, etc. Base and remote differ a lot, often the remote version is completely missing, i.e., was moved to different file. Use log to identify what was refactoring about. E.g., you can find the file that is a new home for the code that is missing from the R

Use log to find refactoring changesets > hg log --follow R
4

5

Iterate through base-local differences change by change and apply them to the code in a correct place In any case consider contacting those who did the refactoring for help and/or code review
What every programmer should know about merging branches in Mercurial October 11, 2012 17 / 22

Sergey Kishchenko (Quickoffice)

Merge problem: non-source files conflicts
Why occurs?
Modifying the resource/project file and not merging it into all branches immediately Storing user settings in the tree Synchronizing rarely Pointless modification of project files/resources

How to prevent?
Avoid pointless modification of non-source files Consider using an ”early-fix” branch for non-source file modification and merge it into all branches immediately Do not store user settings in the tree Consider storing mergeable sources instead of the non-source products

How to deal with?
Consider using a specialized tools to merge specific files In case files are not mergeable choose either local or remote version and try to reproduce all of the changes from the other version
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 18 / 22

One more time: good things
Using branches wisely Specifying branch for pulling and pushing Using graft Using good graphical tool for merging Using 3-way merge Using ”early-fix” branches Getting knowledge from others when merging theirs code Providing help to those who merge your code Providing a good description for the changes Using hg cp and hg mv commands to copy and rename/move files Cross-code reviews Small self-contained changesets Writing easy understandable code!
Sergey Kishchenko (Quickoffice) What every programmer should know about merging branches in Mercurial October 11, 2012 19 / 22

One more time: bad things

Manual merges Applying patches manually Being a coward and selecting either local or remote version without checking it Trusting automatic merge tools completely Using bad names for branches Using --force flag Copying and moving files without using hg cp/hg mv

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

20 / 22

One more time: things to avoid

Doing a refactoring that can’t be merged into all branches immediately Modifying non-source file without merging it into all branches immediately Modifying a component that somebody is working on without notifying this person Storing autogenerated code and user settings in the code tree Using branches without bookmarking or naming them Committing all of the changes in one changeset

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

21 / 22

Thank you! Questions?

Sergey Kishchenko (Quickoffice)

What every programmer should know about merging branches in Mercurial October 11, 2012

22 / 22