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

Reply via email to