Why Git?

Some time back, I gave a presentation that included an overview of the Git version control system.  I still occasionally get asked why Git should be used instead of Subversion, as it seems harder at first.  Most developers don’t really understand Git until they have used it for awhile, and then they will have an “aha moment.”  There are 3 features of Git that are especially interesting to me:

  1. many repositories (vs. one large repository)
  2. distributed development
  3. cheap branches

Git submodules can now track branches

As of version 1.8.2, Git submodules can now track branches instead of specific commits.  This is good news as in many cases, this is exactly the behavior we want.  However, Git submodules are still not as flexible as Google repo, but since submodules are built into Git, the submodule command is a good solution in many cases.

The “git submodule update –remote” command is the key to tracking branches with submodules.   The following is from the Git man pages:

This option is only valid for the update command. Instead of using the superproject’s recorded SHA-1 to update the submodule, use the status of the submodule’s remote tracking branch. The remote used is branch’s remote (branch.<name>.remote), defaulting to origin. The remote branch used defaults to master, but the branch name may be overridden by setting the submodule.<name>.branch option in either .gitmodules or .git/config (with .git/config taking precedence).

This works for any of the supported update procedures (–checkout, –rebase, etc.). The only change is the source of the target SHA-1. For example, submodule update –remote –merge will merge upstream submodule changes into the submodules, while submodule update –merge will merge superproject gitlink changes into the submodules.

In order to ensure a current tracking branch state, update –remote fetches the submodule’s remote repository before calculating the SHA-1. If you don’t want to fetch, you should use submodule update –remote –no-fetch.

So, if you already have a Git submodule set up, its a simple matter to run git submodule update –remote to update the submodule to the latest master branch.  If you want a different branch, simple edit .gitconfig.

[submodule "meta-bec"]
   path = meta-bec
   url =
   branch = test

Now, if you run git submodule update –remote, Git will update the meta-bec submodule to the latest on the test branch.

This functionality is purely a convenience feature in the submodule update command.  In the actual repository, Git still stores submodules pointed to a particular commit.  The same thing could be accomplished with something like git foreach “git fetch && git checkout test”.  The branch option in .gitmodules functions more as documentation and convenience.  It is very handy to be able to look at .gitmodules and quickly determine that submodule X is tracking branch Y.  Normally, this would have to be documented elsewhere, or figured out in some other way.  Also, for build systems where you want the build to always track the production branches of various projects, update –remote gives you a convenient way to update the build tree.


Git and Distributed Development

This is part of an ongoing series of articles on the Git version control system.

The “many repository” paradigm has been partly driven by the distributed development paradigm.  Git solves the problem of multiple developers working in multiple repositories very well.  Because we want to use and customize projects like the Linux kernel, U-boot, and OpenEmbedded in our projects, then we naturally find ourself in the situation where we need to manage multiple repositories.  Yes, you can check the Linux kernel into your company Subversion repository, but you are much better off long term if you bite the bullet and implement your own Git infrastructure.

As we consider the product development process, we need to consider the life cycle of a product.  Most products live for at least several years, and will go through several software iterations.  If we can update the software components we use, then we can add value to the product in the form of new or updated drivers to support new peripherals, new libraries, performance improvements, etc.  But, we are dealing with millions of lines of source code, so we must have an efficient way to deal with software projects of this size.  The below Figure 2 illustrates how you might organize a typical project.  Notice we can pull updates from the U-boot and Kernel source trees at any time in the development process, and merge the changes with our own modifications.  We might have an outside team working an application, and we then easily synchronize the repositories when it makes sense.

There are many other design flows possible.  Once you have the ability to support multiple branches and repositories easily, it becomes trivial to implement a staging/testing repository for a QA processes, maintenance repositories for supporting old releases, etc.

Even at a personal developer level, Git’s distributed capabilities offers many advantages.  Each Git workspace is actually a full Git repository.  This means you can check changes in locally, re-organize your changes, be able to track changes when off-line, etc.  For this reason, many developers are now using git-svn when they need to work with Subversion repositories.  With git-svn, you have all the benefits of using git locally, and yet you can easily synchronize with Subversion repositories.  And this leads us to our next topic: cheap branches (coming soon).


Git and Why Multiple Repositories

This is part of an ongoing series of articles on the Git version control system.

