Concurrent Versions System

Objectives

After completing this tutorial, you will be able to: 

 1.Setup CVS 
 2.Be able to put a project under CVS 
 3.Be able to use CVS. 
 4.Understand how and why branching is useful. 

Before starting this tutorial, you should: 

 1.Know how to create directories and copy files. 
 2.Have an account on the Cobra Cluster, or another machine with CVS
    installed. 
 3.If using the Cobra Cluster, Add /class/bfennema/bin to your command path.
    [For csh/tcsh: set path=(/class/bfennema/bin $path)]
    [For sh/bash/ksh: PATH=/class/bfennema/bin:$PATH;export PATH]
 4.Setup netscape and a window open to a machine on the cobra cluster next to
    each other. 
 5.Since CVS uses RCS, doing the RCS tutorial would probably be helpful 



Conceptual Overview

CVS is a version control system. It is used to record the history of your source
files. 


Bugs can creep in when software is modified, and may not be detected until a
long time after the modification is made. With CVS, you can retrieve old
versions to find which change caused the bug. 

CVS can also help when a project is being worked on by multiple people, where
overwriting each others changes is easy to do. CVS solves this problem by
having each developer work in his/her own directory and then instructing CVS
to merge the work when each developer is done. 

The CVS files are stored using RCS. For additional information regarding the
format of these files see the RCS tutorial. 


Tutorial

Version 1.5b, 11:51:04 PST 1996

    Tutorial Information


Tutorial Information

All commands are in bold: cvs commit bob.c
All output from the command is in italics: U bob.c

The first time a command is used, the output from the command will be given.
Other times, it may not be if it is the same as before.

Continue - Getting Ready to Use CVS
....................

    Getting Ready to Use CVS

Getting Ready to Use CVS

First set the variable CVSROOT to /class/`username`/cvsroot
[Or any other directory you wish]
[For csh/tcsh: setenv CVSROOT ~/cvsroot]
[For bash/ksh: CVSROOT=~/cvsroot;export CVSROOT]

Next run cvsinit. It will create this directory along with the subdirectory
CVSROOT and put several files into CVSROOT.

Continue - How to put a project under CVS
..............................
    How to put a project under CVS


How to put a project under CVS

A simple program consisting of multiple files is in /class/bfennema/project.

To put this program under cvs first

cd to /class/bfennema/project

Next

cvs import -m "Sample Program" project sample start

CVS should respond with
N project/Makefile
N project/main.c
N project/bar.c
N project/foo.c

No conflicts created by this import

If your were importing your own program, you could now delete the original
source.
(Of course, keeping a backup is always a good idea)

Continue - Basic CVS Usage
..................................
    Basic CVS Usage

Basic CVS Usage

Now that you have added 'project' to your CVS repository, you will want to be
able to modify the code.

To do this you want to check out the source. You will want to cd to your home
directory before you do this.

cd

cvs checkout project

CVS should respond with
cvs checkout: Updating project
U project/Makefile
U project/bar.c
U project/foo.c
U project/main.c


This creates the project directory in your home directory and puts the files:
Makefile, bar.c, foo.c, and main.c into the directory along with a CVS directory
which stores some information about the files.

You can now make changes to any of the files in the source tree.
Lets say you add a printf("DONE\n"); after the function call to bar()
[Or just cp /class/bfennema/project_other/main2.c to main.c]

Now you have to check in the new copy

cvs commit -m "Added a DONE message." main.c

CVS should respond with
Checking in main.c;
/class/'username'/cvsroot/project/main.c,v <-- main.c
new revision: 1.2; previous revision: 1.1
done

Note, the -m option lets you define the checking message on the command
line. If you omit it you will be placed into an editor where you can type in the
checking message.
...............................
    Using CVS with Multiple Developers

Using CVS with Multiple Developers

To simulate multiple developers, first create a directory for your second
developer.
Call it devel2 (Create it in your home directory).
Next check out another copy of project.

    HINT: cvs checkout project

Next, in the devel2/project directory, add a printf("YOU\n"); after the
printf("BAR\n");
[Or copy /class/bfennema/project_other/bar2.c to bar.c]

Next, check in bar.c as developer two.

    HINT: cvs commit -m "Added a YOU" bar.c

Now, go back to the original developer directory.
[Probably /class/'username'/project]

