My Thoughts on Git

Posted by Aaron West at 9:59 AM in Git, Source Control

As a programmer I've used all kinds of source control management solutions. From Microsoft Visual Sourcesafe, to CVS, to Subversion (SVN). I even wrote a 60 page whitepaper detailing the use of Apache, ColdFusion, and Subversion in a development environment. And I've been known to blog about source control from time to time.

Recently I began reviewing the Git source control system for the startup I'm working with. It was a good opportunity to investigate solutions beyond Subversion since there wasn't any previous repositories or "code baggage" to worry about. I began my review by talking with Russ Johnson, the first person to ever recommend Git to me. Russ highly recommends Git and was more than willing to answer my dumb questions and discuss what he saw as advantages when using Git over Subversion. For my thoughts on Git continue reading after the break. Or, if you want to go ahead and download my Git cheat sheet click, here.

The distributed nature of Git

One of Russ' favorite features of Git was its distributed nature. Unlike with Subversion you don't have to create and manage a master Subversion server. You can certainly set up your Git solution to work with a master server - Git calls this the origin server - but it's not a requirement. I highly underestimated the coolness of this feature. Having installed Git on three MacBook Pro's and one Ubuntu (Karmic) origin server, I've had the chance to test the "remoteness" of Git. Wow, it is one of my favorite features too. I like how I can fetch updates from the origin server and merge those updates into my local repository on my own time. Imagine you're at the office on Friday afternoon and your awesome boss says it's time to go home. You - being an equally awesome employee - are going to do some programming over the weekend. So you fetch the latest updates from your team via the origin server and you promptly pack up your stuff and go home. On Saturday you open your laptop and merge the origin changes into your local system and you start programming. Too cool. Other situations where Git's distributed nature come in handy include travel. Most airlines don't have Wi-Fi on their planes yet so you're about as "offine" as it gets when you're in the air. With Git, that doesn't matter. You can still get your work done. You write your code or work on documents, whatever you are tracking with Git. You even commit all your changes to your local Git repository so you can synch them later with the remote Git server.

Branching and merging is easier

With Git, branching and merging is easier. Creating branches and merging code is a matter of running a few simple commands. Sure Subversion has similar commands but Subversion branches feel more weighty. I always felt beholden to Subversion branches and never quite enjoyed the process of merging changes from one branch to another. Git makes this super easy. In fact, Git users are encouraged to create branches for the smallest changes! Another interesting bit about Git is everything is considered a branch. There's no exact concept of a trunk in Git like there is in Subversion. Git does have the master branch which serves the same general purpose, but it doesn't feel the same as a Subversion trunk. Switching between branches is also very easy and an inexpensive task. All in all Git branching and merging feels more polished.

Other cool features

Three other cool features are patching (hunking), stashing, and bisecting. Patching allows you to choose which specific changes in a single file you want to commit. As I code I often find small things I want to fix that aren't related to the larger task I'm taking care of. Wouldn't it be nice if you could commit only related changes together? It makes reviewing code problems and communicating with other developers (through the Git log) much more productive. In Git, the git add -p command allows you to do this. To accomplish the same thing in Subversion you had to remove unrelated changes and perform your commit. Then you had to read the changes you removed and perform another commit. It was tedious.

Stashing is another great git feature. Pretend you're working on a branch called "version2." You're well into the development of version 2 and you have a bunch of changes that haven't been committed to branch version2. Meanwhile a user finds a bug with version 1 and you need to fix it fast. In the Subversion world many developers would simply check their version 2 work into the version2 branch and switch to the trunk to start fixing the bug in version 1. But doing this sucks as you've munged your commit tree with a commit that wasn't really intended. Subversion does have a few things to address this scenario but they feel like workarounds. In Git, you can simply stash all the uncommitted work you've done and save it for later. When you run the git stash save command Git saves your uncommitted work and reverts the branch you're in to the latest commit. Now that you have a clean version2 branch you can safely switch to your master branch and knock out that bug. When you're done fixing the bug you can switch back to the version2 branch and issue the git stash pop command to replay all your changes. You're now right back where you started. Sweet!

The last cool feature I want to discuss is bisecting. This is way cool. In Git, bisecting a repository allows you to find where a bad commit was made. Say you have a bug in your code but you're not sure where the bug originated and which commit introduced it. You can begin a bisecting session and Git will progressively check out bisected commits from your repository. Your working copy changes with the bisection allowing you to test your site or app. If you find the bug present in the commit Git checked out you go back to Git and answer "yes," this commit has my bug. If it doesn't you answer no. Git will bisect your commit tree again and you go and check your site or app again. After a few iterations of this process Git will tell you which commit it believes introduced your bug. You then switch to that commit and begin to audit your code. I've only used this feature in simulations but I can see how it could be a lifesaver.

It's all gravy now

I've become a big fan of Git. It simply fits into my workflow like a nice pair of shoes. But Git is still new to me and I have a lot more to learn. Likewise I forget some commands from time to time so I created a Git cheat sheet to use as a reference. If you'd like to download my Git cheat sheet (PDF) - which includes most of the common, everyday commands, just click here. I also recommend checking out this other cheat sheet that's more fancy than mine. Finally, if you have questions about how Git works or you'd like to let others know why you like Git feel free to post a comment. I'd love to hear from you.

