Tuesday, October 8, 2013

Git: Checkout multiple branches at the same time

With git, source code lives in a single working directory. When we switch from one branch to another, git rearranges our files for us. Usually this keeps things simple, but now and then I wish for two copies of the code.

Do you ever want to run a big fat suite of tests in one branch while working on code in another branch? I do! This requires two different versions of the code on the filesystem at the same time.

Before you go making another copy of the whole repository, consider this solution: write a version of the for-testing branch to a temporary place outside of your working directory. Run the tests over there, leaving the real local repository available for work as usual.

1. Create a temporary directory. Maybe /Users/me/somewhere
2. Go to your git repository, to the project root directory. Now run this command:

git archive branchypoo | tar -xC /Users/me/somewhere

git archive takes the whole source tree from branchypoo, tars it up, and writes the result to stdout.
tar -x extracts the files from stdin
-C <dir> means "do the extraction over in this directory."

Now you're clear to run tests over in /Users/me/somewhere, and your local repository is ready for real work.

Thanks to JørgenE for this trick!

--------

The original post used three steps:

0. Commit or stash any changes you have lying around. (important!)

1. Create a temporary directory. Maybe /Users/me/some/where/else

2. Go to your git repository, to the project root directory. Now run this crazy command, and don't forget the dot at the end:

git --work-tree=/Users/me/some/where/else checkout branch-of-interest -- .

Here,
--work-tree=/Users/me/some/where/else tells git to act like your working directory is in some other location.
checkout writes the specified version of the specified files into your (modified) working directory. Note that checkout behaves differently when given a filepath; if you leave that out, checkout will change your current branch and not give you all the files.
branch-of-interest is a branch name, or any commit identifier.
-- says "I'm done naming commits, here come some paths to files"
. chooses the current directory, including all subdirectories and so on.

The whole command means "Write all the files, as they currently exist on branch-of-interest, into this directory over here (and my staging area)." The staging-area bit is unfortunate. If there's a way to tell checkout to skip that, I'd like to know it.

3. Fix your staging area. git status will tell you that you have a bunch of changes to be committed, and a bunch of other changes. Tell it to forget about that stuff in the staging area.

git reset

Now you're clear to run tests over in /Users/me/some/where/else, and your local repository is ready for real work.