Team Coding With CVS

Problem definition

Forget you've heard of RCS. Just think about the problem.

Problem 1: team coding

How do you get multiple programmers to safely work on the same large code base?

Possible strategies:

Don't get revisions / implicit backup with any of these strategies.

Problem 2: tracking revisions, releases

How do you track evolution of a program and how do you make releases?

Need because:

  1. You want to be able to record exact code state for each release to handle bug reports etc...
  2. You want to find out "what has changed since last version" because it doesn't work anymore.

Possible strategies:

Concepts

CVS (concurrent versions system) is a widely-used, free, open-source tool that manages the above strategies for you. It's "designed by committee" but great for a free tool. Perforce is better, imho, but costs $600 per seat.

CVS has the notion of a repository that stores your your code, tracks all changes, and records your revision comments. CVS doesn't do transactions and doesn't have a real db...just a bunch files on the disk. You can wack trees off the repository (and remove local CVS dirs) w/o consequence. CVS works off a repository directory $CVSROOT and stores some local information in your directories that it manages. You'll set CVSROOT=~userid/cvsroot in your .cshrc or .bashrc etc...

You do not mess with repository, you checkout directories/files, make changes, and then commit your changes and add comments for the log.

Command line usage: cvs command ...

RCS -- Walter Tichy -- works on single files to track revisions. Think of CVS as just a recursive RCS that works on multiple files / dirs. When you check out some code, it does a cp -r repository CWD. When you commit, it does a diff of your current files against repository and then merges your stuff into repository. After a commit, the repository will be a dup of your CWD.

You check out once, commit many time.

There is an implied main branch (main trunk). 1.1, 1.2, 1.3, ... for all files. The HEAD is the latest version of each file.

http://cvsbook.red-bean.com/cvsbook.html
Copyright B) 1999, 2000 Karl Fogel 
     File A      File B      File C      File D      File E
     ------      ------      ------      ------      ------
     1.1         1.1         1.1         1.1         1.1
 ----1.2-.       1.2         1.2         1.2         1.2
     1.3 |       1.3         1.3         1.3         1.3
          \      1.4       .-1.4-.       1.4         1.4
           \     1.5      /  1.5  \      1.5         1.5
            \    1.6     /   1.6   |     1.6         1.6
             \   1.7    /          |     1.7         1.7
              \  1.8   /           |     1.8       .-1.8------->
               \ 1.9  /            |     1.9      /  1.9
                `1.10'             |     1.10    /   1.10
                 1.11              |     1.11    |
                                   |     1.12    |
                                   |     1.13    |
                                    \    1.14    |
                                     \   1.15   /
                                      \  1.16  /
                                       `-1.17-'

http://cvsbook.red-bean.com/cvsbook.html
Copyright B) 1999, 2000 Karl Fogel 

But if you pull the string taut and sight directly along it, you'll
see a particular moment in the project's history - namely, the moment
that the tag was set (Figure 2.2).

     File A      File B      File C      File D      File E
     ------      ------      ------      ------      ------
                                         1.1
                                         1.2
                                         1.3
                                         1.4
                                         1.5
                                         1.6
                                         1.7
                 1.1                     1.8
                 1.2                     1.9
                 1.3                     1.10        1.1
                 1.4                     1.11        1.2
                 1.5                     1.12        1.3
                 1.6                     1.13        1.4
                 1.7         1.1         1.14        1.5
                 1.8         1.2         1.15        1.6
     1.1         1.9         1.3         1.16        1.7
 ----1.2---------1.10--------1.4---------1.17--------1.8------->
     1.3         1.11        1.5         1.17        1.9
                             1.6         1.17        1.10

I expect you students to play around to get the feel. It takes experience.

Single coder usage

You will only need a few CVS commands as a single coder:

I suggest strongly the following dir structure:

~/projects/Server/main/http/*.java
~/projects/Server/release/alpha/http/*.java
~/projects/Server/release/1_0/http/*.java
...

where http is the package name so http.Server maps to

~/projects/Server/main/http/Server.class

if your CLASSPATH is set to .:~/projects/Server/main.

Team usage

Same concept as single-user mode--you'll just be doing that stuff in your own branch.

I suggest strongly the following dir structure:

~/projects/Server/main/http/*.java
~/projects/Server/dev/john-fixing-GET/http/*.java
~/projects/Server/dev/mary-adding-logging/http/*.java
~/projects/Server/release/alpha/http/*.java
~/projects/Server/release/1_0/http/*.java
...

Note: you can have as many of these branches checked out as you want or you can release them. Cancels the effect of cvs checkout.

Example

To make a dev branch and merge your changes back into the main line, follow this procedure:

  1. Create the branch in repository.
    $ cd ~/projects/Server/main/http
    $ cvs tag -b john01.dev
    
  2. Move to an appropriate dev dir and check that branch out. Now you have the main and the john01.dev branches checked out.
    $ cd ~/projects/Server/dev/john01.dev
    $ cvs checkout -r john01.dev http
    
    Note that -b and -r flags are different for some stupid reason.
  3. Check the status to see that you are indeed in the right spot.
    $ cvs status
    
    Will show
       Sticky Tag:          john01.dev (branch: 1.3.2)
    
  4. Work on this branch and commit changes.
    $ cvs commit
    
  5. Get a version of your dev branch merged with mainline. Jump back to main branch area, make sure it's fresh, do merge, resolve conflicts.
    $ cd ~/projects/Server/main/http
    $ cvs update # are we fresh?
    $ cvs update -j john01.dev # merge john01.dev into main
    
  6. Test and commit
    $ cvs commit
    
  7. Set dev branch as "dead"
    $ cd ~/projects/Server/dev/john01.dev
    $ cvs release
    $ chmod -R a-w . # if you want (makes read only)
    

A simple walk-through

  1. Make T.java (http.T is fully qualified name) in /tmp then import.
  2. checkout mainline.
  3. Show CVS dirs and repository.
  4. Show status and log.
  5. Add file U.java (http.U).
  6. Commit.
  7. Show status and log.
  8. Make changes and commit.
  9. Tag a release, jump to release dir (mk it), checkout, show status, set readonly.
  10. Make dev branch, jump to branch, checkout, show status, make change to T.java, commit.
  11. Jump back to main dir, update, status shows main. Merge in dev. compile/test. Commit.
  12. Release dev.

Here is the script output (cleaned up minus the release branch item):

[jazz:~] parrt% cd /tmp
[jazz:/tmp] parrt% mkdir http
[jazz:/tmp] parrt% cd http
[jazz:/tmp/http] parrt% cat > T.java
package http;

public class T {
  int i = 3;
}
[jazz:/tmp/http] parrt% cvs import -m 'course test' http USF start
N http/T.java

No conflicts created by this import
[jazz:/tmp/http] parrt% ls -l /var/data/cvsroot
total 0
drwxr-xr-x  37 parrt  wheel  1258 Sep  7 11:31 CVSROOT
drwxrwxr-x  21 parrt  wheel   714 Sep 11 15:34 http
[jazz:/tmp/http] parrt% ls -l /var/data/cvsroot/http
[jazz:/tmp/http] parrt% mkdir -p /tmp/projects/Server/main
[jazz:/tmp/http] parrt% cd /tmp/projects/Server/main
[jazz:projects/Server/main] parrt% cvs checkout http
cvs checkout: Updating http
U http/T.java
[jazz:projects/Server/main] parrt% cd http
[jazz:Server/main/http] parrt% ls
CVS    T.java
[jazz:Server/main/http] parrt% ls CVS
Entries    Repository Root
[jazz:Server/main/http] parrt% cvs status
cvs status: Examining .
===================================================================
File: T.java           	Status: Up-to-date

   Working revision:	1.1.1.1	Wed Sep 11 22:35:48 2002
   Repository revision:	1.1.1.1	/var/data/cvsroot/http/T.java,v
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

[jazz:Server/main/http] parrt% cvs log
cvs log: Logging .

RCS file: /var/data/cvsroot/http/T.java,v
Working file: T.java
head: 1.1
branch: 1.1.1
locks: strict
access list:
symbolic names:
	start: 1.1.1.1
	USF: 1.1.1
keyword substitution: kv
total revisions: 2;	selected revisions: 2
description:
----------------------------
revision 1.1
date: 2002/09/11 22:35:48;  author: parrt;  state: Exp;
branches:  1.1.1;
Initial revision
----------------------------
revision 1.1.1.1
date: 2002/09/11 22:35:48;  author: parrt;  state: Exp;  lines: +0 -0
course test
=============================================================================
[jazz:Server/main/http] parrt% cat > U.java
package http;
public class U {
  int j = 5;
}
[jazz:Server/main/http] parrt% cvs add U.java
cvs add: scheduling file `U.java' for addition
cvs add: use 'cvs commit' to add this file permanently
[jazz:Server/main/http] parrt% cvs commit
cvs commit: Examining .
...
Checking in U.java;
/var/data/cvsroot/http/U.java,v  <--  U.java
initial revision: 1.1
done
[jazz:Server/main/http] parrt% cvs log
cvs log: Logging .

RCS file: /var/data/cvsroot/http/T.java,v
Working file: T.java
head: 1.1
branch: 1.1.1
locks: strict
access list:
symbolic names:
	start: 1.1.1.1
	USF: 1.1.1
keyword substitution: kv
total revisions: 2;	selected revisions: 2
description:
----------------------------
revision 1.1
date: 2002/09/11 22:35:48;  author: parrt;  state: Exp;
branches:  1.1.1;
Initial revision
----------------------------
revision 1.1.1.1
date: 2002/09/11 22:35:48;  author: parrt;  state: Exp;  lines: +0 -0
course test
=============================================================================

RCS file: /var/data/cvsroot/http/U.java,v
Working file: U.java
head: 1.1
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 1;	selected revisions: 1
description:
----------------------------
revision 1.1
date: 2002/09/11 22:37:29;  author: parrt;  state: Exp;
added a file
=============================================================================
[jazz:Server/main/http] parrt% vi T.java
[jazz:Server/main/http] parrt% cvs commit
cvs commit: Examining .
Checking in T.java;
/var/data/cvsroot/http/T.java,v  <--  T.java
new revision: 1.2; previous revision: 1.1
done
[jazz:Server/main/http] parrt% cvs tag -b dev01
cvs tag: Tagging .
T T.java
T U.java
[jazz:Server/main/http] parrt% cd /tmp/projects/Server
[jazz:/tmp/projects/Server] parrt% mkdir dev
[jazz:/tmp/projects/Server] parrt% cd dev
[jazz:/tmp/projects/Server/dev] parrt% mkdir dev01
[jazz:/tmp/projects/Server/dev] parrt% cd dev01
[jazz:projects/Server/dev/dev01] parrt% cvs checkout -r dev01 http
cvs checkout: Updating http
U http/T.java
U http/U.java
[jazz:projects/Server/dev/dev01] parrt% cd http
[jazz:Server/dev/dev01/http] parrt% cvs status
cvs status: Examining .
===================================================================
File: T.java           	Status: Up-to-date

   Working revision:	1.2	Wed Sep 11 22:37:55 2002
   Repository revision:	1.2	/var/data/cvsroot/http/T.java,v
   Sticky Tag:		dev01 (branch: 1.2.2)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: U.java           	Status: Up-to-date

   Working revision:	1.1	Wed Sep 11 22:37:29 2002
   Repository revision:	1.1	/var/data/cvsroot/http/U.java,v
   Sticky Tag:		dev01 (branch: 1.1.2)
   Sticky Date:		(none)
   Sticky Options:	(none)

[jazz:Server/dev01/http] parrt% vi T.java
[jazz:Server/dev01/http] parrt% cvs commit
cvs commit: Examining .
Checking in T.java;
/var/data/cvsroot/http/T.java,v  <--  T.java
new revision: 1.2.2.1; previous revision: 1.2
done
[jazz:Server/dev01/http] parrt% cvs diff T.java
[jazz:Server/dev01/http] parrt% cd /tmp/projects/Server/main/http
[jazz:Server/main/http] parrt% cvs update
cvs update: Updating .
[jazz:Server/main/http] parrt% cvs status
cvs status: Examining .
===================================================================
File: T.java           	Status: Up-to-date

   Working revision:	1.2	Wed Sep 11 22:37:49 2002
   Repository revision:	1.2	/var/data/cvsroot/http/T.java,v
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

===================================================================
File: U.java           	Status: Up-to-date

   Working revision:	1.1	Wed Sep 11 22:37:11 2002
   Repository revision:	1.1	/var/data/cvsroot/http/U.java,v
   Sticky Tag:		(none)
   Sticky Date:		(none)
   Sticky Options:	(none)

[jazz:Server/main/http] parrt% cvs update -j dev01
cvs update: Updating .
RCS file: /var/data/cvsroot/http/T.java,v
retrieving revision 1.2
retrieving revision 1.2.2.1
Merging differences between 1.2 and 1.2.2.1 into T.java
[jazz:Server/main/http] parrt% javac *.java # and test
[jazz:Server/main/http] parrt% cvs commit
Checking in T.java;
/var/data/cvsroot/http/T.java,v  <--  T.java
new revision: 1.3; previous revision: 1.2
done
[jazz:Server/main/http] parrt% cd /tmp/projects/Server/dev/dev01
[jazz:Server/dev/dev01] parrt% cvs release http
[jazz:Server/dev/dev01] parrt%