This article discusses the trend in software configuration management toward multiple repositories, rather than one large repository.  In the past when many companies used Subversion or comparable systems, there was typically one huge company repository (I’ve seen them in the 10’s of GB in size) that held a hierarchical tree of all the company source code.  This worked fairly well, and is comfortable in that the organization is very similar to a file system directory structure.  However, this model is not very flexible in that it does not have a consistent way to re-use components between different projects.  Some people simply copy source code.  Some have a “common” project that is included in all their other projects.  Subversion externals can be used.  With Git, typically a separate repository is created for each software component.  There are perhaps several reasons for this, but one reason is that Git simply does not scale to huge multi-GByte repositories.  However, this turns out to be a blessing in disguise as I think it is a better model in many cases.  What we end up with is more of a catalog of software components rather than a rigid hierarchy.

There is much emphasis these days on modular, re-usable software components (Object Oriented Programming, plugins, etc.).  Why not keep things modular at the repository level?  Another example of this type of organization is the Internet itself.  It is not a hierarchy of information, but rather a flat system that is organized by hyperlinks.

One of the benefits of organizing your source code this way is that it encourages clean boundaries between software components.  Each software component needs to stand on its own without being propped up by header files located in an unrelated source tree 3 levels up in the directory hierarchy.  This type of organization forces us to make better use of standard build system practices.

How do you implement this type of repository infrastructure?  Build systems such as OpenEmbedded, Gentoo, and the Android build system manage this fairly well.  However, Git also includes a feature named “submodules” that provides a mechanism for one repository to reference source code from another.  What you end up using really depends on your needs, and what you are trying to accomplish.

A screencast is also available that covers this topic.


Git Overview Screencast

This screencast (use Firefox to view the screencast) provides an overview of the Git version control system.  There are 3 features of Git that are especially interesting:

  1. many repositories (vs. one large repository)
  2. distributed development
  3. cheap branches

The fundamental driver for better tools is increasing system complexity.  More and more we are required to manage and integrate more third party software, work in distributed teams, and more effectively re-use the software we do have.  Git is a tool that helps you accomplish these goals.


Git submodules: what to do when you commit to (no branch)

When using git submodules, eventually you’ll run into a situation where a workspace has checked out a submodule as (no branch), and you unknownly make modifications and commits to (no branch).  Now what?  It turns out Git has a very useful feature named reflog.  Reflog keeps a local time based log of all activity.  That means that as long as you do not garbage collect your workspace, you can go back to any point in time and get any commit that was made.  This is useful in a number of scenarios, but lets consider the case where we made two commits to a submodule in the (no branch) state.  We are then ready to push our changes to the upstream repo and we get:

cbrake@happy:/scratch/oe/oe-build-overo/openembedded.custom$ git push bec HEAD
error: unable to push to unqualified destination: HEAD
The destination refspec neither matches an existing ref on the remote nor
begins with refs/, and we are unable to guess a prefix based on the source ref.
error: failed to push some refs to ''

If we do a git log, we find we are on the infamous (no branch).

cbrake@happy:/scratch/oe/oe-build-overo/openembedded.custom$ git branch
* (no branch)

At this point we may wonder what to do.  How do we get these changes onto the master branch?  Using git reflog, we can view all commits and changes to our local repository based on time.

cbrake@happy:/scratch/oe/oe-build-overo/openembedded.custom$ git reflog
6d195b3 HEAD@{0}: commit: add recipe for qt-embedded image
4cf1bd6 HEAD@{1}: commit: add touchscreen utilities
bcc673c HEAD@{2}: checkout: moving from master to bcc673c9824e916a7ec6c04f60a17116af539423
56d9def HEAD@{3}: commit: add more features
5286f87 HEAD@{4}: commit: rename debug image
90896de HEAD@{5}: pull : Fast-forward
5cc3f3b HEAD@{6}: checkout: moving from 90896deb2a25f0d40b1e6305a0ad994f932f22d8 to master
90896de HEAD@{7}: checkout: moving from master to 90896deb2a25f0d40b1e6305a0ad994f932f22d8

Git will keep our keeps commits to (no branch) even though we might switch to another name branch.  And using git reflog, we can easily find these commits and merge them to the master branch.

