I’ve been using git for version control for a few years now and at several different companies (although I still use subversion for personal projects). I think I finally get it and understand the common workflow with it so I wanted to write it down. This largely involves the rebase command (a command which I was initially weary of), hence the post title.
For starters, unlike many people these days, I don’t think git is absolutely superior to other version control systems. As I said, I still use subversion for my personal stuff. So let’s start with some negatives.
First, git doesn’t store directories or history about them. So if you you want an empty directory, you need to add a hidden file (.gitignore is a good choice) to the “empty” directory. As someone who moved from cvs to subversion, this feels like a step backwards. At least in cvs, I understand that it is an unavoidable artifact of using rcs files, but with git I really don’t understand the decision.
Second, git is built very much around the idea of a single project per repository. There are situations where this makes a lot of sense, but there are use cases where I would prefer to have multiple things in one repository and just check out the parts you want.
Finally, I miss cvs tags in files (which subversion supports just fine).
I’m in a good mood so I won’t count the documentation against git.
One of the things people always say is that git is great because it is decentralized and I’m not sure I buy that. In every place I’ve worked (and every major project using it that I’ve looked at), there is always one master, central, blessed repository that everyone else clones and pushes to (sometimes indirectly if only limited people have access). I think this makes sense, but it makes the decentralized talk seem a little funny.
The other part of it being decentralized is that you have a complete backup of the repo with every clone. Except that git clone only clones some things. You can fix this (more or less) with:
$ git fetch --all --tags
Now that I’m done with all that preliminary stuff, I can talk about what I actually wanted to: git rebase (and the associated workflow).
Initially, git rebase seemed like a bad thing to me. It allows you to rewrite the history in a repository, frequently to squish commits together. To someone raised on more traditional version control, that seems like a terrible idea. After all, history is sacred. If I didn’t care about history, why would I bother using version control?
It is only recently that I’ve come to understand the cases where this is okay (and actually very beneficial). I still think that one should never mess with the main history (and if there is a change that someone else has used the branch you are changing, then it is a terrible idea to change history). But what git rebase does it let one work on a local branch and make as many little commits as possible. Then, when the feature or bugfix is done, one can rebase against the main branch and make all that work into a single commit. In source code with multiple commiters working on different features, this is really the only way to end up with history that makes any sense. For a good counter-eample, one need only look at the git history for android.
That’s really all I wanted to point out, that when used with branches, git rebase can be a good way to maintain a legible history on the main branch for code (but I still don’t think it should ever be used on the main branch). This also lets you avoid all sorts of ugly merge commits that don’t really say anything.