A common quote I hear quit often regarding Git is:
“It looks cool but it seems too complicated and Subversion meets my needs just fine.”
On the surface this is a valid statement on both fronts; Git is more complicated, and Subversion is a fine tool and will meet most of your needs.
However in my experience most tools that have tremendous power also have a bit of a learning curve, and rarely has the time spent learning the tool not paid for itself many times over.
In order to provided the most bang for the buck in getting started with Git, we are going to take a look at what I consider one of it’s most powerful and useful features: Local Branches
On a recent project our team encountered a situation in where we had to do a complete redesign of the look and feel of the web application right in the middle of major development. We wanted to take a divide-and-conquer approach and have a small group work on the redesign while the rest of the team continue to work on feature implementations. Using a traditional version control system (e.g.SVN, CVS, etc), you would probably create a branch in your repository for the redesign, continue feature development on the trunk, and then spend many hours and maybe days in merge hell.
However on this project we chose to use Git as our version control system and here is how we utilized the power of local branches to solve our redesign issue.
The first step was to create a new local branch for the look-and-feel changes:
Note: The text between the square brackets “” indicate the branch we are currently working in.
>[master]$ git branch new_laf >[master]$ git checkout new_laf >[new_laf]$
These command creates the new_laf branch and checks it out for us to make our changes.
The “checkout” command simply means that we are switching to a new local branch, not pulling down from the central repository as you might think
You can shorten this process to a on line invocation:
>$ git checkout -b new_laf
With the addition of the “-b” flag, checkout will create the branch if it doesn’t already exist.
Keep in mind that this branch is only local to the developers machine and is not on the central repository.
Think of it as a new local workspace that you are free to do anything you want without harming the master branch.
At this point the developer has two branches: new_laf and master.
Now that the developer, after issuing this command, in the “new_laf” branch can now proceed to make the needed design changes.
Meanwhile the other developers can continue doing regular development against the “master” branch, and continuing to commit to the central repository.
While doing the design changes in the “new_laf” branch, the developer doing the redesign follows a pretty standard git work flow:
...work on file(s) >[new-laf]$ git commit -a -m "new laf changes"
This equates to making the changes to the files and then committing them to the “new_laf” branch.
In a normal Git work flow you world follow up the commit with a push to the central repository, but we are not going to do that in this case.
Note: For this project the look-and-feel work was done with one developer. If we had more working on it we would have created a remote branch on our repository so we could then do a push.
Now here is where Git really shined for us:
Through out the day the developer doing the design work would do the following:
>[new_laf]$ git checkout master //1 >[master]$ git pull //2 >[master]$ git checkout new_laf //3 >[new_laf]$ git merge master //4 ...continue to work in new_laf branch
Here is what’s going on with these commands:
Step 1: Switch to the local copy of “master” branch. This is the branch that the rest of the team is developing against.
Step 2: Pull down all the changes from the central repository to your local repository.
Step 3: Checkout the “new_laf” branch.
Step 4: Merge the updates from the “master” branch back into the “new_laf” branch.
Really all we are doing here is keeping the development branch updated with the what the rest of the team is doing. However, taking this small step a couple times a day throughout the redesign sprint paid for itself a thousand time over when it cam to merge the design changes back into the “master” branch.
All we had to do to accomplish that was issue the following commands (after doing the previous steps one last time):
>[new_laf]$ git checkout master //1 >[master]$ git merge new_laf //2 >[master]$ git push //3
Step 1: Checkout the “master” branch.
Step 2: Merge all the changes from the “new_laf” branch to the “master” branch.
Step 3: Push all the changes up to the central repository.
For our team this look-and-feel change took a little over a week, we changed around 150 gsp pages and templates in Grails project, and throughout the process we had a handful of merge issue that each took a couple minutes to resolve. As stated earlier, doing this type of long running change with parallel development is possible in Subversion or CVS, but you will normally be doing a single big-bang merge in the end, and then you have to travel to the 7th ring of merge-hell.
Git has a lot of tools in it’s shed but in my opinion, none is more powerful and useful than local developer branches.