Spin Versioning and Branching With CVS


Click here if you just want to know how merge your stuff in.

Table of Contents

Getting started with CVS

CVS is in the contrib bin directory.
To use it, make sure you have this directory in your path.
Also, make sure that you set the CVS root directory in your CVSROOT environment variable.
Not doing this will make most commands fail.
man pages
The man pages are in the contrib man page directory (add that to your MANPATH).

Using CVS

The latest greatest SPIN source tree resides in the CVS trunk. The trunk is the version of our files that are checked out by default, ie. no branch is specified. But in general, we never get code (checkout) direct from the trunk.

SPIN development always takes place on branches from the trunk to allow concurrent development. Each developer starts out with a private copy(branch) of the source tree. A branch can be modified without interfering with any other branch. At regular intervals all the work in the branches is merged together to form a new trunk.

Making your branch

The first step in this development environment is creating your own branch of code on which to work. Remember to set the environment variable CVSROOT to /afs/cs/project/spin/cvsroot. Create a branch with a command following this form
	cvs rtag -r spin-4 -b s4-becker spin

s4-becker will be the name of this branch (often the name is, confusingly, called a tag in the cvs docs). This is the naming convention for branches

sVersionNumber-User

Getting your code tree is a seperate step from creating your branch. This command checks out a tree in the subdir spin in the current directory.

	cvs checkout -r s4-becker spin

This is your own tree you can freely change. Each file is backed by an RCS file in CVSROOT. To restore a file to its checked out condition, remove it and restore it with update.

	rm file
	cvs update file

Branches must be created from the new trunk after every merge.

Tags versus Branches

Most cvs operations have a "-r rev" option where rev can be either a branch or a tag. Both branches and tags represent RCS labels stored in the RCS headers in the repository RCS files. It is CVS, not RCS, that intreprets the labels to mean tags or branches.

A branch is a lineage created by cvs tag -b file

A tag is a freeze marked by cvs tag file

Use 'cvs stat -v file' to examine the branches and tags for "file" stat -v shows these labels for mk/kernel/alpha/trap.c:

	r4-loipc                        (branch: 1.3.2)
        release-4                       (revision: 1.3)
        r3-merge                        (revision: 1.3)
        release-3                       (revision: 1.1.1.2)
        release-2                       (revision: 1.1.1.1)
        release-1                       (revision: 1.1.1.1)
        origin-branch                   (branch: 1.1.1)
						.
					       /|\
						|
				"revision:" is a tag.  "branch:" is a branch.
Checkout by tag release-3 will retrieve version 1.1.1.2
	cvs checkout -r release-3 mk/kernel/alpha/trap.c
Checkout from branch r4-loipc will retrieve 1.3.2.x where x is the latest version on that branch.
	cvs checkout -r r4-loipc mk/kernel/alpha/trap.c 

Distributing code from your branch

As frequently as every two days, we may merge the branches into a new trunk. To contribute your code to the trunk, or to distribute it to other branches, it must be commited and tagged.

You may commit to the RCS files in CVSROOT as often as you want. cvs commit corresponds to the RCS ci command. A commit is a good way to preserve a file before experimenting with a radical change. You can always restore previous versions using cvs update as described above.

In your working directory, commit files with a command of this form

	cvs commit -m "log message" files/dirs
You can commit individual files or entire directories. Directories are committed recursively unless you use the -R flag. The message goes into the $Log: index.html,v $ The message goes into the Revision 1.2 1996/09/13 22:39:16 rgrimm The message goes into the Fixed links. The message goes into the The message goes into the Revision 1.1 1996/06/11 21:44:51 bershad The message goes into the New doc structure. The message goes into the area and RCS log of each file commited. If the message is omitted, commit will start an editor so you can enter the log message. Read log messages with cvs log file.

In the top direcotry, make a tag with a command of this form

	cvs tag s4-becker-apr1 spin
The tag command puts a label in every RCS file to identify the revision that corresponds with the file in your branch.

When your branch is committed and tagged, advertise that tag to the merger or others interested in picking up your code.

What update and checkout do

Update and checkout (alias get) are often interchangeable, hence confusing. They will modify your tree, but never ever delete files that are modified. Modified (uncommitted) files are reported as "M filename" and are not deleted.