Now look at bar.c. As you can see, the change made by developer one has no
been integrated into your version. For that to happen you must

cvs update bar.c

CVS should respond with
U bar.c

Now look at bar.c. It should now be the same as developer two's.
Next, edit foo.c as the original developer and add printf("YOU\n"); after
the printf("FOO\n");
[Or copy /class/bfennema/project_other/foo2.c to foo.c]

Then check in foo.c

    HINT: cvs commit -m "Added YOU" foo.c

Next, cd back to developer two's directory.
Add printf("TOO\n"); after the printf("FOO\n");
[Or copy /class/bfennema/project_other/foo3.c to foo.c]

Now type

cvs status foo.c

CVS should respond with

===================================================================
File: foo.c             Status: Needs Merge

   Working revision:    1.1.1.1 'Some Date'
   Repository revision: 1.2     /class/'username'/cvsroot/project/foo.c,v
   Sticky Tag:          (none)
   Sticky Date:         (none)
   Sticky Options:      (none)

The various status of a file are:
Up-to-date 

    The file is identical with the latest revision in the repository.

Locally Modified 

    You have edited the file, and not yet committed your changes.

Needing Patch 

    Someone else has committed a newer revision to the repository.

Needs Merge 

    Someone else has committed a newer revision to the repository, and you
    have also made modifications to the file.


Therefore, this is telling use we need to merge our changes with the changes
made by developer one. To do this

cvs update foo.c

CVS should respond with
RCS file: /class/'username'/cvsroot/project/foo.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
Merging differences between 1.1.1.1 and 1.2 into foo.c
rcsmerge: warning: conflicts during merge
cvs update: conflicts found in foo.c
C foo.c

Since the changes we made to each version were so close together, we must
manually adjust foo.c to look the way we want it to look. Looking at foo.c we
see:

void foo()
{
  printf("FOO\n");
<<<<<<< foo.c
  printf("TOO\n");
=======
  printf("YOU\n");
>>>>>>> 1.2
}


We see that the text we added as developer one is between the ======= and the
>>>>>>> 1.2.
The text we just added is between the ======= and the <<<<<<< foo.c

To fix this, move the printf("TOO\n");to after the
printf("YOU\n");line and delete the additional lines the CVS inserted. [Or
copy /class/bfennema/project_other/foo4.c to foo.c] 
Next, commit foo.c

cvs commit -m "Added TOO" foo.c

Since you issued a cvs update command and integrated the changes made by
developer one, the integrated changes are committed to the source tree.
................................
    Branches in CVS


Branches in CVS

One useful feature of CVS, especially when maintaining several releases of a
software product at once, is the ability to make branches on the revision tree. 

The RCS version numbers have nothing to do with the release numbers of the
software product. Therefore, CVS has the tag command which allows you to
give a symbolic name to a certain revision of a file. The -v option to the cvs
status command allows you to view any tags on a file.


Back to our example, go back to the first developers directory and issue a

cvs update foo.c

to get the current version of foo.c.
Next, we want to release version 1 of our wonderful software product.
To do this, we want to tag all files with the tag release-1.

cvs tag release-1 .

CVS should respond with
cvs tag: Tagging .
T Makefile
T bar.c
T foo.c
T main.c


If some other developer wanted to check out release-1, he would issue the cvs
command:

cvs checkout -r release-1 project

He would then get the release version, instead of the newest version (if there
was one)


Now that we have made a release version, lets pretend we have started working
on version 2. Next thing we know, our customers are complaining about a fatal
error in version 1. Version 2 may be several months off in the future, and this
bug in version 1 needs to be fixed now.

First off, we can remove our two developmental trees from the previous
tutorials. There is a simple way to do this using CVS.
Go to the directory where your first project directory resides, and issue:

cvs release -d project

