In my working life I have lead teams developing some big projects and products. In all these development we had to control versions, releases, some QA dedicated version and so on.
Of course we used SCM for these stuffs, and I focused ,as usual for me, on open source solutions. So I started to use cvs a lot of year ago, and more recently (exactly since Jan 2004) subversion. As in all big projects I needed to track code for different development line and product releases, and use of branches have been quite natural (especially in svn world) achieving these goals.
In my career I have been lucky working with great developers, but we have needed to find an agreement about the use of branches (and tags) in our SCM, because they can easily become a nightmare if leaved out of control and convention. Moreover, it’s a matter of fact that SCM is easy to understand and use, but a correct use of branches and tags may be something which most developers don’t understand and use them without worries.
Some months ago I wrote 2 documents to cover 2 different needs: the first is an introduction to branching and tagging in general and in our environment for new hired people, the second is a checklist of operation needed in branching a project, respecting our “svn pattern”. Both documents was in italian language, but they need a review with minor adaptation of our newest best practice in these days, and so I decided to translate and generalize it to make it public. Originally our document describe svn pattern strictly coupled to jira, fisheye and hudson practice we are using, I tried to decouple them, to make this post easy to read for atlassian/hudson non-believer. If someone is interested I can describe in another post how we are using these tools in our environment. Just let me know by comments or by email.
Ok, stop describing background and go with documents: The first is this post itself, the second is attached here as pdf and txt, since I think it’s more useful in that format used as checklist.
Let’s start describing what is a branch and a tag in svn: branches and tags in subversion just a copy of sources. Branches is for convention a copy where teams do parallel development, tags is for convention a read only copy (and only for convention in svn), to store a copy of code in a particular stage of development (they are for convention not modifiable). How do you create a branch or a tag? Of course, being them just copies, with copy (or move) command. Let’s see the command (here and in the rest of post, I make an example of the most common use, at least for us, of the command…take a look to the “svn help <command>” and the good svn online manual for more detail
svn copy SRC DEST
Our normal convention used in svn is to create 2 directories on repository called branches and tags where you have to copy them. So for example, we can create a branch called “Experiment1″ with this command:
svn copy $REPO_PATH/trunk $REPO_PATH/branches/Experiment1
But how are we using branches? Well we are using 2 different kind of branching, with totally different goals: STABLE branches, used for stable product release maintenance, and personal branches, used for experimental code and/or for agile parallel development.
In this figure I sketched our repository layout. As you can see we have a current development line on trunk and we branch starting from there for e different reasons:
1) starting a new parallel personal development (red), which will be described in detail later in this post.
2) Create a branch for a stable release (green), which need maintenance. When the version reach the end of supported life we migrate the branch on a tag to keep “legacy” code with it’s story somewhere. This approach permit us to always have clean code for any version maintained, where investigate for bugs and stack trace reported by customers.
But where have we to fix a bug? In all branches having the same code? Of course here subversion merging help us a lot.
When we find a bug we correct it on trunk whenever it is possible and then merge the correction (backport in our slang) on all active branches. When the bugs can’t be corrected on trunk (i.e because the buggy code don’t exist in trunk anymore) we fix it on the newest branch available and then backport it on older code.
What we are doing here is in fact a single commit management and merging. It give us an high level of confidence on what we are doing on stable releases, especially used together with Jira, unit tests and hudson.
We always have a person or a team responsible of maintenance of a version, and it’s up to her (or them) to decide what bugs need backporst and it’s up to her (or them) to manage this merge:
cd branch_workingCopy_dirsvn merge –dry-run -r N-1:N $REPO/branches/$BRANCH_NAMEsvn merge -r N-1:N $REPO/branches/$BRANCH_NAME
svn commit -m”JARA-YYY: back porting of commit N, fixing JIRA-XXX”
We use svn also to make parallel development on the same project. Similar approach is described in detail in a lot of article of agile development (1,2). I don’t know, and I don’t care, if we are totally agile compliant, but we use the same idea to create personal branches, and commit on them all works around big Jira tasks.
Our idea is that our trunk have to be clean, buildable and with all test passing (and hudson verify this condition at every commit). Ideally trunk would be releasable at any moment, or at least can receive patch to be backported. But, of course, there are some bug issues and development to be done that can’t be developed in few hours by a single developer on her laptop (buildable, tests passing, feature complete and stable). But of course we needs to have new code somewhere making possible to an heterogeneous team to work on and to be available to all team members at any time. So the solution is to have parallel “personal” branches.
Personal branches is totally different from release ones described above, since they don’t die at some stage, but they have to be merged on trunk, applying to trunk all changes developed and tested in branch. But sometimes this development phase may take some time (in particular for experimental code development), and trunk may change a lot during this time. For this reason merging back a branch on a trunk which have changed a lot could easily become pain, with a lot of difficult to resolve conflict.
Our solution have been to keep personal branches updated, merging frequently from trunk and resolving day by day conflicts, and a final “publish” action reporting all changed code in branch into trunk. Few conflict at a time, and on a well known code base is much more easy to understand and to resolve.
But isn’t difficult to keep track of which revision is already merged on branch? (IOW a lot of merge, means keeping track of merge operations?).
It was true (even not impossible, we always kept track of them with a text file) before subversion 1.4, which includes a command “svnmerge to keep track of merges (it’s in fact a contribution, downloadable also for early versions as svnmerge.py)
What does it for you? It keep track of merges from trunk to branch (using properties on branch) and make much more easy merging in this direction. Theoretically it would also help you also merging back in other direction, but we don’t use it for this operation, since “traditional” merge does a good job in this final “pubblication” operation. There are commands we use to make these operations, refer to previous figure to better uinderstand what we are doing:
CREATE A PERSONAL BRANCH
svn copy $REPO/trunk $REPO/branches/$BRANCH_NAME -m”created branch”
svn co $REPO/branches/$BRANCH_NAME branch_workingCopy_dir
svn commit -m”svnmerge initialized”
MERGING FROM TRUNK TO PERSONAL BRANCH (FREQUENTELLY)
svn commit -m”merged trunk to branch”
MERGING INTO TRUNK FROM PERSONAL BRANCH
svn commit -m”last merge of trunk to branch”
remove property used to track merges
svn commit -m”svnmerge uninit”
(get the revison number….suppose 346)
svn merge –dry-run $REPO/trunk@346 $REPO/branches/$BRANCH_NAME@346
svn merge $REPO/trunk@346 $REPO/branches/$BRANCH_NAME@346
svn commit -m”reported changes from $BRANCH_NAME trunk”
svn delete $REPO/branches/$BRANCH_NAME@346
That’s all. Just one more advice………
Last, but not least, merging works on difference, so don’t forget to ensure that difference are real changes on code, and not simple formatting!!!
Use of some tools to format code automatically at some time is more than useful: eclipse at save file defining a code style formatter profile, jalopy used in ant or in maven or what else you can figure out, but please don’t leave it to developers, use an automatic tool! Of course it’s just my humble opinion, but to many times I have been in pain merging code (and mainly understanding difference on fisheye) with stupid formatting problems!