CVS Branch and Merge Example

One of the most powerful features of CVS is the ability to maintain multiple development branches simultaneously.  This complete example demonstrates how it's done.

Let's say you have a repository containing a single file mypoem.txt that is ready to release.  Let's look at the file  contents:

% cat mypoem.txt
Little Miss Muffet
sat on a tuffet
eat her curds and whey.

When you officially "release" the file to your customers you create a tag in the repository, a symbolic reminder of the state of the repository at a certain point in time.  The -b option says we want to associate the tag with a  new branch of the repository.  Maintenance will occur in the branch while new development will continue on the trunk.  Let's name our tag release-1 using the cvs tag command.  The command is issued from within your working directory, but it really affects the repository.

% cvs tag -b release-1 

Note: the working directory still contains the trunk (not the branch we just created)  -- any changes committed here will go into the trunk of the repository.  So now our developers can happily begin working on release 2 which will contain the "new features and enhancements" -- the next stanza of the poem.

% cat mypoem.txt
Little Miss Muffet
sat on a tuffet
eat her curds and whey.

Along came a strider
and sat up beside her.

The developers add their new work to the trunk. 

% cvs update mypoem.txt
% cvs commit mypoem.txt
Note the new work hasn't been tested yet;  it has defects.  It's still under development.

Parallel development

After a few days of new development the customer reports a defect in Release 1. The word "eat" is supposed to be "eating." They want a patch in a hurry.  It's not a good idea to make the fixes in the trunk because it has unstable new development in it. The fixes can't get released until the new development stabilizes. The customer would have to wait until the next major release before they can get the fixes. They can't wait that long.  So we have to make the fixes in the maintenance branch.

To begin work on the maintenance branch, we need to get the source from the branch by referring to the tag.
% cvs update -r release-1 mypoem.txt
U mypoem.txt

% cat mypoem.txt
Little Miss Muffet
sat on a tuffet
eat her curds and whey.
Notice that we are back to the Release 1 version of the file.

The diagram shows the situation with new versions of development going in the main trunk and bug fixes going in the maintenance branch.  (Specific reversion numbers are arbitrary.)
             
+---------+
Release-1 -> __! 1.2.2.1 ! <- the maintenance branch
/ +---------+
/
/
+-----+/ +-----+ +-----+
! 1.0 !---! 1.1 !----! 1.2 ! <- The main trunk
+-----+ +-----+ +-----+
Now we repair the Release 1 file only in the maintenance branch.
% cat mypoem.txt
Little Miss Muffet
sat on a tuffet
eating her curds and whey.
% cvs update mypoem.txt
% cvs commit mypoem.txt
As soon as the fixes are in we can create a Release 1.1 patch that we can give the customer immediately.  The patch will be made from the maintenance branch and will contain none of the new development.  In the meantime new development can occur on our main development line (trunk) without any interference from bugfixes.

When we are done with bug fixing we can return to working on Release 2.  We update our working directory using the -A flag to revert our working directory to the files on the trunk.
% cvs update -A mypoem.txt
And we see that the file in our working directory is the one in the trunk.
% cat mypoem.txt
Little Miss Muffet
sat on a tuffet
eat her curds and whey.

Along came a strider
and sat up beside her.
We continue development in the trunk getting the next stanza of the poem in order. It would be silly to do bugfixes two times, one time in the branch and one time in the trunk. So we ignore those little Release 1 defects and concentrate on putting in the new features. 
% cat mypoem.txt
Little Miss Muffet
sat on a tuffet
eat her curds and whey.

Along came a spider
and sat down beside her.
% cvs update mypoem.txt
% cvs commit mypoem.txt

Merging maintenance changes into the trunk

Now the new features are finished but the trunk doesn't have the bug fixes we made to create the patch release. At this point we want to combine the bug fixes from the maintenance branch with the new development.  This is called merging.  We use the -j flag to merge the branched sources into the sources in our working directory.

% cvs update -j release-1

There could quite possibly be conflicts if any of the bug fixes overlap the new development.  Watch for the message "conflicts during merge" in the CVS output to indicate conflict.    For example, after merging the Release 1 poem our source file has conflicts shown where the <<<<<<< symbols appear.

% cat mypoem.txt
Little Miss Muffet
sat on a tuffet
<<<<<<< mypoem.txt
eat her curds and whey.

Along came a spider
and sat down beside her.
=======
eating her curds and whey.
>>>>>>> 1.3.2.1

Any conflicts must be manually resolved by editting the file and running the tests again.  When all is done we can commit the changes.

% cvs update mypoem.txt
% cvs commit mypoem.txt
Here is the view after the merge.  It shows new development in parallel with bugfixes and then merging the sources back into the trunk.  At this point, the patches are also in our main development line.
             
+---------+
Release-1 -> __! 1.2.2.1 !____ <- the maintenance branch
/ +---------+ \
/ \
/ \
+-----+/ +-----+ +-----+ \+-----+
! 1.0 !---! 1.1 !----! 1.2 !----! 2.0 ! <- The main trunk
+-----+ +-----+ +-----+ +-----+

Lastly we tag and branch the next release.

% cvs tag -b release-2 

Finding out where you are

It's easy to forget if our working directory has source from the trunk or a branch.  Use cvs status frequently to check where you are.
% cvs status mypoem.txt
===================================================================
File: mypoem.txt Status: Up-to-date

Working revision: 1.3.2.1 Sat Apr 10 18:33:47 2004
Repository revision: 1.3.2.1 cvsroot/mypoem.txt,v
Sticky Tag: release-1 (branch: 1.3.2)
Sticky Date: (none)
Sticky Options: (none)
Notice the Sticky Tag: field shows if we are working on the branch.  If we are in the trunk it will say (none).

Summary: Checking out sources

To checkout the trunk:
% cvs checkout . 

To check out the branch

% cvs checkout -r release-1 .

The -r flag will set a "sticky tag" in the CVS/Tag file, so that most subsequent CVS commands (including commit and update) operate on the branch instead of on the trunk, without your having to specify the branch name. For example, if you have used checkout -r to get the latest copies of the maintenance files, and then changed mypoem.txt, you can commit changes by the usual method:

% cvs update mypoem.txt
% cvs commit

Note: It's recommended to follow the general strategy shown here of doing bugfixes on the fix branch and merging them to the main branch. Doing it the other way around can easily lead to the wrong changes being merged onto the fix branch (e.g. code changes related to new features that aren't implemented on the fix branch).


Here is the official CVS documentation on Branching and Merging.
Comments? Email the .

This document was modified from the original at http://www.phenix.bnl.gov/~pope/cvs-branch.html