cbrake@happy:/scratch/oe/oe-build-overo/openembedded.custom$ git checkout master
Previous HEAD position was 6d195b3... add recipe for qt-embedded image
Switched to branch 'master'
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
cbrake@happy:/scratch/oe/oe-build-overo/openembedded.custom$ git reflog
56d9def HEAD@{0}: checkout: moving from 6d195b3909553b04cba3d3ac182076a2c6b866b2 to master
6d195b3 HEAD@{1}: commit: add recipe for qt-embedded image
4cf1bd6 HEAD@{2}: commit: add touchscreen utilities
bcc673c HEAD@{3}: checkout: moving from master to bcc673c9824e916a7ec6c04f60a17116af539423
56d9def HEAD@{4}: commit: add more features
5286f87 HEAD@{5}: commit: rename debug image
90896de HEAD@{6}: pull : Fast-forward
5cc3f3b HEAD@{7}: checkout: moving from 90896deb2a25f0d40b1e6305a0ad994f932f22d8 to master
90896de HEAD@{8}: checkout: moving from master to 90896deb2a25f0d40b1e6305a0ad994f932f22d8
cbrake@happy:/scratch/oe/oe-build-overo/openembedded.custom$ git merge 6d195b3
Updating 56d9def..6d195b3
 recipes/images/       |   38 +++++++++++++++++++-----------
 recipes/images/ |    8 ++++++
 2 files changed, 32 insertions(+), 14 deletions(-)
 create mode 100644 recipes/images/

At this point, the changes have been merged to the master branch, and we can now push to our public repository:

cbrake@happy:/scratch/oe/oe-build-overo/openembedded.custom$ git push bec HEAD
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (10/10), 1.13 KiB, done.
Total 10 (delta 3), reused 0 (delta 0)
   bcc673c..6d195b3  HEAD -> master

Git reflog can also be used to restore commits that you decided at one point to throw away with “git reset –hard HEAD~2”, etc.  As long as you don’t garbage collect the repo, they are simply dangling state and always still exist.  This is just another example of the ways git can be very confusing, but also very powerful if you understand how it works.

This screencast covers the operations in this article.


Best practices for kernel development with OpenEmbedded

A common question is how do you do kernel development with OpenEmbedded?  Typically, OpenEmbedded builds a kernel by checking the source out of a git repository, or by applying patch files to a released version of the kernel.  See the many recipes for examples.  This works very well for a Linux distribution build system, but is less than ideal for ongoing kernel development where you will have many iterations over a period of time. The OE work directory is considered transient, and should not be used for any ongoing development.  Fortunately, the kernel build system is self contained, so it is a very simple matter to reference the toolchain built by OpenEmbedded and work outside the OpenEmbedded build system.

Use Git

Trust me on this one, just use it!  It will make your life easier.  There is a learning curve to any powerful tool.  Another way to state this is if a tool does not do much, then it would be easy to learn.  So expect to spend a little time learning to use git.  With modern Linux kernel development, much of your time is spent integrating work that others are doing.  For example, if you are using the OMAP3 CPU, you might want to start with linux-omap branch, integrate some patches from the OE beagleboard build, merge the OMAP PM tree, and then merge some bits from the Linux-wireless tree.  This is the way embedded Linux development is done today.  Git makes it possible to have many parallel developments going at their own pace, including your own.  Even in your own development, you will find significant advantages to being able to quickly create and merge branches, revise commits, etc.  There are several articles about git on this site.

Importing an OE kernel into git

If you are starting with an existing OE kernel tree, then you typically need to set up an equivalent tree in your local git workspace.  Typically you just look at the recipe to see how to manually reconstruct it.  For example, lets consider the SRC_URI from the palm-omap1 recipe:

SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.22.tar.bz2 \
 ;patch=1 \

To set this kernel up in git, we might do the following:

  1. git clone git://
  2. cd linux-2.6
  3. git checkout -b my_branch v2.6.22
  4. wget
  5. bzip2 -d patch-2.6.22-omap1.bz2
  6. git am patch-2.6.22-omap1

If the git am fails, then you might need to add a subject and author line to the patch in the following form and then retry git am.

From: Name <>
Subject: omap1 patch

Now when you do a git log, you will see the above patch applied.  git apply can also be used to apply patches, but I prefer git-am as it automatically handles new files and fills in the commit message and author.

Setting up the toolchain

