CVS (concurrent version system)


CVS is a version control system that allows projects to be checked out, changed, and merged back into a release directory.

CVS is used at the Keck observatory to retrieve and replace changes to observatory software.

There are numerous functions of which CVS is capable. The following sections attempt to present those functions in increasing complexity. Thus the first section will be that which most users will find useful. If you find that you are attempting something
beyond the 'basics' then it is probably addressed in one of the addtional major sections.

There is a tkcvs gui based interface to CVS which is a future topic. This page does not currently address tkcvs as there are issues involved when using it from a remote site (not on the Keck intranet). However, once you are familiar with the command line based CVS interface, as described herein, you will find tkcvs very convenient for manipulating files at Keck (I urge the instrument specialists to use tkcvs).
 

1   Common file operations typically performed by a user

Most users are interested in a limited number of file maintenance functions provided by CVS. Typically the user will want to: store recent changes; retrieve the most recent version of a file;  determine if someone else has modified a file; merge ones changes with someone elses changes; retrieve a previous version of a file; add a new file into CVS; and occassionally remove a file from CVS. This section discusses how to perform the aformentioned file operations.

Most of the examples in this section refer to 'test.doc'  which is a file contained in the instrument ~/cvs_test_dir directory for all instruments (or will be in the near future). The intent is that you, the reader, can perform the examples as you read them.

This document does not attempt to define all variations of all CVS commands. Once you have learned the basics for a CVS command you can use the '-H' option to view the variations for a given command. For instance:

            cvs commit -H

would display the various command options for the commit command which is discussed in the next section.
 

1.1 Commit command - saving the changes made to a file

The CVS commit command is used to save a file in CVS. Historically users have used two different technigues for saving a file prior to modifying it: create a backup directory and copy the original into that directory; or copy the file to one with a date tag suffix. With CVS the user can eliminate this step of the process and be assured that CVS will not lose an old version of a file (at least one has to work very hard to perturb CVS). CVS also allows one to easily retrieve a previous version of a file if one changes their mind in regards to modfications (refer to section 1.8).

The following is a tutorial example which allows you to manipulate the test file, test.doc.

We will assume that the file is contained in a directory which is 'known' to CVS. One can usually determine if this is true by noting if a subdirectory called CVS exists (refer to section 2).

First one must descend into the directory containing the file to be modified. Again we make an assumuption, which is that the reader has logged into an instrument account so as to manipulate an instrument specific file.

        cd ~/cvs_test_dir                     [we assume the directory is in CVS]

Prior to modifying an existing file one would normally determine if the file has been modified by someone else. For this example we will assume that the file is currently upto date and we will simply perform the appropriate CVS command (handling differences and merging are discussed in other sections).

            cvs -n update test.doc                     [determine if the file is upto date]

If the file is upto date then there will be no CVS message and the command prompt will simply return.

If the file is not known to CVS then the response will be:

            ? test.doc

in which case you need to add the file to CVS as described in section 1.2.

If CVS returns any other response to the 'update' command  then the file is not upto date, however we will ignore this, as it is just a test file, so we will proceed with file modifications.

Modify the test.doc with your favorite editor. I suggest you add a new line to the bottom of the file which includes your initials and the date.

Now we will direct CVS to store the modified file:

            cvs commit -m"modfied during tutorial" test.doc

If you do not add the remark with the '-m' option then CVS will pop-up a 'vi' edit session. I typically use the command line option for single line mods and use the vi session for any long explanations. If the commit command is successful then CVS will respond with something similar to:

            RCS file: /usr/local/cvsroot/k2nirc/cvs_test_dir/test.doc,v
            done
            Checking in test.doc;
            /usr/local/cvsroot/k2nirc/cvs_test_dir/test.doc,v  <--  test.doc
            initial revision: 1.1
            done

Note that a new revision number will be generated for each committed change to the file. You can experiment with this if you want by either adding yet another line or modifying the line you did add, then doing another commit.

