Basic Version Control Functions
*******************************

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 Projects
==================

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.

Creating a New Project
======================

Initializing the Project
------------------------

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

Adding Members
--------------

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.

Adding the Administrator as a Member
....................................

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 Regular Project Members
..............................

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.

 1. Alice, gives the project ID (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.

 2. Bob creates his personal key pair and his member block for the project using the 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

 3. Bob gives his user ID (mTUZtKNHGFrs8wzKtqrARIEb6OQ) and a user name of his choosing (bob) to Alice via email.

 4. Alice adds Bob's user name and ID to the project list with the "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.

One member with multiple computers
..................................

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.

Importing The First Project Files
---------------------------------

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

Making Changes
==============

Checking out a Working Copy
---------------------------

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

Editing Files
-------------

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.

Committing Changes
------------------

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

Adding New Files
----------------

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
--------------

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

Getting Diffs
=============

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

Updating the Working Copy
=========================

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

Anonymous Checkout
==================

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

Disconnected Operations
=======================

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.

Ignoring Files
==============

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).