I've searched the web for best practices around software release process with Git. It seems that the practices vary a lot. One of the best articles I have come across is this one (I had to Flattr that post):
http://nvie.com/posts/a-successful-git-branching-model/ The process there is quite complex and sophisticated. I imagine it is required and very beneficial for large-scale projects. In our case (just several developers) I believe we are better off with much simpler process. But it's still a great source of inspiration. In the release process there are some artifacts we recently talked about and which could be important for us: == A single stable branch == This is the branch containing only stable (production-ready) code. In AutoQA we call in "stable". In the aforementioned article they call it "master". There's a small difference in the process of adding hotfixes. We used the same branch for pushing hotfixes and then tagged a new hotfix release at some point. They have a separate "hotfix" branch for those purposes and merge in once they want to create a hotfix release. But otherwise it's the same. The benefits of having such a branch: * People following this branch don't have to track release announcements or periodically list available tags. Simple "git pull" will always give them latest stable code. The drawbacks of having such a branch: * It is not trivial to maintain this branch with full commit history. My simple approach for AutoQA 0.5.0 was to create a patch from stable to v0.5.0 and apply it on stable [1]. But that does not keep history. The history is retained if you run "git log v0.5.0", but not if you run "git log stable". Tim tried to fix that problem by merging v0.5.0 and stable [2]. But that has its own drawbacks. You need to solve merge conflicts by hand and even if you do that, it is still possible that stable differs from v0.5.0 (some code changes didn't need to be detected as conflicts). With Tim's approach you still need to diff your branches afterwards and resolve any remaining differences by my diff-n-patch approach. It looks better in the end, but it also requires more work. Interestingly the guy in that article didn't mention this problem at all (although they must have encountered this problem too). All in all, stable branch has its uses and its challenges. We don't even need it, there are other approaches (described below). It's just a matter what we desire. Do you think there are people out there following just our stable branch? Do we care if they have to switch tags from time to time? == Release branches == The principle is simple. With each tagged (minor) release we fork off a separate branch out of it. For example for 0.5.0 release we create "0.5-stable" branch. For 0.6.0 release we create "0.6-stable" branch. The rest of the process is the same as we have used till now. All hotfix commits are pushed to the relevant release branch and then tagged in some point of time. It then looks like this: -o--o--o--o--o--o-- (master) ^\ | o--o--o- (0.5-stable) | ^ | tag:0.5.1 tag:0.5.0 In this picture we have tagged 0.5.0 on master, then forked off 0.5-stable branch, pushed three more commits into that branch and then tagged 0.5.1 release. Advantages: * There are no issues with merging. We can work on more releases at once (not relevant to our project imho). Disadvantages: * Having the latest stable code requires checking the tags periodically and switching to the latest one. Maybe you wonder - will we have lots and lots of these branches, eventually exploding the output of "git branch -r"? No. The nice thing here is that we need to create this release branch only when it's needed (we discover a bug that needs a hotfix). Also we can delete these branches once we are sure we won't work on this branch anymore (i.e. once 0.6.0 is out we can delete 0.5-stable in our case). Because don't forget, both branches and tags are the same in Git -- pointers. Branches are just moving pointers, while tag pointers stay put. Once we know there will be no more development, the tag is all we need to keep, the branch can be removed. I consider this approach quite nice. In the past I was too concentrated on having a stable branch where you can always "git pull" the latest stable code. But maybe we don't need it after all and release branches would satisfy our needs instead? (We can of course have both stable branch and release branches, but I consider that unnecessarily complicated.) == Branches used for tagging == There was a discussion lately on which branch we should tag our releases. I would like to clarify that. Due to the Git's nature this question does not really apply. In the above text I already described that branches and tags are almost the same -- pointers. The branch determines just the top commit and all other commits are linked through ancestor relationship. So you can't say "this commit is on branch X", you can just say "this commit is accessible from branches X, Y and Z". There is no ownership relationship. That means it doesn't really matter which branch the particular commit used to belong, it only matters if that is the top of the tree we want to archive by tagging. The important questions are then: * Does it contain the code we want? * Does it refer the commit tree log we want? It means that these approaches are equivalent: (master)$ git tag 0.5.0 and (master)$ git checkout -b 0.5-stable (0.5-stable)$ git tag 0.5.0 Both contain the same code and both refer to the same tree. However, if we do big-patch approach for our stable branch (like I did a few days ago), those approaches are not interchangeable: tag:0.4.0 tag:0.5.0 v v --o--o--o--o--o--o--o-- (master) \ \ o---o----------o--- (stable) ^ tag:0.4.1 If I do "git log 0.5.0", I get a fine-grained list of commit history. Now imagine I would tag a different commit: tag:0.4.0 v --o--o--o--o--o--o--o-- (master) \ \ o---o----------o--- (stable) ^ ^ tag:0.4.1 tag:0.5.0 Now I get the same code for "git checkout 0.5.0", but I get only a fraction of commit history for "git log 0.5.0". Not that it doesn't serve the purpose. But the first approach is just better, because it keeps also the history. == Conclusion == I have described the current approaches. I may have misunderstood something, I'll welcome corrections. As for our project, I'm open to any suggestions. I think that our current practice serves us well. I'm fine with the big-patch approach for stable branch, because the commit history is retained for master branch and for all the tags. I'm fine with Tim's merging approach too. OTOH I'm also fine with switching to using release branches. They are pretty. And it may be simpler for understanding that our current approach. I don't think it would be viable for us to do both, release branches and stable branch. KISS. Once we decide what we want, I'll document the process on our wiki. Keep the comments coming :) Kamil [1] http://piratepad.net/M9RUj1qAe2 [2] https://fedorahosted.org/pipermail/autoqa-devel/2011-June/002475.html _______________________________________________ autoqa-devel mailing list [email protected] https://fedorahosted.org/mailman/listinfo/autoqa-devel