The only other important note, in regards to the commit command, is that issuing the command without an explicit filename will cause all modified files in the directory to be committed. Of course all of those files will then have the same comment, which is sometimes appropriate when making a change to several files in support of a new instrument feature or some such, however it is advisable to ensure that files will not be committed that are being modified and tested by someone else within that same directory.
 

1.2   Add command - adding a new file to CVS

Occassionally one needs to create a new file and add it to the CVS repository.  This is relatively straight forward. Create the file as needed (and test it) then issue the cvs add command. I suggest a file like <your initials>.tst.

            cvs add <newfile>

The add command in itself is insufficient for adding a file to a CVS repository. In fact, the file is only noted within the context of the local directory and the repository has not been alterated. Granted if you perform an update (refer to section 1.3) the status for the file will indicate that it has been added, where correct interpretation of that status will indicate that the file has not yet been committed. Hence the next step is to commit the file as defined in section 1.1 above. This is a test directory so it is okay for you to perform the commit, in addition, we will investigate removing files in section 1.6.
 

1.3   Update command - updating to the most recent version of a file or reverting to an older version

One of the most important features of CVS is the ability for many people to modify a given file from any number of different accounts (hence the C meaning concurrent). The implication is that a given file in any of those accounts may not be upto date, that is, a newer version may exist in the CVS repository. The CVS command to retrieve any version of a file is update. The update command also provides status on the current state of a single file or all files in a directory. By default update will retrieve the latest version of a file provided that the local file is an unmodified older version.

We will go through several editting sessions in order to investigate the various status messages that can be generated with update.
 

1.3.1  Determining the current status of a local file

One form of the update command is to issue it in such a way that it reports what would be done but actually does nothing. Some people use the report only form to determine the current state of a file or files in a directory. The report only form allows one to: decide if they want to update an entire directory or only a single file; determine if a file needs to be added; determine if files need to be merged.

The report only form of the update command is:

    cvs -n update

This will show the current state of all files in a directory (multiple status lines with the status of one file per line).

To see the current state of a single file, the file name is appended to the update command. For instance:

    cvs -n update test.doc

will display the current state of test.doc.

There are several possibilities for the current state of a file. The following gives the potential statuses for a file. We will investigate each of these possibilities.

            ? test.doc                                [the file is not in cvs]
            M test.doc                              [the local copy of the file has been modified]
            A test.doc                               [the file has been added to CVS but not commited]
            U test.doc                               [the local copy is old]
            C test.doc                               [a conflict of modifications has occurred and the file needs correcting]

To test the update commands response to a file that is not in CVS simply 'touch junk' then 'cvs -n update'. The response for the new file should be:

            ? junk

Now edit test.doc again and add a line. The result from 'cvs -n update' will be:

            M test.doc

The 'M' status tag indicates that the local version of a file has been modified since it was last committed.

To investigate the 'A' status of a file it is necessary to create a new file and issue the add command for that file (as was done in section 1.2). Create a new file called junk then enter 'cvs add junk'.  Once again issue the update command and observe the status of:

            A junk

To undo the add we will issue the remove command which is discussed in section 1.6. For now simply 'rm' the file and then enter the command as shown.

            cvs remove -m"removing temporary file" junk

To cause the 'U' status tag to occur we must modify a file from within another context. We will do this from another directory which will be a shadow directory to cvs_test_dir, that is, its CVS link will be to cvs_test_dir such that the new directory will contain the same files as cvs_test_dir. So change directory to the instrument's home 'cd ~' then 'cd cvs_tutorial'. If the directory 'cvs_tutorial' does not exist then we will create it using the checkout command (described in section 1.7). To perform the checkout you must change directories to the instrument account's home 'cd ~' then issue the checkout command as shown below. Note that you must replace <instr> with the account name and, the format of the checkout command depends upon whether or not you are on a Keck headquarters computer.

