1.
Overview
This document introduces
its reader into the subject of version control system,
using the implementation of Concurrent Versions System
(CVS).
Anyone who is interested
in software development, who is working in a development
group, or who is interested in version management
should read this document.
The listed documents
are referenced below:
[CVS]
|
Version
Management with CVS by Per Cederqvist et al
|
[WinCVS]
|
WinCvs
Version 1.1 Users Guide by Don Harper |
2. Introduction
CVS stands for Concurrent
Version System. It is a version control system that
has been developed in the public domain by many people
beginning in 1986. Currently, CVS is maintained by
Cyclic Software and there is lots of information of
their web site at
http://www.cvshome.org/.
Using CVS, you can
record the history of your source files (normally
text files, binary files are handled with some restrictions).
Instead of save every version of every file, CVS stores
only the differences between the versions. CVS also
helps you if you are working in a group on the same
project: CVS merges the work when each developer has
done its work.
Moreover, CVS allows
you to isolate changes onto a separate line of development,
known as a branch. When you change files on
a branch, the changes do not appear on the main
trunk. Later you can move the changes from one
branch to another branch (or the main trunk) by merging.
The CVS repository
stores a complete copy of all the files and directories
which are under version control. Normally, you never
access any of the files in the repository directly.
Instead, you use CVS commands to get your own copy
of the files into a working directory, and then work
on that copy.
CVS can access a repository
by a variety of means. It might be on the local computer,
or it might be on a computer across the room or across
the world. Using CVS with a remote repository
we talk about client/server operation. Several
protocols are supported to connect to the remote repository,
e.g. rsh, password authentication, GSSAPI, kerberos.
You can define several
repositories if you have different development groups
that work on separate projects without sharing any
code. All you have to do is to specify the appropriate
repository when you are starting the session.
If you want to keep
track of a set of revisions involving more than one
file, you can use tags to give a symbolic name
to a certain revision of each file. You can think
of the tag as a handle. When you pull on that handle,
you get all the tagged revisions.
file1 file2
file3 file4 file5
1.1
1.1
1.2 1.1
1.2 *** 1.1 *** 1.3 *** 1.2 *** 1.1 ***
<*** tag ***>
1.3 1.2
1.4
1.5
So it's a good idea
to tag every software release, patch, or merge with
its unique tag.
Often, two developers
try to edit the same file simultaneously. CVS supports
some solutions for this situation, e.g.
- File locking or reserved checkouts:
Only one person is allowed to edit each file at
a time.
- Use watches: Watched files are checked
out read-only. To make them read-write (and inform
others watchers) the cvs edit command is used.
- Unreserved checkouts: The rarity of serious
conflicts may be surprising, so often neither file
locks nor watches are used. If an overlap occurs,
CVS prints a warning and the resulting file includes
both versions of the lines that overlap, delimited
by special markers.
Note: In some cases
unreserved checkouts are clearly inappropriate (e.g.
if no merging tool exists).
3. A Sample Session
To learn the most
used CVS commands, we are walking through a typical
work session. The commands are shown as CVS command
line and over WinCVS menus. Note that the most used
WinCVS commands have short cuts or context sensitive
popup menus (by clicking the right mouse button).
The first thing you
must set-up your CVS session. Set your environment
and login to the server.
CVS commands
Set $CVSROOT
for local access...
> CVSROOT=<cvs_root>
> export CVSROOT
... or remote
access and connect to the CVS server:
> CVSROOT=:pserver:<username>@<servername>:<cvs_root>
> export CVSROOT
> cvs login
WinCVS commands
Start your WinCVS
client program. First time you must set-up your preferences.
Admin -> Preferences
-> General Settings
Admin -> Preferences
-> Global Settings
Admin -> Preferences
-> WinCVS Settings
Then you can login
to the CVS server:
Admin -> Login
Remarks
The repository's root
directory <cvs_root> is defined either on the
local server or on the remote server <servername>.
After the successful login, you are ready to work
under CVS.
Next thing you must
do is to get your own working copy of the source.
Change to your working directory and use the checkout
command to do this (option -r for read-only).
CVS commands
> cd <work_dir>
> cvs -r checkout <module>
WinCVS commands
Create -> Checkout
module ...
Choose your working
area
Choose your module
Use
the default settings in this example. By default,
files are checked out as read-only.
Remarks
After the successful
login, the sources of <module> will be copied
into your local working area <work_dir>. <module>
is either a valid module name or a relative path in
the repository.
If you have already
checked out the sources you can update your working
area with the newest checked-in files:
CVS commands
> cvs update
WinCVS commands
Select the <module>
in the module tree, then the menu Modify à Update
selection...
Remarks
The default directory
for the update command is always the current working
directory. The command updates the subdirectories
recursively.
In this chapter we
describe the normal way to edit a source file using
reserved checkout (file locking). Change to the working
directory where the file to edit exists.
CVS commands
> cd <work_subdir>
> cvs admin -l <filename>
> cvs update <filename>
> cvs edit <filename>
> vi <filename>
WinCVS commands
Select the file <filename>
in the file list, then the menus
- Trace -> Lock selection
- Modify -> Update selection ...
- Trace -> Edit
- Query -> View selection or View with <default_editor>
You have decided to
make a new version of the file <filename>. This
will store your new file in the repository and make
it available to other developers. For the undo of
changes see the next chapter.
CVS commands
> cvs commit
-m "<log_message>" <filename>
> cvs unedit <filename>
WinCVS commands
Select the file <filename>
in the file list, then the menu Modify -> Commit
selection...
Commit settings, Enter the log message
The commit
command automatically unlocks the file <filename>.
The unedit command
is only successful if watches are in use. WinCVS also
automatically makes the file read-only.
You have decided to
undo the changes of the file <filename>. In
this case, all the commands should be reverted. For
the commit of changes see the previous chapter.
CVS commands
> cvs unedit
<filename>
> cvs update <filename>
> cvs admin -u <filename>
WinCVS commands
Select the file <filename>
in the file list, then the menus
- Trace -> Unedit selection
- Trace -> Unlock selection
You can finish your
session with the cleanup of your working area. Use
the release command therefore. This command checks
that all your modifications have been committed.
CVS commands
> cd <work_dir>
> cvs release -d <module>
WinCVS commands
Select the <module>
in the module tree, then the menu Trace à Release
selection.
Remarks
The -d option removes
your working copy too. Otherwise you can remove the
working area manually.
4. Advanced Commands
In this chapter some
further CVS commands are described. This commands
are very useful but not used in the daily business.
Most of this commands have a variety of options so
we recommend to look up in [CVS] as well.
To add a new file
to a directory, follow these steps:
-
You must have a working copy of
the directory.
-
Create the new file inside your
working copy of the directory.
-
Use the command cvs
add <filename> to add this file to
version control. For binary files use the option
-kb.
-
Use the command cvs
commit <filename> to actually check
in the file into the repository. Other developers
cannot see the file until your perform this step.
You can also use the
command cvs add to
add a new directory as well. Note: Unlike most other
command the add command is not recursive.
New files are added,
and old files disappear. But you want to be able to
retrieve an exact copy of old releases everytime.
Here is what you can
do to remove a file:
-
Make sure that you have not made
any uncommitted changes to the file.
-
Remove the file from your working
copy of the directory (use rm or delete).
-
Use cvs
remove <filename> to tell CVS that
you really want to delete the file.
-
User cvs
commit <filename> to actually perform
the removal of the file form the repository.
Removing directories
is similar to removing files: The way that you remove
a directory is to remove all the files in it. You
don't remove the directory itself. Instead you specify
the option -P to cvs update, cvs checkout, or cvs
export, which will cause CVS to remove empty directories
from working directories.
Tags are symbolic
names to a certain revision of each file. We recommend
to tag all software releases, patches, or merges with
its unique tag.
You have two possibilities
to tag: Running the cvs tag
command causes CVS to select the revisions which are
checked out in the current working directory. The
cvs rtag command works
directly on the repository contents and requires no
prior checkout and does not look for a working directory.
Using the Working Directory
For the following
cvs command tags the current working directory.
CVS commands
> cd <work_dir>
> cvs tag -c <tag_name> [file | directory
| module]
WinCVS commands
Select the module
in the module tree or the file in the file list, then
the menu Modify -> Create a tag on selection...
Remarks
You can use the option
-c to check for uncommitted changes
(locally modified files).
Using the Repository
The cvs
rtag command tags the repository as of a certain
date or time. This is useful to tag the latest version.
rtag works directly
on the repository and requires no prior checkout.
This command is not supported by WinCVS. Tag the most
recent revision no later than <date> ...
> cvs rtag
-f -D <date> <new_tag> [file | directory
| module]
... or tag those files
that contain existing tag <existing_tag>
> cvs rtag
-f -r <existing_tag> <new_tag>
[file | directory | module]
CVS allows you to
isolate changes onto a separate line of development,
known as a branch. When you change files on
a branch, those changes do not appear on the main
trunk.
Create a Branch
Again you will use
the cvs tag or cvs rtag commands to create a branch.
The tag command uses the current revisions in the
working copy, the rtag command works directly in the
repository:
> cvs tag –b
<branch_tag>
... or tag those files
that contain existing tag <existing_tag>
> cvs rtag
-f -r <existing_tag> <branch_tag>
[file | directory | module]
Note that branches
always get created in the repository, not in the working
copy. So you must checkout the branch files to your
working directory explicit:
> cvs -r checkout
-r <branch_tag> <module>
or switch the working
directory to a given branch with the cvs update command:
> cvs -r update
-r <branch_tag> <module>
Now you can work on
the branch files and commit your changes back to repository.
Merging a Branch
You can merge changes
made on a branch into your working copy. The working
copy could be either the main trunk or another branch.
> cvs update
-j <branch_tag> [file | directory | module]
The option -j merges
the changes made between up to the newest revision
on that branch into your working copy. Conflicts can
result from the merge operation. This conflicts should
be resolved before committing the changes to the repository.
If the development
continuos on that branch, you may want to merge those
changes again. As recommended earlier each merged
revision should be tagged in the branch. Use that
tag for subsequent merges:
> cvs update
-j <merge_tag> -j <branch_tag>
[file | directory | module]
The most common use
for CVS is to store text files. If you are willing
to give up a few of CVS' abilities (such as display
differences, merging revisions), CVS can store binary
files as well.
The -kb
option available in some CVS commands insures that
neither line ending conversion nor keyword expansion
will be done. New files can be added as follows:
> cvs add -kb
-m "A binary file" <filename>
Or you can use the
following commands to recover the binary file:
> cvs admin
-kb <filename>
> cvs update -A <filename>
> cvs commit -m "Make it binary" <filename>
CVS can use a mechanism
known as keyword substitution or keyword
expansion to help identifying delivered files.
Embedded strings of the form $keyword$ in
the source file are expanded to strings of the form
$keyword:value$.
This is a list of
the keywords. For full explanation, please refer to
[CVS].
$Author$ |
The login name of user who
checked in the revision. |
$Date$ |
Date and time (UTC) the revision
was checked in. |
$Header$ |
A standard header.
|
$Id$ |
Same as $Header$ (except
RCS file without path). |
$Name$ |
Tag name used to checkout
this file. |
$Locker$ |
The login name of the user
who locked the revision. |
$Log$ |
The log message supplied
during commit. |
$RCSfile$ |
The name of the RCS file
without a path. |
$Revision$ |
The revision number assigned
to the revision. |
$Source$ |
The full pathname of the
RCS file. |
$State$ |
The state assigned to the
revision. |
5. Administrator Tasks
In this chapter some
administrator tasks are discussed. The directory
$CVSROOT/CVSROOT contains some administrative
files. You can edit this files in the same way that
you would edit any other module: Get a working copy,
edit it, and commit your changes in the normal way.
When you check in an administrative file, CVS rebuilds
the administrative file database.
The most important
of the administrative files is the modules file. It
defines all modules in the repository. This is not
strictly necessary, but modules can be convenient
in grouping together related files and directories.
Three different line
formats are valid:
# key -a aliases...
# key [options] directory
# key [options] directory files...
This is a sample of
modules file:
CVSROOT
CVSROOT
modules CVSROOT modules
test projects/test1
One could write books
about security issues... Here are only some recommendations.
The directory $CVSROOT/CVSROOT
contains confidential information. You must control
the permissions on this directory very restrictive,
specially if you are using the password authenticated
server.
It is possible to grant read-only
access to the repository using the password authenticated
server. There are two ways to do this: by inclusion
and by exclusion. Inclusion means listing all users
with read-only access in the
$CVSROOT/CVSROOT/readers file. Exclusion means
explicitly listing everyone who has write access
in the $CVSROOT/CVSROOT/writers
file. Please refer to the following rules:
-
If readers
exists, and the user is listed in it, then the
user gets read-only access.
-
If writers
exists, and the user is not listed in it, then
the user gets read-only access. This is true even
if readers exists, and the user is not listed
in it.
-
If both files exist and the user
is listed in them, CVS resolves this conflict
in a conservative way: such a user gets read-only
access.
When authenticating a password, the
server first checks for the user in the file. If it
finds the user, it will use that entry for authentication,
else the server can try to authenticate user name
and password using the operating system's identification
(fall back behaviour). Please find further information
in [CVS].
In a first step the
files must be created in the repository. The next
step is to define the module in the modules
file. This step is not strictly necessary, but modules
can be convenient in grouping together related files
and directories.
Creating the Repository from Existing
Files
You will probably
already have several projects that can be put under
CVS control. In this case you will use the import
command:
> cd <working_dir>
> cvs import -m "Imported sources"
<repository_dir> <vendor_tag> <release_tag>
The files in the working
directory <working_dir> are imported
in the CVS repository as $CVSROOT/<repository_dir>.
<repository_dir> could contain a directory
structure as well.
It is a good idea
to check that the permissions CVS sets on the directories
inside $CVSROOT are reasonable, and that they
belong to the proper groups.
If some of the files
you want to import are binary, you may want to use
the wrappers features or to change them manually to
binary.
Create an empty directory
structure and import this structure to create the
corresponding directory structure in the repository.
Then use the add command to add files as they appear.
Check that the permissions
CVS sets on the directories inside $CVSROOT
are reasonable.
Creating the Repository from Other
Version Control Systems
If you have a project
which you are maintaining with another version control
system, you may wish to put the files from that project
into CVS and preserve the revision history of the
files. Here the way for RCS is shown, please see [CVS]
for other systems.
This is one of the
few times when it is a good idea to access the CVS
repository directly: Create the appropriate directories
in CVS if they do not already exit. Then copy the
files in the appropriate directories in the CVS repository
without changing the file name.
Note that the RCS
files are not locked when you copy them into CVS.
5.4 Backing Up the Repository
For the most part
it is possible to backup the repository just like
any other files. However, there are a few issues to
consider:
To get a consistent
state of the repository, one should not use CVS during
backup. To not use CVS, you might forbid logins or
turn off your CVS server. Another idea is to lock
CVS.
6. Examples
- Go to the top of the project tree:
cd /home/myproj
- cvs import -m "Initial Import into CVS"
myproj akadia start
myproj = Name under which you will check
out the project
akadia = vendortag
start = releasetag
The directory tree in now imported in
the CVS, however you must now checking out a working
copy, the current directory tree is still not a CVS
working copy.
- Go to another empty directory
Local Repository
- cvs checkout myproj
Remote Repository
- cvs
-q -d :pserver:zahn@rabbit.akadia.com:/opt/cvs-root
\
checkout myproj
You get the same as what you imported,
with the addition of a subdirectory named CVS
- cd CVS (In the working CVS directory)
- ls -l
-rw-r--r-- 1 zahn dba 134 Aug 29 13:56
Entries
-rw-r--r-- 1 zahn dba 7 Aug 29 13:56 Repository
-rw-r--r-- 1 zahn dba 14 Aug 29 13:56 Root
- cat Repository
myproj
- cat Entries
/README.txt/1.1.1.1/Tue Aug 29 10:30:36 2000//
/hello.c/1.1.1.1/Tue Aug 29 10:30:36 2000//
D/a-subdir////
D/b-subdir////
D/myproj////
- cat Root
/opt/cvs-root
Make a change on hello.c, even if nothing
in the repository has changed since checkout, something
in the working copy may have, and update will show that.
- cvs update
cvs update: Updating .
M hello.c
cvs update: Updating a-subdir
cvs update: Updating a-subdir/subsubdir
cvs update: Updating b-subdir
cvs update: Updating myproj
The M next to hello.c
means the file has been modified. If you want a more
detailed look at the changes, you can get a full report
in diff format.
- cvs diff
- cvs -Q diff
(Shorter Output)
- cvs -Q diff -c (Display
some lines of context on either side of a change)
The commit command
send modifications to the repository.
- cvs commit -m "Error corrected
in explain()"
cvs commit: Examining .
cvs commit: Examining a-subdir
cvs commit: Examining a-subdir/subsubdir
cvs commit: Examining b-subdir
cvs commit: Examining myproj
Checking in hello.c;
/opt/cvs-root/myproj/hello.c,v <-- hello.c
new revision: 1.2; previous revision: 1.1
done
Check the status of the files in the
CVS repository
- cvs status
Finding out who did what (Browsing Log
Messages)
- cvs log
Create the new file in the working CVS
directory, add and commit it in CVS:
- cvs add newfile.c
cvs server: use 'cvs commit' to add this
file permanently
- cvs ci -m "Added newfile.c"
newfile.c
RCS file: /opt/cvs-root/myproj/newfile.c,v
done
Checking in newfile.c;
/opt/cvs-root/myproj/newfile.c,v <-- newfile.c
initial revision: 1.1
done
Unlike adding files, adding a new directory
is done in one step:
- mkdir c-subdir
- cvs add c-subdir
Directory /opt/cvs-root/myproj/c-subdir added
to the repositor
CVS handles CRLF correctly on textfiles,
but this is not desired for binary files, therefore
use the -kb option. For Textfiles you may disable the
keyword expansion as well: use -ko.
cvs add -kb who
cvs ci -m "Binary File added" who
Removing a file is similar to adding
one, except there's an extra step: You have to remove
the file from the working copy first.
rm newfile.c
cvs remove newfile.c
cvs ci -m "removed newfile.c" newfile.c
Removing newfile.c;
/opt/cvs-root/myproj/newfile.c,v <-- newfile.c
new revision: delete; previous revision: 1.1
done
CVS doesn't really keep directories
under version control. If you want to remove a directory
from a project, you first remove all the files in it,
then use update -P to remove the directory from the
working directory.
cd a-subdir
rm file1 file2 file3
cvs remove file1 file2 file3
cvs ci -m "Removed all files"
Now remove empty directory from working
copy
cvs update -P
CVS does not automatically bring new
directories from the repository into your working copy.
From time to time you should run update -d, telling
to bring down any new directories from the repository.
cvs update -d
All empty directories from the repository
are now rebuild in the working copy.
Renaming a file is equivalent to creating
it under the new name and removing the old file.
mv README.txt INSTALL.txt
cvs remove README.txt
cvs add INSTALL.txt
cvs ci -m "renamed README.txt to INSTALL.txt"
README.txt INSTALL.tt
Removing README.txt;
/opt/cvs-root/myproj/README.txt,v <-- README.txt
new revision: delete; previous revision: 1.2
done
RCS file: /opt/cvs-root/myproj/INSTALL.txt,v
done
Checking in INSTALL.txt;
/opt/cvs-root/myproj/INSTALL.txt,v <-- INSTALL.txt
initial revision: 1.1
done
Renaming Directories is a bit cumbersome.
The best policy is to try to come up with a good layout
when you initially import the project. One solution
to rename one or more directories is to checkout the
project, make the changes on the local working copy,
delete the CVS project in the repository and import
the changed project again.
cd myproj
mv a-subdir z-subdir
find . -name CVS -exec rm -rf {} \;
cd /opt/cvs-root
rm -rf myproj
cd /home/zahn/myproj
cvs import -m "Test Projekt" myproj akadia
start
rm -r myproj
cvs checkout myproj
The date-based retrieval are done by
passing update the -D flag. With the -D option, update
retrieves the highest revision of each file as of the
given date and it will revert the files in the working
copy to prior revisions if necessary. Retrieving by
date is useful when the mere passage of time is your
main concern.
cvs -q update -D "2000-09-14"
Often you really want to retrieve the
project as it was at the time of a specific event --
perhaps a public release, a known stable point in the
software development or the addition or removal of some
major feature. The method CVS offers for making such
marks is known as tagging.
Setting a Tag (Snapshot):
cvs rtag Final-Release myproj
Retrieving the tagged release (Snapshot):
cvs checkout -P -r Final-Release
myproj
Removing Tags (untagging)
cvs
rtag -d Final-Release myproj
|