Skip to content
phillipadsmith edited this page Apr 4, 2011 · 4 revisions

Merging between branches could not be easier in Git. Gone are the nightmare days of manually having to track when you last merged, or when you branched, in order to tell Subversion or CVS what commits to merge. Furthermore, a Git merge is a real merge.

When you merge in Subversion, all it does is diff the two branches and then apply the diff. Then you commit the merge as one big, gigantic commit. Git, on the other hand, can merge branches in a number of different ways (see git-merge for details). If there are no conflicts, the merge is automatically committed with a useful log message. If there are conflicts, well you simply resolve them and then commit the merge. Either way, you never have to remember when you last merged, because Git remembers for you. You don’t even have to tag a merge anymore.

That’s not to say that merges will always be simple or easy. It’s worthwhile to familiarize yourself with the Git way of branching and merging.

Example Merge

Let’s say that there have been a bunch of bug fixes in the rev_1_10 maintenance branch, and you want to merge them into master so that the next major release will have the same fixes. (This will be a common task for Bricolage core developers to keep things up-to-date in the core repository.) Here’s what you do:

First, make sure that both branches are up-to-date:

cd bricolage
git checkout rev_1_10
git pull origin rev_1_10
git pull upstream rev_1_10
git push origin rev_1_10
git checkout master
git pull origin master
git pull upstream master

We issue to calls to git pull for each branch in order to ensure that we have all of the latest commits both from our “origin” repository on GitHub, as well as the Bricolage project’s canonical repository up-stream (see “Working with Git” for how to set up the upstream link). We also issue a git push to make sure that all of our local changes have been pushed back up to GitHub. Now we’re ready to merge!

git merge rev_1_10

This command should show what files are being merged, something like this:

Auto-merging README
Auto-merging contrib/bric_media_upload/bric_media_upload
Auto-merging lib/Bric/Admin.pod

Once it’s done, the merge will be committed. Boom! You’re done. Nothing to do but push the merge up to your fork on GitHub. But if there were conflicts, it might look more like this:

Auto-merging README
CONFLICT (content): Merge conflict in README
Auto-merging contrib/bric_media_upload/bric_media_upload
Auto-merging lib/Bric/Admin.pod
Automatic merge failed; fix conflicts and then commit the result.

So you’ll have to resolve the conflicts. This basically means that you edit the files with conflicts to resolve them, then use git add to stage them to be committed. Once you’re done, then you commit the merge with git commit. Git will know that it’s a merge and generate the appropriate commit message.

That’s not to say that merging is always straight-forward. Here are some tips to help work through the conflicts:

  • If you’re familiar with graphical resolution tools, use git mergetool to launch one.
  • Use git checkout --ours path/to/file to reset a file to what it was before the merge.
  • Use git checkout --theirs path/to/file to reset a file to what’s in the merging branch.
  • Use git diff ORIG_HEAD to see what the merge has changed.
  • Use git add to stage resolved files, even if you used git checkout --ours to throw out all merge changes in a file, as Git will recognize this and remove the file from the list of staged files.
  • Use git status to monitor what files have been resolved and which still need help.

The git status command can actually be very useful. It will output something like this:

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	modified:   contrib/bric_media_upload/bric_media_upload
#	modified:   lib/Bric/Admin.pod
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	unmerged:   README

Once the “Changed but not updated” section is empty, you’re ready to commit the merge! Run git commit, accept the default commit message, and you’re done.

Well, almost. Whether or not you had commits, you’ll want to push the merge up to GitHub:

git push origin master

Merging into Core

As of this writing, the GitHub fork queue does not support merges. Until that changes, if you want to get a merge into the canonical Bricolage repository, there are really only two approaches:

  1. If you have commit access to the canonical repository, you can clone it directly, do the merge, and then push it back up to the “bricoleurs” account.
  1. If you don’t have commit access to the canonical repository, you’ll need to do the merge in a fork, push it up to GitHub, and then submit a pull request, as usual. It will then be up to a core developer to pull in the merge from your fork.

If you are a Bricolage core developer, and you or someone else has performed merge in a fork, here’s how you pull it into the canonical repository
replacing Git URL on the git add remote line with the name of the forked repository with the merge to be pulled in:

git clone [email protected]:bricoleurs/bricolage.git
cd bricolage
git remote add merger git://github.com/username/bricolage.git
git pull merger master
git push origin master
git remote rm merger

This allows you to pull in all changes from the forked repository, including the merge. If that is the only difference between the fork and the canonical repository, this will work well. If it’s not the only difference, you might have to cherry-pick commits to pull in. YMMV.

Clone this wiki locally