Aaron West's Gravatar
About this post:

This entry was posted by Aaron West on March 31, 2010 at 9:59 AM. It was filed in the following categories: Git, Source Control. It has been viewed 24888 times and has 16 comments.

1 related blog entries

16 Responses to My Thoughts on Git

  1. Excellent post. Interestingly, I had been thinking about this just this morning. I had heard great things about Git but hadn't had an opportunity to try it (who has the time). Our development environment is always in motion, with many side projects and branches requiring merges and upkeep. Git sounds like a good fit, if I can only find the time to try it and implement it!

  2. I've used Subversion and Perforce in the past, but your post on Git has convinced me that I ought to try it-- not the least for the ability to commit to a local repository while I'm offline.

  3. @Mike - I typically don't have good timing but in this case it appears I do. Definitely check out Git. Another benefit of its distributed nature is testing Git on your local machine without having a remote Git server. If you like what you see on your local machine you can ramp up from there and start working with remote origins.

    @Tom - Thanks so much for commenting. I didn't necessarily set out to convince folks to switch to Git but its great to know my post will encourage you to dig deeper.

  4. Nathan Kondra

    My firm is just starting to look into a proper source control system, would you recommend looking into GIT for a first time implementation or should we start somewhere else to get the proper methodologies and systems in place first? (Dumb question?)

  5. @Aaron Have you done much topic branching? I am using git at work but we haven't ventured into create branches for working on x.

  6. Also people should checkout if they want to explore using git.

  7. @Nathan, you should check out Git. There's no reason to start anywhere else. Git is built on the same source control management principles other tools are, it's just a matter of how each tool implements the principles. If you have the time to look into other tools like Subversion (SVN), I recommend doing that as well. It'll help you pick what's right for you. But if you only have time to pick one and get started, my personal opinion would be to go with Git.

  8. @Mike - Well, like I said in the post I'm still new to Git. So I wouldn't say I've done a ton of anything in Git. But I'm using it heavily on a daily basis. I'm not sure what you mean by "topic branching," but I pretty much branch for any sort of change. If I'm making a single code change and a single commit, I'll do that on the master branch, but pretty much everything else is a separate branch.

  9. 'Topic branches' I see as two themes. One: You can start a branch to work on a topic, and merge updates of the mainlines (or if things are getting rough, from other topics), and when the feature is done, merge it back into master. One of the cool things (some disagree on this) is that, if nothing else is happening on trunk at that time, the topic branch will simply become the master branch ('fast forward').

    Second part is that you can rebase your topic branch to the current state of the mainline. This is like merging the advancement of the mainline into each of the commits on your branch, so it now looks like you did all work on that base. When done you can merge those commits on the master branch, and it still looks like linear development. And when you grokked that, you can look at interactive rebase which allows you to edit the history of your branch (like reorder commits). This allows to clean up, and make review of your changes easier.

    The rebasing is particularly useful for open source projects where a contributor can work out a nontrivial feature and then rebase onto the current master, and mail in the commits as patches, which can be put into the maintainer's repo while keeping the original authorship information.

  10. Convinced me. Going to check out GIT this weekend. Your post makes it sound dreamy.

  11. @Andreas - all the topic branching and merging/rebasing with the master (or mainline as you called it) are normal workflows in any source control management system. Each team will choose to do things slightly different regarding merging branches into the master branch or periodically merging the master (rebasing) with a regular branch.

    @John Allen - that's great to hear John. I've got a few links stored in Delicious that might help you get started this weekend. So check this out if you want:

  12. For your cheat sheet:

    git config [--global] branch.master.remote origin

    git config [--global] branch.master.merge refs/heads/master

    If you find that most of your repos are simple pulls from the origin, and you're never really pulling from any other tracking branch, these two settings save you some typing. You can now just "git pull" and "git push" instead of "git pull origin", or the more verbose "git pull origin master".

    If you cloned the repo instead of creating it, these two settings should already be in that repo's config. But these settings provide benefit if you created the repo and then later added the origin remote (because you started the project, but then moved the hosting elsewhere).

  13. @Rick - Our general workflow is for a developer to start the repo locally first. Then we log into the remote Ubuntu server and create a new repo directory, switch to the directory, and run the command git init --bare. The developer then goes back to the local repo and does a git remote add origin URL:directory-to-repo. Then, a git push remote origin master. Finally, the developer deletes their local repo and then clones the remote.

    In my experience this sets up the local repository so we can do simply git pushes and git pulls (or fetches) with or without branch names. If we leave branch names off the commands all branches are pushed, pulled, or fetched. Or, if we type the branch name into the command only one branch is affected.

  14. Mike T.

    "...Imagine you're at the office on Friday afternoon and your awesome boss says it's time to go home. You - being an equally awesome employee - are going to do some programming over the weekend..."

    Nice one: "awesome" boss (kiss up?), "awesome" employee (has no life outside work?)

    The moral of this story: work SMARTER - not HARDER, there is life out there...

    Nice write up on GIT. Thank you, Aaron.

  15. @Aaron Please name any other VCS that offers rebasing branches, except for git's two sidekicks. (Perhaps my description of rebasing was a bit misleading.)

  16. Best thing is it doesn't leave millions of .svn folders scattered through everything it touches!