Current Articles | RSS Feed
One of the most compelling features of the Git version control system (VCS) is its ability to create highly usable and lightweight branches, and the ease of merging those branches later. Branching creates multiple "copies" of the same repository and allows you to separate out a set of changes while you experiment with them, or to create different versions of a project, without affecting the main tree. It's a feature that developers sometimes don't make the most of, simply because branching is so much more costly in other VCSes that they're not used to it, or they're not aware of the many branch commands and tricks available in Git. Here's a host of useful tips to get your Git branching and merging skills up to expert level in no time.
Since it's so quick and easy to branch in Git, and equally easy to merge back into the main tree, it's worth branching whenever you're working on something new. It's also good practice to use a branch when reviewing someone else's patches before merging them with your own master branch.
The basic branch commands are:
git branch
git branch BranchName
git branch -d BranchName
-D
git checkout BranchName
git checkout -b BranchName
So to create a new branch of your project and call it V2, use git branch V2. If you do that, then type git branch to list all existing branches, you'll see two branches, with a star by the one in use, which is still the "master" branch. To switch to the new branch, type git checkout V2. Make a change and commit it, then use git checkout master to switch back to the master, where your change will not be visible, because you made it to a different branch.
git branch V2
git checkout V2
git checkout master
To merge V2 back into the current working branch, use git merge V2. Assuming you made no changes in the two branches that would conflict, V2 and the master branch are now identical, and git branch shows that the other branch still exists, so you can return to it and do more work. You need to have committed all your changes (or use git stash, which we'll talk about in a moment) to merge. The merge will also fail if there are conflicts, in which case you can use git status to show the problem files, and edit them to resolve the conflict. Run git add file.txt for each edited file to add it to the scheduled commit, then git commit to finish the merge commit.
git merge V2
git stash
git status
git add file.txt
git commit
To show branches (and tags, which are used to mark important points in a project's history) and make this process easier to track, use
git log --oneline --decorate
Another useful command is git checkout -. A bit like cd -, this command returns to the previously checked-out branch. It's useful if you're frequently jumping between branches. You can also use git checkout @\{-2\} to check out the second-last branch previously checked out, and similarly with any number. (The - symbol is just an alias for @\{-1\}.)
git checkout -
cd -
git checkout @\{-2\}
-
@\{-1\}
With a straight merge, the history shows the changes tracked on the new branch, then one big merge on the master branch. This can make it harder to keep track of what happened with which commit. An alternative is to use git rebase V2, which will "squash" the changes back into the master branch. A graphical illustration of this is available over at the Git Community Book. Rebasing can make things a bit clearer and tidier in some situations, but may get a bit complicated if there are conflicting changes on master and V2. git rebase can also be used in interactive mode to rearrange commits in more complicated ways.
git rebase V2
git rebase
If you've made changes on the master, then realized that you'd rather be working on a branch, you can easily make the switch using git stash:
git stash save "work for bug 123"git checkout -b bug123branchgit stash pop
git stash save
save
git stash pop
git stash list
git stash pop stash@{1}
stash@{1}
You can also use this technique to switch changes between non-master branches. git stash is also useful if you want to merge changes from another branch without committing your current set of changes – for instance, if you get a patch from elsewhere but your own patch isn't ready to commit yet.
If you need to start work from an older state of code, you can create a branch that corresponds to a previous state of another branch. Use git reflog show master to show every commit that the master branch has pointed to, then git checkout -b branchX master@{7} to create a branchX that looks like master did after the master@{7} commit, without any of the commits since. Again, you can use any number here.
git reflog show master
git checkout -b branchX master@{7}
master@{7}
A neat Git option if you're using branches on a remote server is tracking, which sets up a link between a local and a remote branch. This means that your local copy of the remote branch will reflect changes in the remote branch when you use git pull (which does a fetch plus merge) and git push (to share your own changes). Tracking means that you don't need to specify the name of the remote branch when using these commands. Use
git pull
git push
git push -u origin master
to push the "master" branch to the "origin" remote branch and set up tracking. Similarly, use
git checkout -t origin/newthing
to create and check out a "newthing" local branch that tracks "origin/newthing." This allows you to make changes to a shared branch, then use git push to share your changes.
To list remote branches, use git branch -r. For a more nuanced list, you can use a command like
git branch -r
git branch -a --contains 50f3754
to filter the lists of branches, including remote branches (the -a flag) to those that include commit 5of3754 in their ancestors.
-a
Another great Git command is git cherry-pick, which enables you to choose certain commits from the commit list and bring only those across to another branch. First, you'll need to use git log on the branch with the changes (here, newbranch) to get the SHA of the commit(s) you want:
git cherry-pick
git log
$ git log --oneline --decorate4568f02 (HEAD, newbranch) editing file2feda6bd adding file3631dbb6 adding file249ba7da (master) Test 1
You now want to merge some of these newbranch commits back into master, but not all of them. Let's say that you want only the file2-related changes – that is, commits 631dbb6 and 4568f02. Switch back to master, then use git cherry-pick:
$ git checkout master$ git cherry-pick 631dbb6 4568f02[master d7654a0] adding file2 0 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 file2[master a9bf224] editing file2 1 files changed, 1 insertions(+), 0 deletions(-)$ git log --oneline --decoratea9bf224 (HEAD, master) editing file2d7654a0 adding file249ba7da Test 1
master now has those two changes, without the intermediate change to file3. You can now carry on happily on either branch.
Similarly, you can also check to see which changes from a branch are already present on the master:
$ git checkout newbranch; git cherry -v master- 631dbb65cb7c23aeed51abcbeda6ebf7dcde4de9 adding file2+ feda6bd20c9e7429166580f9b754ab164f72095a adding file3- 4568f028544c5f97b5aeed9baed0892505b032ec editing file2
git cherry master compares changes on the current branch to changes on the master, and marks those present on both (the file2 changes) with "-", and those present only on the current branch (the file3 change) with "+". The -v option shows the commit messages as well as the file IDs, which is useful if you don't have a list of SHA IDs in your head.
git cherry master
-v
Git is incredibly flexible and powerful. These are just a few of the insanely useful things you can do with branching. If you can think of something you might want to do, there's probably a Git command for it. (And if not, you can always consider submitting a patch.) Try out the commands here, and see how much more productive you become.
Allowed tags: <a> link, <b> bold, <i> italics