Merging with Git
Clone this wiki locally
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.
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 mergetoolto launch one.
git checkout --ours path/to/fileto reset a file to what it was before the merge.
git checkout --theirs path/to/fileto reset a file to what’s in the merging branch.
git diff ORIG_HEADto see what the merge has changed.
git addto stage resolved files, even if you used
git checkout --oursto throw out all merge changes in a file, as Git will recognize this and remove the file from the list of staged files.
git statusto monitor what files have been resolved and which still need help.
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
- 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.
- 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 firstname.lastname@example.org: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.