If you need to checkout cvs_tutorial on a Keck headquarters computer then enter:

            cvs -d <instr>@apua:/usr/local/cvsroot checkout -d cvs_tutorial <instr>/cvs_test_dir

If you need to checkout cvs_tutorial on a Keck summit computer or other remote site then enter:

            cvs -d <instr>@apua.keck.hawaii.edu:/usr/local/cvsroot checkout -d cvs_tutorial <instr>/cvs_test_dir

If the checkout fails then you will have jump to section 1.7 before proceeding.

Assuming the cvs_tutorial directory exists then cd into that directory and modify test.doc (append your favorite line). Commit the file as discussed in section 1.1. Now change directories to ~/cvs_test_dir again and enter the CVS update command again 'cvs -n update'. The status should be:

            U test.doc

The 'U' status tag indicates that a local file has not been modified since the last time it was committed and that a newer version of that file exists in the repository.

To cause the 'C' status tag to occur please modify the local copy of test.doc (in cvs_test_dir) with your second most favorite line. If you enter the update command again, but without the '-n' option, then the file will be modified by CVS and response should be:

            C test.doc

The 'C' status tag indicates that there is a conflict between the local version of a file and the latest version in the repository. A file with a conflict cannot be committed until the conflict is resolved by the user. Edit the file and look at the lines added by CVS in order to indicate the nature of the conflict. You should see something similar to:

            <<<<<<< test.doc
            my second favorite line

            =======
            my favorite line

            >>>>>>> 1.11

In order to commit a conflicting file you must first edit it and resolve the conflict by hand (merge the changes). The file will not be accepted by CVS until the lines containing the '>>>>>>>' are removed, as a minimum.
 

1.3.2  Retrieving older versions of files  (creating sticky tags)

Often one needs to toggle between versions of a file in order to investigate a difference in behavior. This is done by use of an update command option '-r'. Note that it is often necessary to use the CVS log command (refer to section 1.5) in order to determine which version to retrieve.

For this example we will assume we want to retrieve the original version of test.doc. So enter:

            cvs update -r1.1 test.doc

When you use the '-r' option you create what is called a 'sticky' tag. A sticky tag precludes you from modifying and committing a file without performing a few contortions.
 

1.3.3  Forcing an update to the most recent version of a file (undoing sticky tags)

Often, after testing/comparing an older version of a file,  it is necessary to undo a sticky tag so as to update to the most recent version of a file.
This is again done with the update command as such:

            cvs update -A test.doc

Please update test.doc to the most recent version, if you have not already done so, as it will be needed in subsequent sections.
 

1.4  Diff command - checking differences between your current working copy of a file and the most recent CVS revision

CVS provides a difference command to compare local files with versions in the repository. I typically difference a file, before making changes to that file, in order to determine if someone else has recently worked on that file.

The CVS difference command is 'diff'. The difference command defaults to diff'ing the file with the one in the repository that has the version number from which the local copy was obtained. Thus if someone else has made changes and updated the repository, for a file you are diff'ing, then by default you will not be informed of those differences. If you want to see differences between the local copy and the most recent version in CVS then you must use the '-rHEAD' option of the diff command. I typically do this as standard practice so that I can determine whether or not I want to merge or overwrite changes. This is done as follow:

            cvs diff -rHEAD test.doc

If the file is upto date (in this case it is if you just completed section 1.1 above) then no status is generated and the shell prompt returns.

To test the CVS diff command response when the local copy has been modifed and not yet committed, re-edit test.doc and make a change such as appending a line with the word 'test' (or whatever) then re-issue the diff command. The response will be something like:

            Index: test.doc
            ===================================================================
            RCS file: /usr/local/cvsroot/k2nirc/cvs_test_dir/test.doc,v
            retrieving revision 1.1
            diff -r1.1 test.doc
            9c9
            <
            ---
            > test