Now that you have a kernel, you must set up a toolchain so you can build it.  I typically set up my kernel directory next to my OE build directory in my project space, so I can then source the following script to set up the toolchain:

CROSS_COMPILER_PATH=`cd ../oe/build/angstrom-2008.1/tmp/cross/armv7a/bin; pwd`
BUILD_ARCH=`uname -m`
OE_STAGING_PATH=`cd ../oe/build/angstrom-2008.1/tmp/staging/${BUILD_ARCH}-linux/usr/bin; pwd`
STAGING_KERNEL_DIR=`cd linux-2.6; pwd`
export ARCH=arm
export CROSS_COMPILE=arm-angstrom-linux-gnueabi-

Adjust to whatever you are building for.  Now you can simply type make.  The reason the OE_STAGING_PATH is added to the PATH in the above example is so that the uboot mkimage utility can be used directly from the OE build if your build target is make uImage.

Installing modules

Sometimes you need to re-install all modules on the target because you changed kernel version, etc.  Typically OE packages up all modules and adds the one you specify to the rootfs.  Because we are building the kernel outside the OE directory, OE can no longer do this.  However, its still very easy to install modules from your kernel development directory:

rm -rf modules_install; INSTALL_MOD_PATH=modules_install make modules_install
rsync -av modules_install/lib/modules/2.6.22 root@

The first command installs the modules to a temporary directory, and the second command rsync’s the modules to your target system.

Creating a kernel recipe with your changes

Once you get to the point where you want to create a recipe with your changes, you can easily export a patch, or series of patches using git diff or git format-patch.  Simply add the patch files to your kernel recipe SRC_URI.  You can also teach bitbake to fetch your kernel source directly from a git repository, but I’ve generally found the patch mechanism to be adequate and easier in most cases.  As an example, you can create one large patch with all your changes that can be applied on the 2.6.22 released kernel:

git diff HEAD..v2.6.22 > my_kernel_changes.patch

Other ways …

This is just one flow and there are many variations.  There is also a new mechanism in OpenEmbedded called srctree that allows you to use OpenEmbedded in an external source tree.  srctree has the potential to further streamline this type of development.

As with any task, you want to use the tools that make sense for the task.  OpenEmbedded makes sense for building Linux distributions, but it is not a kernel development tool.  Git and the kernel build system make sense for kernel development.


How to capture source changes to an OpenEmbedded package

One task that is a often confusing to new OpenEmbedded users is how to capture changes to the source code for a package/recipe.  First, lets review the progression in tools use to capture source code changes.

Progression of tools
Figure 1: Progression of tools

In days of yore, developers often used gnu diff to capture modifications to a source tree.  The typical practice was to create two source trees: a pristine, and a dirty tree.  Modifications were made in the dirty tree, and periodically gnu diff was run between the two trees to capture the changes.  Then came quilt which allowed you to capture changes without a pristine tree — kind of a cheap version control system.  The typical flow was:

  • cd <source dir>
  • quilt new my_changes.patch
  • quilt add file1.c
  • edit file1.c
  • quilt refresh (now my_changes.patch records the edits to file1.c)
  • debug
  • edit file2.c
  • (oops forget to quilt add file2.c — now what ….)
  • restore file2.c from pristine source
  • quilt add file2.c
  • edit file2.c
  • quilt refresh
  • (now my_changes.patch records edits to file1.c and file2.c)

As you can see, things are much better than plain diff, but you still have to keep track of the files you edit.  With git, we can do essentially the same things, only git keeps track of the files you edit, plus it is easier to organize patch files.  The flow with git is something like this:

  • cd <source dir>
  • git init
  • git add *
  • git commit (now the entire source tree is recorded by git)
  • edit file1.c
  • edit file2.c ….
  • git status (shows you files that were modified)
  • git add file1.c file2.c
  • git commit
  • git log (shows you changes you have made)
  • git format-patch HEAD~1 (outputs the patch created by the last commit)

Once your source code is in git, then you can do all kinds of fancy things like merging, re-ordering, and re-naming patch files with the git-rebase –interactive command.

