CVS Errata
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.
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.
id="coding_cvs_branching">
% 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
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
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).
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).
<!-- -- end of script -- -->
.