Now delete the most recent change and diff again to ensure the files are identical. Alternatively, you can delete test.doc and do 'cvs update test.doc', which will recreate test.doc from the last version commited. Note that update is discussed in a section 1.3 above.

To test the case where there is a newer version in CVS than in the local directory we will modify test.doc for another directory. Change directory to ~/cvs_tutorial. Hopefully this directory has been created for the instrument in which you are working (this was done in section 1.3.1 above). If not then please change directory to the home directory 'cd ~' and enter one of the following checkout commands (described in section 2.?) . You must substitute the instrument for <instr> in the following checkout command(s). Also the command depends upon whether or not you are on a Keck summit computer (or remote site) or on a Keck headquarters computer. From hq you would enter:

            cvs -d <instr>@apua:/usr/local/cvsroot checkout -d cvs_tutorial <instr>/cvs_test_dir

otherwise you would enter:

            cvs -d <instr>@apua.keck.hawii.edu:/usr/local/cvsroot checkout -d cvs_tutorial <instr>/cvs_test_dir

The result will be a new directory called cvs_tutorial which is linked to the same CVS repository as cvs_test_dir.

Now descend into the directory 'cd cvs_tutorial'.

If it was necessary to checkout the cvs_tutorial then ensure that test.doc is current, delete the file 'rm test.doc' then use the CVS update command 'cvs update -A test.doc'.

Now modify the file by again adding a line then commit that change as discussed in section 1 above.
Return to ~/cvs_test_dir and again issue the diff command. This time the response will be something like:

            ===================================================================
            RCS file: /usr/local/cvsroot/k2nirc/cvs_test_dir/test.doc,v
            retrieving revision 1.2
            retrieving revision 1.1
            diff -r1.2 -r1.1
            10c10
            < *
            ---
            >

The 'less than' and 'greater than' symbols are relevant to the CVS version of a file such that 'less than' means the local file has something less than the CVS version.

Now try the diff command without the '-rHEAD' option. The result will be that no differences are indicated. This is because the local file will be compared with the version from which it was derived (the version before the latest modification). Remember that this is the default as it can sometimes have significant implications.
 

1.5   Log command - checking the history of file revisions

The CVS log command allows one to view the entire history of modifications to a file provided that those who modified the file entered sufficiently detailed comments. That is, the log command lists all revision numbers along with the comments for those revisision. Hence, I hope that you will always enter useful comments when committing a file.

There are several reasons for use of the log command. Some of those reasons are: when a new version of a file does not function as expected; when merging; when attempting to find an older version of a file; before updating a file to the most current version; and sometimes when confused about the results from a diff command.

The log command is straight forward:

           cvs log test.doc
 

1.6   Remove command - moving or removing a file and how to handle it in CVS

The CVS remove command is an often overlooked command. The intent of the remove command is to prevent CVS from updating a file that is no longer wanted in the repository or at least in a directory in which the file had been added. Simply removing a file from the Unix file system is insufficient as the next CVS update command, in that directory, will restore the file. The remove command syntax is:

            cvs remove -m"<comment>" <filename>

If you recall, in section 1.3.1 we used remove to delete the file 'junk' which was added during the update command examples.

The lack of use of the remove command has occassionally caused problems at the observatory. For instance a problem can arise if a file is modified and moved to another directory, but not removed from CVS. If the original directory occurs earlier in the user's search path then the next CVS update in the original directory will cause the older version to be restored such that it is found and used.

When CVS removes a file it actually places that file in the 'attic'. Thus a remove mistake is not catastrophic.

1.7   Checkout command - populating/re-populating a CVS subtree

The CVS checkout command is used to populate a CVS subtree. This is a powerful command as it allows one to create a subtree at a remote site such that the subtree is populated with all the files currently on a Keck observatory instrument account.
 

TBC
 
 

Other than the initial checkout, the command is often used when new subdirectories are added to an already existing CVS subtree, and other users wish to udate their directories with the new subdirectories.
 
 
 
 