One of the uses of this technique is when you need to record a small change to a package source in a build system such as OpenEmbedded, and apply that change for subsequent builds.  In this case you might do something like the following:

  • bitbake -c devshell <recipe_to_patch>
  • in devshell capture changes in git as shown above to create my_changes.patch
  • cp my_changes.patch <oe_tree>/recipes/<recipe_to_change>/files/
  • edit <oe_tree>/recipes/<recipe_to_change>/<recipe_to_change>.bb
    • tell bitbake to apply the patch when building the recipe: SRC_URI += “file://my_changes.patch;patch=1”
    • increment the PR variable so that bitbake knows to rebuild the recipe.

Figure 2 illustrates the above steps.

Flow to capture packages source changes in OpenEmbedded
Figure 2: Flow to capture package source changes in OpenEmbedded

While the above steps might seem overly complex, you must consider what you are trying to do.  Building a Linux distribution is not a simple task.  We are dealing with large amounts of source code from many different projects.  Putting all this source code in one tree is not an option, because then we would be defeating the very reasons open source is attractive in the first place: flexibility, largly decoupled projects, advanced technology, fast bug fixes, many options to choose from, developer support, etc. Each open source project must remain a self contained project that is largly decoupled from other projects so it can develop at its own pace.  It is for these reasons that open source technologies are used to give products a competitive edge.  So, like any complex process or task, there must be some understanding of how it works, an appreciation for what it can do for you, and an investment in tools and techniques required to be effective.


Howto use a Git topic branch to maintain a patchset, and isolate problems

The more I use Git, the more I am really impressed with some of its capabilities.  What is Git?  Git is a very advanced distributed source code control system that can do some very neat things.  For the average developer using open source software, we are mainly concerned about maintaining patch sets (often called a topic branch).  Git includes a rebase capability that is very useful for a number of different operations related to maintaining a branch of code including moving a branch forward, moving a branch around on an upstream branch to look for breakage, and merging changesets to create patch files.  This article provides a brief overview of some of these operations and several tips.

When in doubt, make a branch

The most important concept to understand when working with Git is to get used to creating and destroying branches.  This is different than most other SCMs where all branches are stored on a central repository, and you don’t want to clutter the branch namespace.  With Git, get used to branching without even thinking about it.  For example, the following are the branches in a Git repository I use to maintain patch sets for the Compulab cm-x270:

 git branch
* test

Most of the names are self explanatory.   The cmx270 branch is where I track the latest kernel version.  The svs branch is for a customer platform based off the Compulab cm-x270.  To view the changes on any particular branch:

git-log cmx270_2.6.22

an Git will start showing you a list of changes on that branch.  This works even if you are not working on that branch, so it is very handy for seeing what changes are in other branches.  With Git is also very easy to move changes between branches using git-cherry-pick.  For example, if we are working on the cmx270 branch, and we want to pull the 3rd changeset from the HEAD of the cmx270_2.6.22 branch into the cmx270 branch, we would do something like:

git-cherry-pick  cmx270_2.6.22~2

Git is really good at maintaining patch sets

Many developers use quilt to maintain patch sets.  Once you understand how Git works, Git is even better at maintaining patch sets.  Although there are some add-on tools available for maintaining patch files in a git repository like Patchy GIT and Stacked GIT, I’ve found that core Git works well enough.  Actually the Patchy GIT maintainer has quit working on Patchy GIT because core GIT now meets his needs.  The fundamentals are you simply export each Git commit as a patch using the git-format-patch command as shown below:

git-format-patch -o tmp/ master
Produces the following files (all of the commits since the branch has left the master):

Pretty slick!  HEAD~8 means to back up 8 revisions from the current HEAD and then start outputting changes as patch files.  The name of the patch file is the commit comment.

Moving your patch set forward in time

If you are maintaining a patch set for the Linux kernel, you might want to move your patchset up to the latest version for testing, and also maintain patchsets for each stable version of the kernel.  Lets say we already have a patch set for the 2.6.20 version.  The first thing we need to do is create a branch.  In this example, I am maintaining a patch set for the Compulab cm-x270 computer module.

git-branch cmx270_2.6.20 v2.6.20  (branch name, tag name in repository)
git-checkout cmx270_2.6.20

At this point, I would manually apply each patch, and then commit each patch as its own changeset.  Now, I want to move the changeset forward to kernel version 2.6.21.  The easiest way to do this is create a new branch, and simply rebase your patchset to the new kernel version.  Make sure you create a new branch first, or your existing branch will be moved!

git-checkout -b cmx270_2.6.21 cmx270_2.6.20
git-rebase --onto v2.6.21 master (tag point to relocate branch, upstream branch)

