So far, we've just looked at committing content to the git repository. In other words, we've been building up linear histories, one commit at a time. Although there's nothing wrong with this – after all, most other version control systems you've been used to may work in exactly that way – there's a lot of power that Git bestows upon you with branches.
A lot of people avoid branching, if they've only been used to lesser version control systems like CVS or SVN. That's not because branching is especially different (although still an order of magnitude slower than Git) – rather, it's the lack of good merging that kills branching. As a result, branches are reserved for product releases, and then, begrudgingly.
Git, on the other hand, makes branching and merging free – so much that branching becomes a way of life in a Git workflow.
A merge brings together one more commits onto the current branch. Typically the commits are branch names, but they can be any hash in the repository.
A common workflow is to branch off an item of development to implement a new feature. In non-distributed systems, this is often represented as the “check it out but don't commit it” phase; but in Git, creating a branch is free and committing as you go is encouraged – a bit like autosaving your source files. When you're ready, you can merge it back onto the main development branch:
$ git checkout -b feature # implement feature $ git commit -m "Feature part 1 implemented" # implement feature $ git commit -m "Feature part 2 implemented" # test, check everything is OK # Switch back to master: $ git checkout master $ get merge feature # Optionally, delete the feature branch $ git branch -d feature
What we've done here is create a new feature branch
feature, worked on it for a while, then switched back to
merged the contents in. It's fairly common for this pattern to occur frequently; sometimes, with features overlapping each other. Don't worry about it; Git always keeps track of your changes.
If there's no problems, then
git merge will automatically create a commit for you. If not…
Nothing in life is free, and merging is no exception. If you've changed the same file in two or more divergent commits, then you might end up with a merge conflict. This is like other version control systems; you get
<<<<<<< ======= >>>>>>> markers in the code, like you'd see in other version control systems. However, you see these a lot less frequently in Git, because commits tend to be smaller, and in many cases, Git can replay re-orderings in your code.
To fix the merge conflict, edit the file, removing the merge conflict markers and resolving on a conflict-by-conflict basis, and
git add the file. You can use
git status to show you the list of files; those with merge conflicts will be shown separately, so you can step through these individually, fixing and
git adding them as you go.
Once you're done, running
git commit will commit all your merge changes. Unlike previous cases, where you have a single parent mentioned in the commit metadata at the top, this time you'll see two parents. These represent the previous version of this tree and the merged tree that you're bringing in.
There's more interesting things we can do with merged trees and merges, but we'll cover those in more detail another time.
Come back next week for another instalment in the Git Tip of the Week series.