This was a response to an email from a friend about why he should switch to Git from SVN. Perhaps you’ll find it useful as well. :)
Three things come to mind right away:
1) Distributed instead of centralized.
With SVN, there is one “true” copy of the code at all times. Everyone checks out the code from this one true copy and checks the code back in when you’re done. There is nothing wrong with this, and in fact, this is also what you will also usually have with Git. The big difference is that you don’t *HAVE* to have it with Git if you don’t want to.
For example, with OnceOvers, Dan and I work off of the development installation that is up on Heroku. This acts as the “true” copy right now, meaning that Dan and I both check out a complete version from the one on the server and push code back into it. This works great for now and is essentially the same as what you would have with SVN.
However, as soon as we are ready to take the site live, I will be pushing the site to a production installation hosted somewhere else. This is now the production instance of our website, instead of the development one. The map looks something like this:
So that means that Dan and I can keep pushing and pulling from the development server without worry. When we want to take whatever we have live, we just push the current state to the production server. Additionally, I can also keep another copy of it on GitHub (or any git server) with only a single command.
Also, because of the distributed architecture, I can keep pieces of the code in all sorts of places. So, if I wanted to OpenSource a portion of the application but keep another portion of it closed, that’s super easy.
The distributed piece is also interesting because you don’t need an internet connection to check in some changes. The advantage to checking in changes is that you can see where they were and roll back to that point in the future. (Kind of a like a checkpoint in Mario) If you are working in SVN, you need to commit the changes to the server before breaking the whole page again or else you might lose your progress. With git, you can check in to the repository on your laptop as many times as you want without needing to connect to the internet, so you can wipe the whole file and be right back where you were within seconds. When you do get to an internet connection, you can just “git push” it to the remote server.
Speaking of the remote server, because both copies of the repository are full copies, you don’t have to worry about losing the repository if the hard drive on the server crashes. You just specify a new remote repo and you’re back up and running in minutes with all of the history still intact. I’ve done this a number of times just when moving to a new hosting provider.
2) Super easy to create branches of your work to try new things
Now, all this is fine and dandy and not really that compelling since most of it can be done with SVN. However, where it gets really powerful is branching and merging.
As a programmer, even when I’m working with HTML / CSS, I might try some crazy new idea that involves editing a bunch of files even though I’m not sure it’s going to work. With SVN, because I’m working from a server copy, I would either have to checkout the entire repo into another folder and do all my craziness or I would have to start working on it and change all of my files knowing that it would be a pain in the but to go back to the beginning. With SVN this also restricts me from making little changes while in the middle of a big change.
Lets say you’re working on a site for a client and you want to move the entire HTML / CSS structure over to HTML5 / Eric Meyer Reset from XHTML 4.1 / YUI Reset. You start work and get about 3/4 done when the client calls and says there is a typo on the live site that needs to be fixed immediately. How do you go back to the live copy and make the little change when you’re in the middle of a big change? With SVN, you would checkout a new version of the repo, make the change and check it back in. Here are three ways to do it with Git, in order of complexity.
- “git stash” will literally stash all changes that you have made and revert the files back to their last commit state, as if you had just downloaded them. You can make the little change, check it in and push it to the server. When you’re ready to get back to work, you just type “git stash apply” and you are back to where you were. With SVN you can do this with a diff / patch workflow, but it’s a bit more cumbersome than just typing stash. (Thanks @snookca for the reminder)
- “git add -p filewithtypo.html” will send you into interactive / partial mode. If there are multiple edits in a file but you just want to check in one of them, this will allow you to pick which one and check it in, instead of checking in the whole file. It’s awesome. :)
- Branching. With SVN, branching was kind of a pain in the ass. A bunch of smart people who use SVN seem to think it was easy enough, but I never really used it because it always broke or screwed something up. I guess I just wasn’t smart enough. Anyway, branching and merging in git is really straight forward. Lets say you want to work on the HTML5 rewrite. You can run “git branch html5” and it will create a new space for you to work. To work in that space, just type “git checkout html5” and you are now in the html5 branch. You start making your changes and then get the call from the client about the typo. All you do is type “git checkout master” and you’re back in the clean branch pre-changes. You fix the typo, check it in, push it to the server and then type “git checkout html5” to get back to work. When you are done making all of the HTML5 changes, you can run “git checkout master” to get back to the clean branch and then type “git merge html5” to apply all the changes that you made. It’s that easy. This also lets you work on totally separate features at the same time without any conflicts since you can have as many branches as you want. No pushing or pulling necessary to switch. :)
3) Cleaner and smaller folder sizes
With SVN, you get all those annoying .svn folders created in your folder structure. If one of the folders get messed up, you’re in trouble. The folders hold the “clean” copy of every file so that you can revert back to it whenever you want. If you have made changes and then somehow screw up the .svn folder, you have to do a diff of your changes, svn up and the patch the files back together. Kind of a pain in the butt. That also means that every file you checkout is duplicated.
With Git, there is only one folder created at the root of your project directory called “.git” and it holds all of the information about the repo. Instead of storing full copies of all the files, it stores diffs from one version to another. So, it only stores records of the changes. This lets you literally “play back” the changes that you’ve made over a number of commits. This is why it is so much easier to branch and merge files. Since diff files can be fuzzy, you don’t have to compare exact copies every times which results in less collisions. Also, the diffs are generally much smaller in size than an actual file, so you save space.
That about sums it up. As for why you would use this instead of SVN, that choice is totally up to you and SVN is still a darn good version control system.
Versions is probably the best OSX visual version control application out there, although Tower is making progress on providing a Git one ( http://www.git-tower.com/ ) and Gitbox is already fairly mature ( http://www.gitboxapp.com/ ). As for Kaleidoscope, it works with Git as well and ties into Gitbox already.
Personally, I like using the command line. I just find it so easy that I haven’t found a reason not to use it yet.
I hope that answers some of your questions. :)