The upstream branch is required to be specified so that Git knows where our branch changes start — specifically where the cmx270_2.6.21 branch diverges from the master branch.

There may be a few things to clean up along the way if changes don’t apply cleanly.  The most critical thing to know is that if you want to skip a patch, you must run “git-reset –hard” before running “git-rebase –skip”.  This is often handy if you have an especially troublesome patch that you don’t want to apply now.  You can skip it and then cherry-pick it later.  Otherwise the process is fairly straightforward.  After you are finished, you can now export a set of patch files that can be applied to the 2.6.21 kernel.

Bisecting the master branch to determine when things broke

You may run into a situation where something broke on the main branch, and you don’t know where.  Most of the time, you would just run git-bisect to do a binary search to find where things broke.  This does not work so well if the platform you are testing is not supported in the main branch — the changes in your topic branch are required to make the system run.  Once again, git-rebase to the rescue.  The first thing we must do is find the mid-point between the known good and bad points.

git-rev-list --bisect v2.6.20 v2.6.21

Now, rebase out changes to the above rev and test.

git rebase --onto 13f7e5acc8b329080672c13f05f252ace5b79825 master

The build failed, so now we have a new “bad” point and can continue our binary search.

git-rev-list --bisect v2.6.20 13f7e5acc8b329080672c13f05f252ace5b79825

If you can build working kernels from the main tree, then you can directly use git-bisect — another good reason to get your changes into the mainstream source, but this is not always possible.

Another option for doing this type of binary search is to use git-bisect, and then cherry pick your changes at each bisect point.  It may also be possible to use git-merge, but I have not figured out how yet.


That is it for now.  Git is very useful for maintaining multiple patch sets for different versions of an open source project, and is just another thing that makes working with open source projects a real pleasure.  Future articles will cover how to further manipulate patches such as how to combine two patch files.


Benefits of OpenEmbedded switching to Git

Recently the OpenEmbedded project has switched to the Git version control system.  This is good news for many reasons.  The obvious reasons are Git is faster than Monotone, handles branching better, has lots of nice features, larger user base, etc.  Monotone has served us well, but as new tools become available, it is time to change.  For those of us helping customers use OE for embedded projects, Git will make using OE much easier.  Companies want to be able to track OE with minimal effort and typically maintain a few minor tweaks to OE.  As most Embedded Linux projects now implement Git infrastructure for kernel development, the OE source tree can be maintained using the same infrastructure.  Branching is very natural in Git, so it is fairly easy to create a OE “topic branch” and periodically merge with upstream changes as needed.  The ability for easy repo hosting and branching allows OE users to lock down a version of OE for periods of project development, and still maintain a connection to the upstream OE repository for easily updating to new versions, or cherrypicking changes.  So a big thank you to all who helped make this change happen.


more fun with git branches

One thing you learn after using git for awhile is you get used to trying random things, and it will often just work.  For example, if I want to know the differences between Linus’s kernel tree, and the Wolfson dev branch for a particular directory:

cbrake@happy:/build/linux-2.6$ git diff --stat origin/master..wolfson/dev sound/soc/codecs
 sound/soc/codecs/Kconfig       |  125 +++
 sound/soc/codecs/Makefile      |   34 +
 sound/soc/codecs/ad1939.c      |  690 +++++++++++++++
 sound/soc/codecs/ad1939.h      |   70 ++
 sound/soc/codecs/ad1980.c      |  309 +++++++
 sound/soc/codecs/ad1980.h      |   23 +
 sound/soc/codecs/cs4251x.c     |  771 +++++++++++++++++

Another way to get similar information is:

git log origin/master..wolfson/dev sound/soc/codecs

If I’m working on a topic branch, and I want to see a summary of all the changes in my Topic branch:

git log --stat origin/master..origin/my_topic_branch > my_topic_branch_changelog.txt

One of the neat things about git branches is you don’t have to be on a branch to interact with it.  You can diff, log, and checkout from branches other than the one you are currently in, and it is all very fast.  For instance, if I want to grab the latest copy of a file in the Wolfson dev branch, I can do something like:

git log checkout wolfson/dev sound/soc/codecs/wm9713.c

Not that this is a very good idea, but just to illustrate a point.  Git branches are amazing and make development work so much less tedious.