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
The 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
yKSwpZkikKz+reTV9z2a28W2F5Y
.
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
$PASTWATCH_ROOT/myproject/project.key
.
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.
CVS Equivalent:
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
file: key.iFUG7VF60eLb10b2awUBgw-GKL0
.
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 join
command. This command generates a key
pair and writes the key to
$PASTWATCH_ROOT/myproject/member.mTUZtKNHGFrs8wzKtqrARIEb6OQ
along
with the project ID in $PASTWATCH_ROOT/myproject/project.id
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
the project.
CVS Equivalent: Give Bob an account on a server, and make sure he can write
to /home/alice/CVSRepository
.
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.
The 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
project.
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
directory: initial_files
. First, Bob cd
's into
initial_files
and then calls past import
:
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.
CVS Equivalent:
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
CVS Equivalent:
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 file
.
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
CVS Equivalent:
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
CVS Equivalent:
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
repository.
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
CVS Equivalent:
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: "past diff
[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 -t
flag.
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 Equivalent:
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 "past update
"
command to retrieve the latest version from the repository. past
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
CVS Equivalent:
cvs update
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 past
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
patterns in .pastwatchignore
. Each line in
.pastwatchignore
contains either an exact file name or a pattern
like *.o
(match all files ending with .o
).
Go to the first, previous, next, last section, table of contents.