I’ve been thinking a little bit about branching strategy lately as I work on some personal website development. Although I’m on a team of one, this is a chance for me to learn Git and practice one of the better features of a distributed version control system: easy branching.
For me, branches are “heavyweight” items, mostly because my career has been spent working in centralized version control systems like Team Foundation Server and SVN. In these systems, branches are full copies of items, so creating a branch of a TFS project or SVN folder can be expensive for larger projects. For this reason, branching tends to be fairly rare. With a centralized VCS in place, you might have branches for different environments (e.g., development, QA, and production) or maybe just one master branch per project. Branching for hotfixes or specific tasks feels like overkill and sucks up a lot of developer time.
But there’s a great reason to branch for hotfixes and specific tasks. Imagine that you’re working on Project X and you have Issues 1, 2, and 3 to deal with. You start working on Issue 1 and get blocked. Without separate branches per issue, you can work on Issue 2 while you’re blocked, but when you check in code, you have to be careful that you don’t check in any of that Issue 1 code, just in case Issue 1 falls off the sprint or the impediment turns out to be insurmountable.
In contrast, if you have the ability to create separate branches per issue, you can start by creating a branch for Issue 1. Then, when you get blocked on Issue 1, go back to your main branch and create a separate branch for Issue 2. After you’re done working on Issue 2, you can merge back to your main branch and start on Issue 3. In the meantime, Issue 1 frees up again, so you can switch back to Issue 1, complete the work there, and then merge that work up to the main branch. A good VCS will figure out that your new code from Issue 2 should supersede your equivalent old code in Issue 1 and vice versa, leaving merge conflicts only when the Issue 2 and Issue 1 branches both modified the same part of the same file. Once you get that merge complete, you can switch back to the Issue 3 branch and keep working.
But while you’re working on Issue 3, a production problem appears and you need to get on it right away. Issues 1 and 2 aren’t ready to go out into production just yet, so you want a hotfix area which mimics production.
I’m still in the initial steps of development right now, but I’ve had a chance to reflect somewhat on branching strategy, and to build up some branching discipline, I’ve decided to work from the following basic plan:
- Master branch. This is my production branch and exists on my source control server as well as on my development machine. I will use this branch to deploy code to my production web server, database server, etc.
- Dev branch. This is my development branch and exists on my source control server as well as on my development machine. I will use this branch to deploy code to my development web server, database server, etc.
- Issue## branch. For each development task, I create an Issue[ticket number] branch and begin development on that issue. This allows me to work on multiple issues as the mood strikes. This branch will only exist on my development machine; once I have finished development on an issue, I can merge the code into the Dev branch and delete the issue branch.
- Hotfix branch. This branch exists on my source control server as well as my development machine. This branch can deploy code to a hotfix web server, database server, etc., but for now, my plan is to do that testing on my development machine and then roll the hotfix into the Master branch and let it deploy to production.
- Bug## branch. If I get a high-severity bug, I will create a branch called Bug[ticket number] and use this branch for bugfix work. This keeps each bugfix branch separate from other bugfixes and any development code. This branch will only exist on my development machine; once I am satisfied that the bug is fixed, I’ll merge to Hotfix and remove this local branch.
- Dev branch. This is my development branch and exists on my source control server as well as on my development machine. I will use this branch to deploy code to my development web server, database server, etc.
If I end up working on a team with multiple developers, I might need to turn Issue and Bug branches into something I do on the server as well as my development machine. For now, however, I want to keep the server simple and focus on my core needs: master, dev, and hotfix.
One nice thing I will say about Git is that git checkout works great for this. Git does branching well on a few counts. First, branches are very lightweight, meaning that I can create (and delete) a new local branch in almost no time. Unlike SVN or TFS, I don’t need to wait for all of my files to copy to a different folder every time I have a new task. Along these same lines, I don’t have N copies of each file on my hard disk, thus saving a lot of disk space. Finally, because Git branches are “in place” changes, I have one Visual Studio solution in one location and I can jump between branches without having to close the current solution and open another one somewhere else.
I won’t pretend that the strategy I’m using for branching is the best branching strategy ever—I’m not even sure it will work out for me in the long run, although I am optimistic. What I will say, however, is that my opinion of Git has increased since I’ve used it a bit more, and this nice branching model is a big part of that opinion shift.