For many uses of CVS, one doesn't need to worry
too much about revision numbers; CVS assigns
numbers such as 1.1
, 1.2
, and so on, and
that is all one needs to know. However, some people
prefer to have more knowledge and control concerning
how CVS assigns revision numbers.
If one wants to keep track of a set of revisions involving more than one file, such as which revisions went into a particular release, one uses a tag, which is a symbolic revision which can be assigned to a numeric revision in each file.
Another useful feature, especially when maintaining several releases of a software product at once, is the ability to make branches on the revision tree.
Each version of a file has a unique revision number. Revision numbers look like `1.1', `1.2', `1.3.2.2' or even `1.3.2.2.4.5'. A revision number always has an even number of period-separated decimal integers. By default revision 1.1 is the first revision of a file. Each successive revision is given a new number by increasing the rightmost number by one. The following figure displays a few revisions, with newer revisions to the right.
+-----+ +-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! +-----+ +-----+ +-----+ +-----+ +-----+
CVS is not limited to linear development. The revision tree can be split into branches, where each branch is a self-maintained line of development. Changes made on one branch can easily be moved back to the main trunk.
Each branch has a branch number, consisting of an odd number of period-separated decimal integers. The branch number is created by appending an integer to the revision number where the corresponding branch forked off. Having branch numbers allows more than one branch to be forked off from a certain revision.
All revisions on a branch have revision numbers formed by appending an ordinal number to the branch number. The following figure illustrates branching with an example.
+-------------+ Branch 1.2.2.3.2 -> ! 1.2.2.3.2.1 ! / +-------------+ / / +---------+ +---------+ +---------+ Branch 1.2.2 -> _! 1.2.2.1 !----! 1.2.2.2 !----! 1.2.2.3 ! / +---------+ +---------+ +---------+ / / +-----+ +-----+ +-----+ +-----+ +-----+ ! 1.1 !----! 1.2 !----! 1.3 !----! 1.4 !----! 1.5 ! <- The main trunk +-----+ +-----+ +-----+ +-----+ +-----+ ! ! ! +---------+ +---------+ +---------+ Branch 1.2.4 -> +---! 1.2.4.1 !----! 1.2.4.2 !----! 1.2.4.3 ! +---------+ +---------+ +---------+
The exact details of how the branch number is constructed is not something you normally need to be concerned about, but here is how it works: When CVS creates a branch number it picks the first unused even integer, starting with 2. So when you want to create a branch from revision 6.4 it will be numbered 6.4.2. All branch numbers ending in a zero (such as 6.4.0) are used internally by CVS (see section 6.8 Magic branch numbers). The branch 1.1.1 has a special meaning. See section 12 Tracking third-party sources.
A file can have several versions, as described above. Likewise, a software product can have several versions. A software product is often given a version number such as `4.1.1'.
Versions in the first sense are called revisions in this document, and versions in the second sense are called releases. To avoid confusion, the word version is almost never used in this document.
By default, CVS will assign numeric revisions by
leaving the first number the same and incrementing the
second number. For example, 1.1
, 1.2
,
1.3
, etc.
When adding a new file, the second number will always
be one and the first number will equal the highest
first number of any file in that directory. For
example, the current directory contains files whose
highest numbered revisions are 1.7
, 3.1
,
and 4.12
, then an added file will be given the
numeric revision 4.1
.
Normally there is no reason to care
about the revision numbers--it is easier to treat them
as internal numbers that CVS maintains, and tags
provide a better way to distinguish between things like
release 1 versus release 2 of your product
(see section 6.4 Tags--Symbolic revisions). However, if you want to set the
numeric revisions, the `-r' option to cvs
commit
can do that. The `-r' option implies the
`-f' option, in the sense that it causes the
files to be committed even if they are not modified.
For example, to bring all your files up to revision 3.0 (including those that haven't changed), you might invoke:
$ cvs commit -r 3.0
Note that the number you specify with `-r' must be larger than any existing revision number. That is, if revision 3.0 exists, you cannot `cvs commit -r 1.3'. If you want to maintain several releases in parallel, you need to use a branch (see section 6 Revisions and branches).
The revision numbers live a life of their own. They need not have anything at all to do with the release numbers of your software product. Depending on how you use CVS the revision numbers might change several times between two releases. As an example, some of the source files that make up RCS 5.6 have the following revision numbers:
ci.c 5.21 co.c 5.9 ident.c 5.3 rcs.c 5.12 rcsbase.h 5.11 rcsdiff.c 5.10 rcsedit.c 5.11 rcsfcmp.c 5.9 rcsgen.c 5.10 rcslex.c 5.11 rcsmap.c 5.2 rcsutil.c 5.10
You can use the tag
command to give a symbolic name to a
certain revision of a file. You can use the `-v' flag to the
status
command to see all tags that a file has, and
which revision numbers they represent. Tag names must
start with an uppercase or lowercase letter and can
contain uppercase and lowercase letters, digits,
`-', and `_'. The two tag names BASE
and HEAD
are reserved for use by CVS. It
is expected that future names which are special to
CVS will be specially named, for example by
starting with `.', rather than being named analogously to
BASE
and HEAD
, to avoid conflicts with
actual tag names.
You'll want to choose some convention for naming tags,
based on information such as the name of the program
and the version number of the release. For example,
one might take the name of the program, immediately
followed by the version number with `.' changed to
`-', so that CVS 1.9 would be tagged with the name
cvs1-9
. If you choose a consistent convention,
then you won't constantly be guessing whether a tag is
cvs-1-9
or cvs1_9
or what. You might
even want to consider enforcing your convention in the
taginfo file (see section 15.3 User-defined logging).
The following example shows how you can add a tag to a file. The commands must be issued inside your working copy of the module. That is, you should issue the command in the directory where `backend.c' resides.
$ cvs tag release-0-4 backend.c T backend.c $ cvs status -v backend.c =================================================================== File: backend.c Status: Up-to-date Version: 1.4 Tue Dec 1 14:39:01 1992 RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) Existing Tags: release-0-4 (revision: 1.4)
There is seldom reason to tag a file in isolation. A more common use is to tag all the files that constitute a module with the same tag at strategic points in the development life-cycle, such as when a release is made.
$ cvs tag release-1-0 . cvs tag: Tagging . T Makefile T backend.c T driver.c T frontend.c T parser.c
(When you give CVS a directory as argument, it generally applies the operation to all the files in that directory, and (recursively), to any subdirectories that it may contain. See section 8 Recursive behavior.)
The checkout
command has a flag, `-r', that lets you check out
a certain revision of a module. This flag makes it easy to
retrieve the sources that make up release 1.0 of the module `tc' at
any time in the future:
$ cvs checkout -r release-1-0 tc
This is useful, for instance, if someone claims that there is a bug in that release, but you cannot find the bug in the current working copy.
You can also check out a module as it was at any given date. See section A.7.1 checkout options.
When you tag more than one file with the same tag you can think about the tag as "a curve drawn through a matrix of filename vs. revision number." Say we have 5 files with the following revisions:
file1 file2 file3 file4 file5 1.1 1.1 1.1 1.1 /--1.1* <-*- TAG 1.2*- 1.2 1.2 -1.2*- 1.3 \- 1.3*- 1.3 / 1.3 1.4 \ 1.4 / 1.4 \-1.5*- 1.5 1.6
At some time in the past, the *
versions were tagged.
You can think of the tag as a handle attached to the curve
drawn through the tagged revisions. When you pull on
the handle, you get all the tagged revisions. Another
way to look at it is that you "sight" through a set of
revisions that is "flat" along the tagged revisions,
like this:
file1 file2 file3 file4 file5 1.1 1.2 1.1 1.3 _ 1.1 1.2 1.4 1.1 / 1.2*----1.3*----1.5*----1.2*----1.1 (--- <--- Look here 1.3 1.6 1.3 \_ 1.4 1.4 1.5
Suppose that release 1.0 of tc has been made. You are continuing to develop tc, planning to create release 1.1 in a couple of months. After a while your customers start to complain about a fatal bug. You check out release 1.0 (see section 6.4 Tags--Symbolic revisions) and find the bug (which turns out to have a trivial fix). However, the current revision of the sources are in a state of flux and are not expected to be stable for at least another month. There is no way to make a bugfix release based on the newest sources.
The thing to do in a situation like this is to create a branch on the revision trees for all the files that make up release 1.0 of tc. You can then make modifications to the branch without disturbing the main trunk. When the modifications are finished you can select to either incorporate them on the main trunk, or leave them on the branch.
The rtag
command can be used to create a branch.
The rtag
command is much like tag
, but it
does not require that you have a working copy of the
module. See section A.16 rtag--Add a symbolic tag to a module. (You can also use the tag
command; see section A.17 tag--Add a symbolic tag to checked out versions of files).
$ cvs rtag -b -r release-1-0 release-1-0-patches tc
The `-b' flag makes rtag
create a branch
(rather than just a symbolic revision name). `-r
release-1-0' says that this branch should be rooted at the node (in
the revision tree) that corresponds to the tag
`release-1-0'. Note that the numeric revision number that matches
`release-1-0' will probably be different from file to file. The
name of the new branch is `release-1-0-patches', and the
module affected is `tc'.
To fix the problem in release 1.0, you need a working copy of the branch you just created.
$ cvs checkout -r release-1-0-patches tc $ cvs status -v driver.c backend.c =================================================================== File: driver.c Status: Up-to-date Version: 1.7 Sat Dec 5 18:25:54 1992 RCS Version: 1.7 /u/cvsroot/yoyodyne/tc/driver.c,v Sticky Tag: release-1-0-patches (branch: 1.7.2) Sticky Date: (none) Sticky Options: (none) Existing Tags: release-1-0-patches (branch: 1.7.2) release-1-0 (revision: 1.7) =================================================================== File: backend.c Status: Up-to-date Version: 1.4 Tue Dec 1 14:39:01 1992 RCS Version: 1.4 /u/cvsroot/yoyodyne/tc/backend.c,v Sticky Tag: release-1-0-patches (branch: 1.4.2) Sticky Date: (none) Sticky Options: (none) Existing Tags: release-1-0-patches (branch: 1.4.2) release-1-0 (revision: 1.4) release-0-4 (revision: 1.4)
As the output from the status
command shows the branch
number is created by adding a digit at the tail of the revision number
it is based on. (If `release-1-0' corresponds to revision 1.4, the
branch's revision number will be 1.4.2. For obscure reasons CVS always
gives branches even numbers, starting at 2.
See section 6.1 Revision numbers.).
The `-r release-1-0-patches' flag that was given
to checkout
in the previous example
is sticky, that is, it will apply to subsequent commands
in this directory. If you commit any modifications, they are
committed on the branch. You can later merge the modifications into
the main trunk. See section 7 Merging.
You can use the status
command to see what
sticky tags or dates are set:
$ vi driver.c # Fix the bugs $ cvs commit -m "Fixed initialization bug" driver.c Checking in driver.c; /usr/local/cvsroot/yoyodyne/tc/driver.c,v <-- driver.c new revision: 1.7.2.1; previous revision: 1.7 done $ cvs status -v driver.c =================================================================== File: driver.c Status: Up-to-date Version: 1.7.2.1 Sat Dec 5 19:35:03 1992 RCS Version: 1.7.2.1 /u/cvsroot/yoyodyne/tc/driver.c,v Sticky Tag: release-1-0-patches (branch: 1.7.2) Sticky Date: (none) Sticky Options: (none) Existing Tags: release-1-0-patches (branch: 1.7.2) release-1-0 (revision: 1.7)
The sticky tags will remain on your working files until you delete them with `cvs update -A'. The `-A' option retrieves the version of the file from the head of the trunk, and forgets any sticky tags, dates, or options.
Sticky tags are not just for branches. For example,
suppose that you want to avoid updating your working
directory, to isolate yourself from possibly
destabilizing changes other people are making. You
can, of course, just refrain from running cvs
update
. But if you want to avoid updating only a
portion of a larger tree, then sticky tags can help.
If you check out a certain revision (such as 1.4) it
will become sticky. Subsequent cvs update
will
not retrieve the latest revision until you reset the
tag with cvs update -A
. Likewise, use of the
`-D' option to update
or checkout
sets a sticky date, which, similarly, causes that
date to be used for future retrievals.
Many times you will want to retrieve an old version of
a file without setting a sticky tag. The way to do
that is with the `-p' option to checkout
or
update
, which sends the contents of the file to
standard output. For example, suppose you have a file
named `file1' which existed as revision 1.1, and
you then removed it (thus adding a dead revision 1.2).
Now suppose you want to add it again, with the same
contents it had previously. Here is how to do it:
$ cvs update -p -r 1.1 file1 >file1 =================================================================== Checking out file1 RCS: /tmp/cvs-sanity/cvsroot/first-dir/Attic/file1,v VERS: 1.1 *************** $ cvs add file1 cvs add: re-adding file file1 (in place of dead revision 1.2) cvs add: use 'cvs commit' to add this file permanently $ cvs commit -m test Checking in file1; /tmp/cvs-sanity/cvsroot/first-dir/file1,v <-- file1 new revision: 1.3; previous revision: 1.2 done $
This section describes a CVS feature called magic branches. For most purposes, you need not worry about magic branches; CVS handles them for you. However, they are visible to you in certain circumstances, so it may be useful to have some idea of how it works.
Externally, branch numbers consist of an odd number of dot-separated decimal integers. See section 6.1 Revision numbers. That is not the whole truth, however. For efficiency reasons CVS sometimes inserts an extra 0 in the second rightmost position (1.2.3 becomes 1.2.0.3, 8.9.10.11.12 becomes 8.9.10.11.0.12 and so on).
CVS does a pretty good job at hiding these so called magic branches, but in a few places the hiding is incomplete:
cvs log
.
cvs
admin
.
You can use the admin
command to reassign a
symbolic name to a branch the way RCS expects it
to be. If R4patches
is assigned to the branch
1.4.2 (magic branch number 1.4.0.2) in file
`numbers.c' you can do this:
$ cvs admin -NR4patches:1.4.2 numbers.c
It only works if at least one revision is already committed on the branch. Be very careful so that you do not assign the tag to the wrong number. (There is no way to see how the tag was assigned yesterday).
Go to the first, previous, next, last section, table of contents.