CVS should respond with
You have [0] altered files in this repository.
Are you sure you want to release (and delete) module `project':

To this response: y


The -d option tells cvs release to delete the working copy.
You can now issue this same command for developer 2's directory.

Next we want to create a branch off version 1.
Go back to the original directory where project was and issue the command:

cvs rtag -b -r release-1 release-1-patches project

CVS should respond with
cvs rtag: Tagging project

Next we need a working copy of the branch that was just created.

cvs checkout -r release-1-patches project

CVS should respond with
cvs checkout: Updating project
U project/Makefile
U project/bar.c
U project/foo.c
U project/main.c


You can now fix the bug in version 1. Any changes committed will be
committed to the branch and not the main trunk.
Lets say the bug fix is to swap the YOU and TOO printf's in foo.c
Do this
[Or copy /class/bfennema/project_other/foo5.c to foo.c]

Next, check back in foo.c: cvs commit -m "Fixed printf bug" foo.c

It is also possible to merge the branch back into the main tree.
To do this, first release the patched version.

cd ..
cvs release -d project

Next, used the -j 'branch' option to cvs checkout to merge release-1 and
release-1-patches.

cvs checkout -j release-1-patches project

CVS should respond with
cvs checkout: Updating project
U project/Makefile
U project/bar.c
U project/foo.c
RCS file: /class/'username'/cvsroot/project/foo.c,v
retrieving revision 1.3
retrieving revision 1.3.2.1
Merging differences between 1.3 and 1.3.2.1 into foo.c
U project/main.c


If there are any conflicts, they will have to be manually resolved.
After this is done you can now do a

cvs commit -m "Merged patch"

to commit all the files changed by the merge of release-1-patch into the
current source tree.
..................................
    Additional CVS Commands

Additional CVS Commands

To add a new file to a module: 

    Get a working copy of the module. 
    Create the new file inside your working copy. 
    use cvs add filename to tell CVS to version control the file. 
    use cvs commit filename to check in the file to the repository. 


Removing files from a module: 

    Make sure you haven't made any uncommitted modifications to the file. 
    Remove the file from the working copy of the module. rm filename. 
    use cvs remove filename to tell CVS you want to delete the file. 
    use cvs commit filename to actually perform the removal from the
    repository. 


For more information see the cvs man pages or the cvs.ps file in cvs-1.7/doc.
...............................
    Files Used In Tutorial

    Makefile 

MAKE=   make
CC=     gcc
RM=     rm -rf

OBJS=   main.o foo.o bar.o

prog:   $(OBJS)
        $(CC) -o prog $(OBJS)

clean:
        $(RM) $(OBJS) prog

.c.o:
        $(CC) -c $<
=======
    main.c 
#include <stdio.h>

extern void foo();
extern void bar();

void main()
{
  printf("This is a test program.\n");
  foo();
  bar();
}
======
    foo.c 
void foo()
{
  printf("FOO\n");
}
======
    bar.c 

void bar()
{
  printf("BAR\n");
}
======
    main2.c 

#include <stdio.h>

extern void foo();
extern void bar();

void main()
{
  printf("This is a test program.\n");
  foo();
  bar();
  printf("DONE\n");
}
======
    foo2.c 

void foo()
{
  printf("FOO\n");
  printf("YOU\n");
}
======
    foo3.c 

void foo()
{
  printf("FOO\n");
  printf("TOO\n");
}
======
    foo4.c 

void foo()
{
  printf("FOO\n");
  printf("YOU\n");
  printf("TOO\n");
}
======
    foo5.c 

void foo()
{
  printf("FOO\n");
  printf("TOO\n");
  printf("YOU\n");
}
======
    bar2.c 
void bar()
{
  printf("BAR\n");
  printf("YOU\n");
}
======
..............................

System Requirements

    CVS can be compiles under UNIX, OS2, and Windows NT. 
    This version of CVS does no seem to be compatible with the version of RCS
    on the Cobra Cluster. 
    The version of CVS compiled in my bin directory on the Cobra Cluster uses
    the GNU RCS and GNU diff files which are also in my bin directory. 
    For information on compiling CVS, RCS, or diff, see the system
    administrator at the machine you want them installed on (usually root). 
..................................

References

Version Management with CVS, Copyright  1992, 1993 Signum Support AB
[Available in cvs-1.7/doc, file cvs.ps]

CVS man page
[Available in /class/bfennema/man]



CVS is available via anonymous ftp from prep.ai.mit.edu in /pub/gnu
[cvs-1.7.tar.gz]
RCS is available via anonymous ftp from prep.ai.mit.edu in /pub/gnu
[rcs-5.7.tar.gz]
diff is available via anonymous ftp from prep.ai.mit.edu in /pub/gnu
[diffutils-2.7.tar.gz]