Continuous integration with multiple branch development in Subversion
As you note, one purpose of using a branch is to segregate specific code fluctuations from ticket-fixing and feature development away from the trunk. But once the feature or ticket is complete, you should merge it back. In Subversion, branches are better used to track sets of related features (like those for a release), not individual features. Otherwise you will quickly wind up with unmanageable numbers of branches.
Furthermore, why delay the integration at all? The longer you wait between releases, the higher the likelihood that your isolated change will conflict with another change made since then and/or produce further instability in your system once merged back.
My preferred strategy is to do something like this:
[begin work on 0.4 branch]
|
|
v
(*)---(*)-------(a)--(b)---(c)-- <-- Trunk is "unstable".
\ | | Contains all commits.
ver \ [merge from trunk] Developers commit to trunk.
<-- 0.3 \ v v
+---(a)--------(c)-- <-- Branch is "stable".
Contains selected commits from trunk.
Know beforehand what's going onto branch.
Now, once you're ready for release:
[trunk]
(*)---(*)---(*)----------------------------[development continues]--->
[0.4 branch] No further development on branch unless
(*)---(*)---(*)---[0.4-release] spot fixes are needed. Then re-tag (0.4.1)
^ and re-release.
|
|
[make tag on branch; release from stable branch,
not unstable trunk]
I know you asked about the best way to coerce your continuous integration system to do this. But I would respectfully suggest that given that Hudson is recognized as a relatively capable CI system, the fact that you're having a lot of trouble shoehorning your development model into it is a possible sign that it's not a process that lends itself well to CI in the first place.
Our typical practice is to have two base builds per project: one against trunk and one against the current release branch. This way you know that:
- Whatever is being updated is being integrated correctly (
trunk
) - Whatever your release target is, if you stopped working now you would still have a correct and working (just not fully featured) build.
Here is what we do (inspired from Version Control for Multiple Agile Teams by Henrik Kniberg):
- development is done in a development branch and features are pushed to trunk when "done done"
- trunk is the "done" branch
- at release time, we tag the trunk
- when a defect comes up, we create a release branch from the tag
- defects is patched in the release branch
- patch is merged from release branch to trunk immediately after releasing (to include it in future releases)
(source: infoq.com)
CI runs on all branches (development branches, trunk, release branches).
That sounds painful and overly complicated (from a branch/merge standpoint).
I would branch at release and have developers check in to the trunk. Anything that needs to go out as a hot fix could be merged with the release branch.