2     More complex functions

2.1   Determining if a file is known by CVS:


        Assume the file is myfile. The command to issue is:
            cvs -n update myfile

        7.1) If the file is known and not modified
             there will be no response and the command will simply terminate

        7.2) If the file is known and has been modified
            the response will be:
                M myfile

        7.3) If the file is known and has been modified by someone else from another account the response will be:
                U myfile

            in this case caution is required when modifying the file (see section 9 below - conflicts and merging )

        7.4) If the file is not known  the response will be:
                ? myfile

            in this case the file must be added to CVS, if it is not a temporary file (see section 8 below - Adding a new file ).

2.2  Determining if a directory is known by CVS


        If the directory has a subdirectory called CVS then it is most likely so.

        If you enter the following CVS command from within a directory:
            cvs -n update

        then the response depends upon whether or not the directory is in CVS as depicted in the following.

        6.1)  If the directory is not known to CVS then the response will be:
            cvs update: No CVSROOT specified!  Please use the `-d' option
            cvs [update aborted]: or set the CVSROOT environment variable.

        6.2) If the directory is known to CVS then the response will indicate the status of the files in the directory,
            where nothing is generated for an 'upto date' file, and other files will have a leading 'M',. 'U', or '?'.
            All subdirectories will also be traversed, with statuses being generated for each file. An unknown subdirectory
            will result in a status with a leading '?'.
 
 
 
 

2.4  Adding a new directory into CVS
 
 

3    Starting from scratch


13) Where's this CVS repository?

     If you look in the ~lris/bin directory, there is a subdirectory called CVS that contains 3 files:

     a) Root            (master root of CVS repository, usually kics@hana:/usr/local/cvsroot)
     b) Repository  (The CVS repository for keeping track of  manuka's ~lris/bin area)
                              points to kics@hana:/cvsroot/lris/summit/bin
      c) Entries   (list of all files & revisions in the repository)

   95% of the time you won't have to worry or know about this -- so this is FYI only.


A Potpourri of Other CVS Commands

  • How to get previous version of a file.

  •     e.g., version 1.17 is the most recent version, but you want to retrieve version 1.16 of the file:

                cvs update -r 1.16 file.c
     

  • To force an update of the directory with the latest CVS versions (regardless of sticky tag), do:

  •  

     
     
     
     
     

                cvs update -f
                 OR
               cvs update -A myfile
     

  • To force an update of directory which now contains a new subdirectory:

  •             cvs update -d
     

  • To remove a revision for a file from CVS : (be careful!)

  •     e.g., get rid of revision 1.3, but keep 1.2:

                 cvs admin -o1.3 drvAbDf1.c        (the "o" is for "outdates")
     

  • To totally remove a file from the CVS repository (it will go into the CVS 'Attic'):

  •             rm nogoodfile
            cvs remove nogoodfile
            cvs commit -m"remove it " nogoodfile
     

  • To check differences for files changed after 01oct97:

  •  

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

                cvs diff -D1-oct-97
                 (or use -R for revisions)
     

  • To check cvs version that is being used on your system :

  •  

     
     
     
     
     
     
     
     
     

                  cvs -v
     

  • To checkout a CVS module from a remote site AND also call it something else

  •    e.g., you're on maili as nirc and you want to place the cvs files in ~nirc/nircp3dev instead of in ~nirc/kss/nircp3dev.
       The CVS Repo is at Keck HQ on hana:

                cd ~nirc
               cvs -d kics@hana:/usr/local/cvsroot checkout -d nircp3dev kss/nircp3dev
                (where -d is for 'directory output specifiction')
     
     


    Weird Things and Unusual Notes (you shouldn't have to worry about this too often)

  • *** Note that to commit, each machine will need the file, /kroot/etc/commitCheck.

  •          (from hana ~wlupton/sunos/kroot/etc)
     
  • To debug CVS commands that aren't working, use the solaris truss cmd to trace system calls.

  •    It runs only on Solaris.  e.g., :

             truss -f -t open -t stat cvs tag dcs-3-0

            where -f for fork; -t to look for calls to open and stat and the command is d is 'cvs tag...'
     
     

  • To unlock a 'locked' file :

  •      - first check / remove lockfile in mydir/CVS/*
         - otherwise, check protections and
         - otherwise, must use cvs admin commands ... eg. rcs unlock
         ** don't edit the *,v files!!
     
  • If you're trying to checkout a module (e.g., kss/ire_common) but are having trouble...

  •    e.g., it says it doesn't know about the module, check the 'modules' file!

             cd ~
         cvs -d kics@hana:/usr/local/cvsroot checkout CVSROOT
         cd CVSROOT
         vi modules
            ... add the module ! (like an alias, e.g.,'core', 'ire_common')
         cvs commit -m"bla bla bla" modules
         then go back and try to cvs checkout that module
     
     

  • If you -know- there are differences w/ your working copy of the file, but  'cvs diff FILE' shows no differences and neither  does 'cvs -n up', then check the CVS/Entries file -- it maybe comparing against wrong version (e.g., that was removed from repository):

  •  

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

        <echock/kroot/kss/dcs/key/data> touch met_cake_config
        <echock/kroot/kss/dcs/key/data> cvs -n up
        cvs update: Updating .
        cvs [update aborted]: could not find desired version 1.2 in /usr/local/kcvsroot/kss/dcs/key/data/met_cake_config,v
        <echock/kroot/kss/dcs/key/data> pwd

         (note vsn 1.2 was removed)
        <echock/kroot/kss/dcs/key/data> more CVS/Entries
        /Makefile/1.2/Sat Apr  4 01:36:41 1998//
        /Makefile.Host/1.1/Fri Feb  6 08:30:37 1998//
        /aut2_cake_config/1.3/Wed Oct  1 09:36:50 1997//
        /dcs2_cake_config/1.116/Sat Apr  4 01:36:43 1998//
        /dcs2_header_info/1.8/Sat Apr  4 01:36:44 1998//
        /met_cake_config/1.2/Sat Apr  4 01:59:39 1998//
         D


    Section on TAGS... closing off Releases ... TBD -- ask AH

  •  You can just -tag- a release (freeze that CVS version of files, e.g., "nircp3-rel3-0") and continue to build in the same  development area - should be able to commit, diff, update (and get -latest-/post-tag), etc.  As long as you don't make a 'sticky tag' in that directory!  (see below).   Just tag:

  •  

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

          cd mytree-totag
              cvs tag myrel-3-0

    Therefore, if later on you need to revert to pure "3-0", just make a new directory and  checkout the nircp3 module w/ the tag "myrel-3-0".

    [This is the opposite of DCS. DCS uses 'sticky tags' to prevent inadvertent update (w/ the latest) into a released/closed-off directory.  If you set a sticky tag, this will only let you update into that directory using the tagged versions.  DCS is the opposite because it has separate development/release areas.  To be more restrictive in a directory and  set sticky tag, do:

             cvs update -r myrel-3-0
     

  • To retag a new revision of a file (after it has already been closed off and tagged) :

  •     e.g., previous version 1.1 was tagged for dcs-2-12; but file got updated again and version
        1.2 used in dcs-2-12 so file needs retagging :

             cvs tag -lF -r 1.2 dcs-2-12 k1mountNfs
         T k1mountNfs                                            [cvs will return this output, 'T'agged]

            (where "-l" is local-only, "-F" forced a retag (otherwise will get error),
             "-r" is reviision you want tagged (the latest) and "dcs-2-12" is the tag)
     

  •  To check out cvs modules including previously Tagged versions & upated ones :

  •  

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

             cvs -d kics@hana:/usr/local/cvsroot checkout -A dcs