wiki:git/merge
Last modified 5 years ago Last modified on 02/03/13 22:58:04

Merging with git

In git, branching is easy and lightweight, and you should branch often. You can later sync two diverging branches with git merge. The basic syntax is to checkout the branch you want to merge into and call git merge with the name of the branch you want to merge from. For example:

git checkout working
git merge master

will merge changes in master not currently present in the working branch into the working branch. If the changes between the branches do not overlap, the merge is easy: files modified in the merge-from branch (master) are copied into the merge-to branch (working).

Merge conflicts

If both branches modify the same file, git will try to automerge the the changes into a single, coherent version. Sometimes, however, this is not possible, and a merge conflict results. This is perfectly normal, and git provides options for resolving the conflict. The git book provides a good quick overview of merge conflicts and ways of resolving them. Git will list conflicts after a merge in git status

Suppose we have a file awesome.cpp in the master branch and the working branch. In the master branch, the file looks like

#include "awesome.h"

void foo1(){
        printf("awesome!");
}

void foo2(){
        printf("sweet?");
}

In the working branch we have

#include "awesome.h"

void foo1(){
        printf("awesome!");
}

void foo2(){
        printf("sweet!");
}

void baz(){
        foo2();
}

When we merge, we get a conflict...

$ git merge master
Auto-merging awesome.cpp
CONFLICT (content): Merge conflict in awesome.cpp
Automatic merge failed; fix conflicts and then commit the result.

$ git status
# On branch working
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#	both modified:      awesome.cpp
#

git will modify the file and blend the changes of both branches into a cpp that is unlikely to compile

#include "awesome.h"

void foo1(){
        printf("awesome!");
}

void foo2(){
<<<<<<< HEAD
        printf("sweet!");
}

void baz(){
        foo2();
}
=======
        printf("sweet?");
}

>>>>>>> master

Blocks of changes have the form

<<<<<<<< HEAD 
  our version
=========
  their version
>>>>>>>> (name of branch we merged from

There are three options for resolving the merge on each conflicting file

  • keep our version using git checkout --ours awesome.cpp
  • accept their version using git checkout --theirs awesome.cpp
  • mix both versions by hand and add the merged result

Here, the flag --ours refers to the branch you are merging into. The flag --theirs refers to the branch you are merging from. It may be the case that --ours and --theirs are really both yours, but this is the convention git uses.

If you decide to resolve the conflict by hand, remember to remove the <<<<<, ====, and >>>> tags and test that the merged result compiles before committing the change. If all looks good, mark the conflict as resolved using

git add awesome.cpp
git commit 

git will automatically generate a log message indicating that the commit was the result of a merge and list any files that conflicted during the merge. You can simply accept this message without modification.

Examples when sharing with partners

In this course, you may find that your first merge has lots of conflicts. Some of them might have nothing to do with project1 and be in some other directory. For these files, it is probably best to use git checkout --ours to keep your local changes. Withing the projects/01 directory you may want to use a combination of --ours, --theirs and hand merging.

Merge won't start

Sometimes the merge won't start if you have uncommitted changes that would be overwritten by the merge. If you get an error like

error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)

or

error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)

you will need to add and commit your local changes first (using git add and git commit), reset your changes using git checkout --, or temporarily stashing your changes before running the merge. You may need to do this before pulling too, since pull effectively fetches remote changes and merges them into your local branch.