This chapter describes how to perform basic version control functions using Pastwatch in more detail. The description is geared towards users who are familiar with other version control systems like CVS. To help with the transition to Pastwatch, we'll try to give a similar CVS command where applicable. Throughout this chapter, we illustrate the concepts with an example project named myproject which has one administrator named Alice and two developers named Bob and Cliff.
Pastwatch performs version control for projects. Each Pastwatch project has a number of project members and one project administrator. Each project also has a file system directory that is under version control. The following illustration shows the parts of a Pastwatch project:
This Pastwatch project currently contains three files and one subdirectory. The administrator is named Alice and the two project members are Bob and Cliff. As project members, Bob and Cliff can add, remove and edit the project files. As administrator, Alice may add new members to the project.
Pastwatch uses public key authentication, so the project administrator and project members each have their own individual key pairs. The administrator uses her secret key to alter the list of project members. A project member may have one or more local replicas, one for each computer he uses. Each local replica has a key pair that pastwatch uses to commit changes to the repository. Each project member uses a member key pair to add local replica keys to their person list of replicas.
Each Pastwatch project stores one project. For example, if you were developing two separate pieces of software: a word processor and web browser, each would be stored in a separate Pastwatch project. Each Pastwatch project contains a single logical project. This is different from CVS because you can store many different software projects in a single CVS repository.
pastctl is a utility that helps administrate Pastwatch projects.
The command "
pastctl create <projname>" creates a new
administrator key pair and an empty project with the new key pair. The
project has no members, and contains no data. For example, to create a
new project named myproject, Alice would execute the command:
alice% pastctl create myproject Creating new key: project.key.48859#1 (Rabin) Key Label: myproject wrote key: /tmp/project.key.48859 new project ID: yKSwpZkikKz+reTV9z2a28W2F5Y
pastctl output says that the new project is labeled
myproject and its project ID is:
yKSwpZkikKz+reTV9z2a28W2F5Y. myproject is just a label
for the project. The real identifier for the project is
The project ID is an important value. Pastwatch must have the project
ID to read the project repository. Luckily, Pastwatch users do not need
to memorize the project ID. It is stored as the symlink:
$PASTWATCH_ROOT/myproject/project.id. The secret key which
allows Alice to add project members is written to
alice% ls -l $PASTWATCH_ROOT/myproject total 2 lrwxr-xr-x 1 alice wheel 32 Mar 16 10:20 project.id -> project:yKSwpZkikKz+reTV9z2a28W2F5Y -rw------- 1 alice wheel 602 Mar 16 10:20 project.key
Since Pastwatch uses the project ID to name the repository, the project label is not very significant. Pastwatch only uses the project label as a place to store the project ID. Another person may create another project with the same label and their project will not conflict with Alice's project. This is because their project identifier will be randomly chosen and thus unique.
It is safe to ignore the rest of the
pastctl create output.
alice% mkdir /home/alice/CVSRepository alice% cvs -d /home/alice/CVSRepository/ init
Only project members may make changes to files in a Pastwatch project's repository. It is the project administrator's responsibility to add members to the project. The project administrator is not a project member by default; she must add herself as a member if she wants to make changes to the repository files.
In our example, Alice is the project administrator. To add herself as a
project member, she uses the "
pastctl addmember" command. This command
generates a member key pair for Alice and adds her as a project member.
The hash of Alice's member public key is
iFUG7VF60eLb10b2awUBgw-GKL0, and the secret key is stored in the
alice% pastctl addmember alice myproject Creating new key: member.key.12378#1 (Rabin) Key Label: myproject wrote key: /tmp/member.key.12378 new member: alice, iFUG7VF60eLb10b2awUBgw-GKL0 alice% ls -l $PASTWATCH_ROOT/myproject total 4 -rw------- 1 alice wheel 607 Mar 16 10:22 member.iFUG7VF60eLb10b2awUBgw-GKL0 lrwxr-xr-x 1 alice wheel 32 Mar 16 10:20 project.id -> project:yKSwpZkikKz+reTV9z2a28W2F5Y -rw------- 1 alice wheel 602 Mar 16 10:20 project.key
Adding subsequent project members is slightly more complex because the project administrator should not generate the key pair for the new member (otherwise, she would have the new member's secret key). This procedure is best explained with an example. In our example, Alice needs to add Bob as a project member.
yKSwpZkikKz+reTV9z2a28W2F5Y) to Bob; the project ID is not confidential information, so she can freely e-mail it or post it on a web site.
pastctl joincommand. This command generates a key pair and writes the key to
$PASTWATCH_ROOT/myproject/member.mTUZtKNHGFrs8wzKtqrARIEb6OQalong with the project ID in
bob% pastctl join -P yKSwpZkikKz+reTV9z2a28W2F5Y myproject Creating new key: member.key.48955#1 (Rabin) Key Label: myproject wrote key: /tmp/member.key.48955 give mTUZtKNHGFrs8wzKtqrARIEb6OQ and a member name to project administrator bob% ls -l $PASTWATCH_ROOT/myproject total 2 -rw------- 1 bob wheel 615 Mar 16 10:28 member.mTUZtKNHGFrs8wzKtqrARIEb6OQ lrwxr-xr-x 1 bob wheel 32 Mar 16 10:28 project.id -> project:1k6wxTsgGGxV+1ifLnAmSAR3n9E
mTUZtKNHGFrs8wzKtqrARIEb6OQ) and a user name of his choosing (
bob) to Alice via email.
pastctl addmember -k <userID> <username> <projname>" command.
alice% pastctl addmember -k mTUZtKNHGFrs8wzKtqrARIEb6OQ bob myproject new member: bob, mTUZtKNHGFrs8wzKtqrARIEb6OQ
As the project grows, Alice can add more members. If Cliff needs to
join the project, he generates a key pair with
pastctl join and
passes his user ID to Alice. Alice adds Cliff's user ID using
pastctl addmember. Bob does not need to do anything when Cliff joins
CVS Equivalent: Give Bob an account on a server, and make sure he can write
Each pastwatch member may have several computers they edit the repository on. Each one of those computers will have a local replica of the repository and thus it will have its own key in the project. This key is called a logkey for reasons we explain later.
A member must copy his memberkey to the new computer to create the new logkey: the member should copy the $PASTWATCH_ROOT/projlabel directory from a computer that already has a replica, to the new computer. This directory contains the project ID and the memberkey.
The first time the member uses pastwatch on the new computer, pastwatch will create a new logkey pair for the new computer and it will ask the member to provide a label for the new logkey. By default, pastwatch chooses the username and hostname to label the logkey.
After you create a project, you will need to import an initial set of files. Each Pastwatch project performs version control on a directory structure, so the initial files must be in a directory hierarchy to begin with. The initial directory can contain files and subdirectories or it can be empty if there are no initial files.
past import command creates a new Pastwatch module and adds a
set of new files to the module. The Pastwatch module name is the
default directory name that Pastwatch creates when checking out the
To import files into a new project, use the
past import command:
past -p <projectID|label> import -m <message> modulename"
In our example, Bob is importing an initial set of files in the
initial_files. First, Bob
initial_files and then calls
bob% cd initial_files bob% past -p myproject import -m "Initial Import" myproject pastwatch: Creating a new log key and log for this replica. pastwatch: Member block currently has 0 entries: pastwatch: sfscd not running, limiting sources of entropy Creating new key: bob@workstation Key Label: bob@workstation [press enter] pastwatch: no replica, building from scratch pastwatch: root of branch tree CmWnm2V8RFM3gsHfzykZV3QdVSM pastwatch: new snapshot: +yj0Ms0agxAut-QE-7CqvS+hihc, 1 deltas. For commit record: CmWnm2V8RFM3gsHfzykZV3QdVSM pastwatch: Using branch head: CmWnm2V8RFM3gsHfzykZV3QdVSM N ./README N ./main.c N ./util/util.h pastwatch: committing pastwatch: new snapshot: p11hVWvD1aVi2NK3BKfTd4zG5ww, 16 deltas. For commit record: 36avpSpKHLBTasIsWeYLU63GeCE
Note that pastwatch automatically created a logkey for Bob on his workstation.
bob% cvs -d /home/alice/CVSRepository import myproject bob release_0_1
To make changes to an existing project, you must first checkout a
working copy of the project to your local disk. You can then
edit your working copy directly and commit changes from your working
copy into the repository. To checkout a working copy, use the
past -p <projectID|label> checkout [-d <dir>] modulename" command.
In our example, Bob checks out a working directory using this command:
bob% past -p myproject checkout myproject pastwatch: Using branch head: 36avpSpKHLBTasIsWeYLU63GeCE D myproject D myproject/util U myproject/README U myproject/main.c U myproject/util/util.h
bob% cvs -d /home/alice/CVSRepository checkout myproject
Once you have a working copy, you can directly edit the files in the working copy without affecting the project repository. When you are satisfied with your changes, you can commit the changes to the repository.
To commit changes to the repository, use the "
past commit -m
message file" command.
past commit creates a new version in the
repository with the new contents of
In our example, Bob edits the
README file and commits his
changes to the repository.
bob% echo "By Bob" >> README bob% past commit -m "Added by-line" README pastwatch: Using branch: init pastwatch: Using branch head: W0cSwdqsifZI9fbdHait55FnciA pastwatch: checking for updates and conflicts pastwatch: updating . M README pastwatch: committing in README Committing README pastwatch: committing pastwatch: new snapshot: spwN1PisR-r6XXq1W6IzmQs4Et0, 1 deltas. For commit record: bw2jr5Rjl17YM0j78ncEAgXnjxo
bob% cvs commit -m "Added by-line" README
To add a new file to the repository, first create the file in the
working copy and then use the "
past add file" command to mark the
file for adding during the next commit.
In our example, Bob creates the file
util/util.C and adds it
to the repository.
bob% touch util/util.C bob% past add util/util.C pastwatch: Using branch: init pastwatch: Using branch head: bw2jr5Rjl17YM0j78ncEAgXnjxo bob% past commit -m "Added util.C" util/util.C pastwatch: Using branch: init pastwatch: Using branch head: bw2jr5Rjl17YM0j78ncEAgXnjxo pastwatch: checking for updates and conflicts pastwatch: updating util.C A util/util.C pastwatch: committing in util/util.C N util/util.C pastwatch: committing pastwatch: new snapshot: lhVzVYEUu2A+nLimh6gqoFnspLg, 3 deltas. For commit record: MroX1c5g3AHo4CK2lpcMLRoll-4
bob% touch util/util.C bob% cvs add util/util.C bob% cvs commit -m "Added util.C" util/util.C
Removing files from the repository is very similar to adding new files.
First, remove the working copy of the file, then mark the file for
removal using the "
past remove file" command. Finally, commit
the removal to the repository.
In our example, Bob removes the file
util.h from the project
bob% rm util/util.h bob% past remove util/util.h pastwatch: Using branch: init pastwatch: Using branch head: MroX1c5g3AHo4CK2lpcMLRoll-4 bob% past commit -m "Removing util.h file" util/util.h pastwatch: Using branch: init pastwatch: Using branch head: MroX1c5g3AHo4CK2lpcMLRoll-4 pastwatch: checking for updates and conflicts pastwatch: updating util.h R util.h pastwatch: committing in util.h Removing util.h pastwatch: committing pastwatch: new snapshot: gZnzm7PHsBndp7sft5cuBzZuiqA, 1 deltas. For commit record: TQGFXXwtzCo+tvIYsz0+9TOh0yY
bob% rm util/util.h bob% cvs remove util/util.h bob% cvs commit -m "Removing util.h file" util/util.h
Pastwatch can calculate diffs between different versions in the
repository or between a repository version and the working copy. To
calculate a diff, use the command: "
[rep_version1] [rep_version2] [file]".
You may select zero, one or two repository versions when performing a diff. If you select zero old versions, pastwatch will compare the working copy with the parent repository version. If you select one old version, Pastwatch will compare the working copy with the specified old version. If you select two old versions, Pastwatch will compare the two old versions from the repository.
You may specify the repository versions in three different ways. You
can specify a date with the
-D flag, a revision number with the
-r flag or a version tag with the
In our example, Bob wants to see what changes were made between 03/28/05 16:11:53 and 03/29/05 10:12:20 to the README file.
bob% past diff -D '03/28/05 16:11:53' -D '03/29/05 10:12:20' README pastwatch: Using branch: init pastwatch: Using branch head: TQGFXXwtzCo+tvIYsz0+9TOh0yY File: README =============================================== diff -t bob@workstation:2 bob@workstation:3 README 0a1 > By Bob
cvs diff -D '03/28/05 16:11:53' -D '03/29/05 10:12:20' README
Often, the working copy will become out of sync with the latest
repository version. Project members use the "
command to retrieve the latest version from the repository.
update retrieves the latest changes and applies them to the working
copy, but it does not remove the local changes made to the working copy.
In our example, Cliff commits a change to
README and Bob
wants to incorporate Cliff's changes into his working copy.
bob% past update pastwatch: Using branch: init pastwatch: Using branch head: Tm1WS+SoPtIqbw-Ub+X5QRLoTp0 pastwatch: updating . U README pastwatch: updating util
Pastwatch supports a read only mode, so that people who are not project
members may download the project source code and keep up to date with
new revisions. To use anonymous mode, users can use the
command without having a member key.
daniel% past -p yKSwpZkikKz+reTV9z2a28W2F5Y checkout myproject
Each project members stores a local replica of the repository on their local disk in a unique data structure called a branch tree. The branch tree allows Pastwatch users to read and write to the repository even when they are disconnected from the other users.
Pastwatch inspects all the files in the working directory when
performing updates and other operations. If there are some files that
will not be added to the project, you may list them in the
.pastwatchignore file in the working directory. Pastwatch will
ignore any files listed in
.pastwatchignore and files that match
.pastwatchignore. Each line in
.pastwatchignore contains either an exact file name or a pattern
*.o (match all files ending with
Go to the first, previous, next, last section, table of contents.