Just about 6 months ago I took a grad class on Scalable Web Services, the main portion of the class was to 1) come up with a cool app idea, 2) develop it using Ruby on Rails, 3) make it scale. Very cool class, I enjoyed it quite a bit and it definitely sparked my interest in Rails and web performance both of which I have learned a lot more about since then. After the class there was some discussion as to opinions on the technologies used and one thing that most of us agreed with was that git was frustrating and difficult to use. The good news is that in the months since that experience I have used git quite a bit more and as a result I am really starting to like it. So much so that if I were to start a project today I would use git without a doubt.
Given that I pulled a full 180 on my opinion of git I took a step back and started to think about what it is that changed that caused my opinion of git to change. When I really thought about it the conclusion that I came to was that the main difference was my mental model of git. Let me explain...
I would think that I am probably similar to a lot of folks in that up to that point I had used SVN a decent amount, a few projects here and there along with some personal projects/data. As a result of this my mental model of version control was pretty simple, checkout a repo, 1) update, 2) make your changes, 3) commit, see (1. It's pretty simple and I suspect that most people who have used SVN have agree. Given this mental model, when I started using git I really thought it of as SVN with another step, you do steps 1-3 above and add 4) push to remote to the list of steps. Like I said, same as SVN just with an additional step. Anyone familiar with git will tell you that if you are using that model you are missing out on some of the best and most powerful features of git, namely branching. While SVN provides the ability to make branches I never really got the sense that they are a first-class object in the same way that they are in git. To get a sense for why branches are important here is my work flow for a standard task that I am working on:
1. create branch
2. write failing tests
3. write code to make tests pass
5. see 2 until task complete
6. merge branch back into master (smushing commits)
Anyone who is familiar with TDD will recognize steps 2 & 3 as the standard red-green loop but there are two other important things to note. If you are working in a tight red-green loop (which you should be) then step 4) is gonna result in a lot of commits which although the tests pass are probably not something you want commited into the record books forever and ever. In the standard SVN model you could either make all of these commits and spam the commit log with bunches of commits (and merging, ugh) or alternatively just not commit. The former is definitely undesirable and so is the ladder since its important to be able to go back to the last working state. The nice thing is that git allows you to get what you want in multiple commits which you can revert to while not spamming up the commit log. What you notice is that in step 6 when we merge back into the master branch we can either rebase (moves all the commits over) or my preference which is to merge without committing (smush commits). What this does is allow you to take all the commits you have made, smushes them together and then allows you to review what you have changed before you actually commit it into the master branch. For those of you wondering what I'm actually doing in step 6, assume you had your branch called "featureX" which had all the commits on it, you would checkout the master branch (git checkout master) and then do a merge using "git merge --no-ff --no-commit". Then you should have all the changes you made on the featureX branch staged ready to be committed, after you review it of course. It also helps that Macs have GitX which is one of the nicest diff tools I have seen to date.
One other awesome feature of Git that I use all the time (read: way too much) is stash. How many times have you made a change to something that you didn't want to commit but just wanted to keep around in case you needed it later? I seem to need this all the time, whether its simple config changes or some silly snippet I want to try out. If I want to keep that code around without having to commit it I can just do "git stash save some silly snippet" or more concisely "git stash" (the former adds a label to it). Then anytime something like that comes up you can just stash it away for later use.
So if you've been scared to make the switch from SVN to git, don't be scared, it wont bite.