cvs update -r branch will replace your branch with branch adding and deleting files to make the tree look like branch.

cvs update -j branch will merge the diffs between branch and the trunk into your tree. Previously modified files are affectd as well as untouched parts of your branch. No files will be added or deleted. When branch has new files, you must add those files to your branch with tag -b and update -r as usual.

if you want your file to be updated from the trunk type "cvs upd " if you want to update it and move it back from your current branch to the trunk type "cvs upd -A " you do not have to remove the file to do it

Shortcuts

The SPIN tree is large so whole tree commands can take 15 minutes. To save time, you can apply the commands discussed so far to just the code subtrees your are interested in, such as only sal and sys. In particular the gdb part of the tree is very large and often untouched.

One option for major subtrees, is to branch and checkout everything, then rm -rf subtree. Then cvs commands will ignore that subtree.

Working on subtrees can speed up cvs ops but there are caveats. Be sure you, and anyone you hand tags to, knows you are not working on a complete tree.

Doing cvs operations after the fact on parts of the tree you did not expect to change can be very time consuming and frustrating. A good way to stay aware of the CVS status of your branch is with this command

	cvs update -q dirs
The update command will report files in dirs that cvs does not know about and report the modifications that have not been commited. The list it generates displays these code characters next to the filenames.
M Modified and not commited.
A Added and not commited.
R Removed and not commited.
? New unknown file. Possibly needs to be added.

Adding new files

To add a new file to the cvs system, first create the file. Then add it to the trunk with this sequence
	create file
	cvs add file
	cvs update -A file
	cvs commit file
And add the new file to your branch
	cvs tag -b s4-becker file
	cvs update -r s4-becker file
Other people can add the new file to their branch the same way
	cvs rtag -b s4-savage spin/path/file
	cvs update -r s4-savage file

Adding new directories

Add a new directory with these commands
	mkdir dir
	cvs add dir
	cvs update -A dir

Removing obsolete files

Remove a file from future versions of the trunk with these commands
	cvs update -A file
	rm file
	cvs remove file
	cvs commit file
The file remains in CVSROOT so older versions of the trunk can be recreated. It also remains in the current branches until the next branch off the next trunk. To remove files from current branches, use this sequence
	cvs tag -d s4-becker file
	cvs update file

Reorganizing the tree

This is CVS's major weakness. Renaming files or directories, or moving files around in the tree can be done, but is a pain, and is not for the faint of heart. At merge time, when no branches exist, in CVSROOT copy the RCS files from the old name or location to the new name. Use the normal cvs remove commands to delete the file with old name.

Merging Tags into Your Branch

Merging is best left to the merger who creates new trunks, but on occasion you just can't wait. It is important to keep track of what tags you have merged into your branch and tell the merger what tags you have picked up. The simplest scenario is where you never distributed a tag or merged any tags into your branch. More complex scenarios require careful tracking of who has merged what where. File adds and removes must also be tracked by hand.

Suppose you want to merge s4-becker-apr1 into your branch. Further you know that s4-becker-apr1 has had no other tags merged into it and you have not merged anything else into your branch. Merge with a command of this form

	cvs update -j spin-4 -j s4-becker-apr1 spin
The update -j (for join) applies the diffs it finds between spin-4 and s4-becker-apr1 to all the files in the spin tree. The actual merging is done with rcsmerge and diff3.

Now suppose s4-becker-apr15 is announced and you need to again merge it into your branch. Merge with a command of this form

	cvs update -j s4-becker-apr1 -j s4-becker-apr15 spin
This will merge into your code only the differences between the april 1 tag and the april 15 tag. This avoids applying the spin-4 to april1 mods yet again. Those would be duplicate changes/conflicts and you would have to go edit the conflicts out.

When you have modified a patch of code yourself and then merge someone elses change to that same code, a conflict results the automatic tools cannot resolve. Both versions of that patch of code will appear in the merged file marked with banner lines like this

	<<<<<<< filename
	your existing version of code segment
	=======
	version form the tag being merged (tag happens to be version 1.7 of filename)
	>>>>>>> 1.7
Search for the banner lines with grep and resolve them by hand.


becker@cs.washington.edu
November 24, 1995