CS 235 Advanced Operating Systems, Winter 2008CVS HintsYou'll be developing enough software in this course that it's worth your time to learn a source code management (SCM) system, which lets you track versions of your source files over time, branch development, and merge changes between branches. This page provides a quick, CS 235-centric introduction to the most widely used open-source SCM, CVS, the Concurrent Versions System. (But you can use whatever source code management system you'd like; some other popular choices include Subversion, Perforce [commercial], BitKeeper [commercial], and GNU Arch.) What is source code management?A source code management system isn't just about source code. Think of it as a file system with explicit versions. The SCM stores the current version of your files, but it also stores every previous version of your files, back to the very first version you entered. Commands called checkouts let you create copies of the current version of the code, or any previous version. The versioning is explicit because you must explicitly tell the SCM to store a new version of a file; this is called committing the file. There are a lot of reasons this is a good idea! If you mess up some code, you can go back to a previous version. You can see what your code looked like on a previous date, and compare it with today's code. You can tag a particular version with a name, and you can even maintain several branches of the code. A branch is a set of versions that develops independently. For example, after a major product release, the source code is often branched into a "release branch". This means that the main line of source development, which is called the "main trunk" or "mainline", can evolve independently from the release, and updates such as new features won't destabilize the release branch. If bugs are found in the release, they are fixed on the release branch as well as mainline. Another use for branching is to let several developers evolve the code independently, then merge their changes when they're ready. Large-scale software development often uses this branch-and-merge model. In CS 235, you'll use a branch-and-merge model with two branches: mainline, your version of the code, and a vendor branch that contains our original lab files. Setting up a CVS repository for Lab 1The first step is to decide where your CVS repository will go. This is the place where CVS will store all the old versions of your files. If you're doing all your work on SEASnet, use your SEASnet home directory; if you're doing your work on a home computer, put it there. Whichever home directory you choose, we suggest you put your CVS repository in ~/cvsroot (a cvsroot subdirectory of your home directory). Then tell CVS where to find the repository:
(If you're not sure which kind of shell you're using, try the tcsh version on the left. If it fails with an error like "bash: setenv: command not found", use the bash version on the right.) This sets the environment variable CVS uses to find your repository. We suggest putting this statement in your login files (.tcshrc or .bashrc, respectively) so you don't have to type it over and over again. Then tell CVS to initialize the repository:
% cvs init
You can look in the repository if you'd like; there's not much going on.
% ls ~/cvsroot
CVSROOT
Now it's time to download our lab1.tar.gz tarball and add it to the repository. We use the gzcat and tar programs to unpack the lab code, then the cvs import command to add it to our new repository. % gzcat lab1.tar.gz | tar xf - % cd lab1 % ls CODING GNUmakefile boot conf grade.sh inc kern lib mergedep.pl % cvs import -m "lab1 import" jos LAB LAB1 N jos/mergedep.pl N jos/GNUmakefile N jos/.bochsrc ... N jos/boot/Makefrag N jos/boot/boot.S N jos/boot/main.c No conflicts created by this import (If you use GNU tar, you can just say "tar xzf lab1.tar.gz" in the first step.) Let's take apart the cvs import command, which is where all the magic happens.
What's going on inside the repository? % ls ~/cvsroot CVSROOT jos % ls ~/cvsroot/jos CODING,v boot grade.sh,v kern mergedep.pl,v GNUmakefile,v conf inc lib All the files from the lab1 directory have versions in ~/cvsroot/jos, but don't edit the weird ,v files directly; that would mess up the versioning. Instead, check out the jos module to create a working copy. % cd ~ % cvs co jos U jos/.bochsrc U jos/CODING U jos/GNUmakefile ... U jos/lib/printfmt.c U jos/lib/readline.c U jos/lib/string.c % ls jos CODING CVS GNUmakefile boot conf grade.sh inc kern lib mergedep.pl The CVS co command stands for "checkout". You specify the name of a module to check out, which in this case is jos. CVS then extracts a working copy of the software from the repository (by default the latest version on mainline, but you can specify other branches or versions with the -r flag). It creates a directory called jos containing that working copy. Go ahead and browse the directory. It looks exactly like the contents of the lab1 tarball, except that there are extra directories called CVS where CVS keeps some extra information about what exactly you have checked out. You shouldn't ordinarily mess with the contents of CVS directories. Making changesYou've now imported your code into a CVS repository, and checked out a working copy of the repository code. There's no need for the lab1 directory any more, so go ahead and remove that. All of your edits for the lab should take place within the jos working copy. So say you got some work done on the kern/monitor.c source file, and you'd like to commit a version of that file back in to the repository. Here's how. From inside the jos directory:
% cvs ci -m 'mon_backtrace() improvements'
Checking in kern/monitor.c;
/home/kohler/cvsroot/jos/kern/monitor.c,v <-- monitor.c
new revision: 1.2; previous revision: 1.1
done
As before, the -m option supplies a checkin message; if you'd left it off, CVS would have put up an editor. Use the cvs diff command to compare two different versions of the code. For example, let's see how my mon_backtrace() compares with the original version I imported as LAB1.
% cvs diff -u -r LAB1
Index: kern/monitor.c
===================================================================
RCS file: /home/kohler/foo/jos/kern/monitor.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -u -r1.1.1.1 -r1.2
--- kern/monitor.c 3 Oct 2005 05:38:25 -0000 1.1.1.1
+++ kern/monitor.c 3 Oct 2005 06:18:59 -0000 1.2
@@ -59,6 +59,9 @@
mon_backtrace(int argc, char **argv, struct Trapframe *tf)
{
// Your code here.
+
+ /* Code code code code code code code code! */
+
return 0;
}
The options are:
Some other CVS commands you need to know about:
Updating labsWhen we release another lab -- or a lab bugfix -- you'll import the new lab sources into your vendor branch. In the rest of this section, we'll assume you're updating from Lab 1 to Lab 2, and want to merge your solutions with our updates, but the same principles will apply elsewhere. Here's what it will look like graphically: +------+ Mainline +--> work on -->| SOL1 |---+---> merged -->... | Lab 1 +------+ | | | +------+ +------+ Vendor branch | LAB1 |------------------>| LAB2 | (-r LAB) +------+ +------+ The first step is to make sure your changes are checked in to the
repository with The actual import uses the same command as for the initial checkin, but
with a different tag. To incorporate % gzcat lab2.tar.gz | tar xf - % cd lab2 % cvs import -m "lab2 import" jos LAB LAB2 U jos/mergedep.pl U jos/GNUmakefile U jos/.bochsrc ... N jos/kern/trapentry.S C jos/kern/monitor.c U jos/kern/console.c U jos/kern/COPYRIGHT ... U jos/boot/boot.S U jos/boot/main.c 1 conflicts created by this import. Use the following command to help the merge: cvs -d /home/kohler/cvsroot checkout -j The There's also a conflict: Change into your updated working copy directory and use the update
command to merge the vendor branch's changes. As CVS suggested, we'll
supply two tags to the % cd ~/jos % cvs up -Pd -jLAB1 -jLAB2 grade.sh already contains the differences between 1.1.1.1 and 1.1.1.2 conf/lab.mk already contains the differences between 1.1.1.1 and 1.1.1.2 inc/trap.h already contains the differences between creation and 1.1.1.1 kern/init.c already contains the differences between 1.1.1.1 and 1.1.1.2 kern/kclock.c already contains the differences between creation and 1.1.1.1 kern/kclock.h already contains the differences between creation and 1.1.1.1 RCS file: /home/kohler/class/ujos/cvsch_cvsroot/jos/kern/monitor.c,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.2 Merging differences between 1.1.1.1 and 1.1.1.2 into monitor.c kern/pmap.c already contains the differences between creation and 1.1.1.1 kern/pmap.h already contains the differences between creation and 1.1.1.1 kern/trap.c already contains the differences between creation and 1.1.1.1 kern/trap.h already contains the differences between creation and 1.1.1.1 kern/trapentry.S already contains the differences between creation and 1.1.1.1 lib/readline.c already contains the differences between 1.1.1.1 and 1.1.1.2 user/testpmap.c already contains the differences between creation and 1.1.1.1 Now take a look and see if any of the files have changed.
% cvs up
M kern/monitor.c
CVS has merged changes into Sometimes, though, CVS will not know how to resolve a difference between
the two branches. It reports this as a conflict during
% cvs up
C kern/monitor.c
You must resolve these conflicts by hand. CVS changes the conflicted file to show you both versions. Combine them as appropriate, remove the conflict markers, and check in the result. Here's an example conflict: // Simple command-line kernel monitor useful for // controlling the kernel and exploring the system interactively. #include <inc/stdio.h> #include <inc/string.h> #include <inc/memlayout.h> #include <inc/assert.h> #include <inc/x86.h> #include <kern/console.h> #include <kern/monitor.h> #include <kern/kdebug.h> <<<<<<< monitor.c #include <inc/string.h> ======= #include <kern/trap.h> >>>>>>> 1.1.1.2 #define CMDBUF_SIZE 80 // enough for one VGA text line struct Command { ... The red lines are the conflict markers. The
// Simple command-line kernel monitor useful for // controlling the kernel and exploring the system interactively. #include <inc/stdio.h> #include <inc/string.h> #include <inc/memlayout.h> #include <inc/assert.h> #include <inc/x86.h> #include <kern/console.h> #include <kern/monitor.h> #include <kern/kdebug.h> #include <inc/string.h> #include <kern/trap.h> #define CMDBUF_SIZE 80 // enough for one VGA text line struct Command { ... Then check in the result. Although this was a particularly simple conflict to resolve, the principles are the same even for far more complex conflicts. For more informationSee the CVS "Cederqvist" manual, also available in GNU info on most Unix systems that have CVS installed. This page will be updated with more information as the quarter progresses. Written with the help of David Mazières's version |