In this post I present the development model that I’ve introduced for all of my projects (both at work and private) about a year ago, and which has turned out to be very successful. I’ve been meaning to write about it for a while now, but I’ve never really found the time to do so thoroughly, until now. I won’t talk about any of the projects’ details, merely about the branching strategy and release management. It focuses around Git as the tool for the versioning of all of our source code. Why git?For a thorough discussion on the pros and cons of Git compared to centralized source code control systems, see the web. There are plenty of flame wars going on there. As a developer, I prefer Git above all other tools around today. Git really changed the way developers think of merging and branching. From the classic CVS/Subversion world I came from, merging/branching has always been considered a bit scary (“beware of merge conflicts, they bite you!”) and something you only do every once in a while. But with Git, these actions are extremely cheap and simple, and they are considered one of the core parts of your daily workflow, really. For example, in CVS/Subversion books, branching and merging is first discussed in the later chapters (for advanced users), while in every Git book, it’s already covered in chapter 3 (basics). As a consequence of its simplicity and repetitive nature, branching and merging are no longer something to be afraid of. Version control tools are supposed to assist in branching/merging more than anything else. Enough about the tools, let’s head onto the development model. The model that I’m going to present here is essentially no more than a set of procedures that every team member has to follow in order to come to a managed software development process. Decentralized but centralizedThe repository setup that we use and that works well with this branching model,
is that with a central “truth” repo. Note that this repo is only considered
to be the central one (since Git is a DVCS, there is no such thing as a central
repo at a technical level). We will refer to this repo as Each developer pulls and pushes to origin. But besides the centralized
push-pull relationships, each developer may also pull changes from other peers
to form sub teams. For example, this might be useful to work together with two
or more developers on a big new feature, before pushing the work in progress to
Technically, this means nothing more than that Alice has defined a Git remote,
named The main branchesAt the core, the development model is greatly inspired by existing models out there. The central repo holds two main branches with an infinite lifetime:
The We consider We consider When the source code in the Therefore, each time when changes are merged back into Supporting branchesNext to the main branches The different types of branches we may use are:
Each of these branches have a specific purpose and are bound to strict rules as to which branches may be their originating branch and which branches must be their merge targets. We will walk through them in a minute. By no means are these branches “special” from a technical perspective. The branch types are categorized by how we use them. They are of course plain old Git branches. Feature branchesMay branch off from: Feature branches (or sometimes called topic branches) are used to develop new
features for the upcoming or a distant future release. When starting
development of a feature, the target release in which this feature will be
incorporated may well be unknown at that point. The essence of a feature branch
is that it exists as long as the feature is in development, but will eventually
be merged back into Feature branches typically exist in developer repos only, not in Creating a feature branchWhen starting work on a new feature, branch off from the
Incorporating a finished feature on developFinished features may be merged into the
The In the latter case, it is impossible to see from the Git history which of the
commit objects together have implemented a feature—you would have to manually
read all the log messages. Reverting a whole feature (i.e. a group of commits),
is a true headache in the latter situation, whereas it is easily done if the
Yes, it will create a few more (empty) commit objects, but the gain is much bigger that that cost. Unfortunately, I have not found a way to make Release branchesMay branch off from: Release branches support preparation of a new production release. They allow
for last-minute dotting of i’s and crossing t’s. Furthermore, they allow for
minor bug fixes and preparing meta-data for a release (version number, build
dates, etc.). By doing all of this work on a release branch, the The key moment to branch off a new release branch from It is exactly at the start of a release branch that the upcoming release gets
assigned a version number—not any earlier. Up until that moment, the Creating a release branchRelease branches are created from the
After creating a new branch and switching to it, we bump the version number.
Here, This new branch may exist there for a while, until the release may be rolled
out definitely. During that time, bug fixes may be applied in this branch
(rather than on the Finishing a release branchWhen the state of the release branch is ready to become a real release, some
actions need to be carried out. First, the release branch is merged into
The first two steps in Git:
The release is now done, and tagged for future reference. To keep the changes made in the release branch, we need to merge those back
into
This step may well lead to a merge conflict (probably even, since we have changed the version number). If so, fix it and commit. Now we are really done and the release branch may be removed, since we don’t need it anymore:
Hotfix branchesMay branch off from: Hotfix branches are very much like release branches in that they are also meant to prepare for a new production release, albeit unplanned. They arise from the necessity to act immediately upon an undesired state of a live production version. When a critical bug in a production version must be resolved immediately, a hotfix branch may be branched off from the corresponding tag on the master branch that marks the production version. The essence is that work of team members (on the Creating the hotfix branchHotfix branches are created from the
Don’t forget to bump the version number after branching off! Then, fix the bug and commit the fix in one or more separate commits.
Finishing a hotfix branch When finished, the bugfix needs to be merged back into First, update
Edit: You might as well want to use the Next, include the bugfix in
The one exception to the rule here is that, when a release branch currently
exists, the hotfix changes need to be merged into that release branch, instead
of Finally, remove the temporary branch:
SummaryWhile there is nothing really shocking new to this branching model, the “big picture” figure that this post began with has turned out to be tremendously useful in our projects. It forms an elegant mental model that is easy to comprehend and allows team members to develop a shared understanding of the branching and releasing processes. A high-quality PDF version of the figure is provided here. Go ahead and hang it on the wall for quick reference at any time. |
|