CvsCheatSheet

From Mu2eWiki
Jump to navigation Jump to search

Expert.jpeg This page page needs expert review!

Simplest Use Pattern: Rarely Recommended

The simplest use pattern of cvs has four steps and it makes sense only if you are sure that no one else is modifying the same files that you intend to modify:

  1. Check out the files you need.
  2. Modify some or all of these files.
  3. Create some new files. There are tricks to adding new directories: see below.
  4. Edit the [ReleaseNotes.shtml release notes file] .
  5. Commit your new files and changed files to the repository.

Before the commit, the changes you made are local to your working copy. After the commit, anyone who checks out the code will get your changes.

The reason that this pattern is not recommended is that the "c" in cvs stands for "concurrent"; cvs allows many people to check out the same files and work on them in parallel. Therefore the following scenario is possible:

  1. You check out a file.
  2. Someone else checks out the same file;
  3. The other person changes the file and commits it back to the repository.
  4. You change the file and commit.
  5. The commit will fail with a message that your changes conflict with previously committed changes.

If you have changed many files it is possible that some commits will succeed while others fail.

In general this will leave the code base in broken state and it is your job to fix it promptly.



The Recommended Use Pattern

The recommended pattern is:

  1. Check out the files you need.
  2. Modify some or all of these files.
  3. Create some new files.
  4. Make a backup of your work.
  5. Use cvs status and cvs update to check for and merge in changes made by others. Resolve any conflicts this creates. See below .
  6. One final check to ensure that changes made by someone else do not conflict at run-time with changes you made. This step is not needed if cvs update did not modify you working copy.
    • Rebuild your code and rerun your tests.
    • If any of your tests fail, resolve the problem and restart at step 4.
  7. Edit the [ReleaseNotes.shtml release notes file] .
  8. Commit your changes and delete your backups.



Checking for And Resolving Conflicts

It is possible that, after you checked out your code, someone else committed changes to cvs. It is your job to check for this situation, to make sure that your changes do not conflict with the other person's changes and, if they do, to resolve the conflicts. Remember that cvs only knows about conflicts of the form "two people changed the same line"; it cannot tell that the combination of change by you and a change by some else, perhaps in a different file, will cause incorrect program behaviour.

Cvs has a variety of tools to help you manage this situation. The cvs history command will tell you who has made what changes recently. The cvs status command will tell you which files are up to date, which files have possible conflicts, and so on. And cvs update will try to bring your working copy up to date with the head of the repository. These three commands are discussed in more detail below.

The emacs editor has a powerful and convenient interface to cvs status. To use cvs status by hand, do the following:

  • cvs status >& status.log
  • grep File: status.log | grep -v Up-to-date
    Presumably most files are up to date so this will shorten the list of things to look at.
  • Each file will have one of 10 possible status values .
  • The 4 most frequently encountered status values are:
    • Up-to-date: you have not modified your checked out file and no one else has commited a change to it since you checked it out.
    • Locally Modified: means that you modified the file and that no one else has checked in a change to it since you checked it out.
    • Needs Patch: means that you did not modify the file but someone else has checked in changes since you checked out your code.
    • Needs Merge: means that you have modified the file and someone else has also checked in changes since you checked out your code.
  • If there are no files with a status of "Needs Merge" then there are no conflicts that cvs can detect. So you should
    • cvs update -PdA >& update.log.
      See below for details on the recommended options.
    • Check the log file for errors; there should not be any but, if there are, it is your job to resolve them.
    • Proceed to the "one final check" step in the recommended use pattern .
  • If there are files with a status of "Needs Merge" then you need to investigate these files further.
    • Look at status.log to learn the latest version in the repository.
    • cvs diff -r vvv filepath
      where vvv is the latest version in the repository, will show you the differences between your working copy and the latest version in the repository. Remember this for later.
    • If you omit the "-r vvv", cvs diff will show the differences between your current working copy and the version that you checked out. This is certainly useful but it is not what you want for this case.
    • You should be able to tell from the diff output if cvs is likely to be able to do a successful merge.
    • If you have not already done so, make a backup copy of those files in your working copy that need merging.
    • cvs update -PdA >& update.log .
      See below for details on the recommended options.
    • Check by hand that the merges worked properly; if they did not, it is your job to resolve them.
    • Look in update.log to check for other errors; there should not be any but, if there are, it is your job to resolve them.
    • Proceed to the "one final check" step in the recommended use pattern .


How to Recover from a Failed Commit

If your commit fails because of conflicts, it is your job to fix it promptly. Very likely the cvs HEAD will be in a broken state until you fix it.

In some cases the fix will be easy. Just edit your working copy, find the problem and fix it. Usually, however, you will need to do more work. The following are some suggestions.


First, you should make a backup of the current state of your work. You can use cvs history to see who else has recently worked on the offending file; they may have useful advice. You can use cvs diff to compare the current HEAD with the version the other person started from; this will identify what the other person did. You can use cvs diff to compare your working copy with the HEAD; this will show the conflicts plus your other changes that are not conflicts. As a last resort, you can delete the offending file from your working copy and re-checkout the HEAD of that file; after that you can, by hand, merge your changes into the HEAD (this is why it is recommended to make a backup before you start the commit process).



Zombie Directories in your checked out code

Suppose that you have a checked out copy of the code on which you are working. Then you are told that a directory has been deleted in the cvs head. You might expect the following command to remove the directory if you execute it in your top level working directory:

cvs update -PdA

If the only files under that directory are files managed by cvs, then this command will do exactly what you expect - it will remove the entire directory tree rooted at the deleted directory.

However the mu2e build system, scons, interferes with this. When you run scons, it leaves object files ( ending in .os ) in the same directory as the corresponding source files (ending in .cc). Therefore the action of cvs update with the above options will be to:

  • Traverse the directory tree rooted at the removed directory and remove all files known to cvs.
  • Files that are not under version control are not touched; this includes .os files and any other files you may have created.
  • If, after the above steps, any directories are empty, remove those directories.

A typical result is that the .os files remain, along with all of the directories on the path to them. If this happens, verify that the directory tree rooted at the removed directory does not contain files that you care about. If it does, move those files elsewhere. Then, from the top level of your working directory,

/bin/rm -r -i <directory_name>
/bin/rm -r -i lib/libmu2e_<directory_name>*

If you are sure that all is OK, then use ^C to interrupt the command and reissue it without the -i. The second step removes the libraries created from the deleted code.

An alternative is always to do the following when you expect directories to be removed by a cvs update:

find <directory_name> -name \*.os -exec rm {} \;
/bin/rm -r -i lib/libmu2e_<directory_name>*</b>
cvs update -PdA

This removes all .os files and .so files before doing the update; so there will be empty directories for the update to remove.

This sort of behaviour is common to most code management systems, which never touch files that are not under their management.



CVS Cheat Sheet

  • checking out files
    • cvs co module
    • cvs co -r tag module
    • cvs co -D date module
    • module: the name of a package or sub-package (e.g. Offline)
    • tag: the name of a cvs tag (e.g. v0_0_3)
    • date: for example "2010-04-27 01:30"
    • The date option will select the most recent files with a commit date no later than the date specified as the argument. I believe, but am not sure, that the date is given in the time zone set on the computer in which you execute the cvs command.
  • Comparing your current working files to the version that was checked out. This does not warn you about concurrent changes made by others.
    • cvs diff filename(s)
    • cvs diff
    • The first version will compare the specified file(s). If any of the filenames are directories, the cvs will recursively descend through the directory and compare all files.
    • The second version compares all files in the directory tree rooted at .
    • There is also a syntax to diff your working against an arbitrary version in the repository and a syntax to diff two different versions from the repository. Consult the complete cvs documentation .
  • commit your changes
    • cvs commit -m "Comment text goes here." filename(s)
    • cvs commit filename(s)
    • Both versions will commit the named files to the repository.
    • You may use wildcards to specify multuiple files.
    • If a filename is a directory, cvs will recursively descend through the directory and commit all modified or added files.
    • In the first version the comment is given inline.
    • In the second version cvs will open an editor window to allow you to give a longer comment.
    • To choose an editor, set the environment variable CVSEDITOR. For example,
      setenv CVSEDITOR /usr/bin/xemacs   # for tcsh
      export CVSEDITOR=/usr/bin/xemacs   # for bash
      
    • The default editor is vi. If you do not know vi the following commands are useful:
      • i enter insert mode; this allows you to enter text and use the delete key.
      • ESC:wq leave insert mode, save the file and exit.
      • ESC:q! leave insert mode and quit without saving.
      • where ESC refers to the "escape" key.
      • Here is the online vi Tutorial.
  • adding files
    • There are separate instructions for adding a directory.
    • Adding a new file is a three step process.
      1. Create the file(s)
      2. cvs add filename(s)
      3. cvs commit -m "Comment" filename(s)
    • In the add and commit commands, you can use wildcards and/or you may list several files on one line. Be careful with wildcards so that you do not add or commit unintended files.
    • If you accidentally add a file, simply skip the commit for that file.
  • adding directories
    • You cannot commit an empty directory. You must create a file in the directory first. This is why some of the Mu2e directories are empty except for a file with a name like placeholder.txt.
    • The mantra for adding a directory is:
      1. mkdir directoryname
      2. cd directoryname
      3. Create one or more files
      4. cd ..
      5. cvs add directoryname
      6. cvs add directoryname/file1 directoryname/file2 ...
      7. cvs commit -m "Comment text." directoryname
    • This will add and commit both the directory and all of the files that you added in step 6.
  • removing files
    • rm file(s)
    • cvs remove file(s)
    • cvs commit -m "Comment text" file(s)
    • You must rm the file before issuing the cvs remove command.
    • The remove is not final until the commit has been issued.
  • removing directories
    • cvs does not let you remove directories.
    • However it does let you ignore any directories that are empty.
      • cvs co -P Offline
      • cvs update -PdA
      • In both cases, the -P option says to prune empty directories.
    • If you remove all ordinary files from a directory tree, leaving only subdirectories, then the -P option will skip the full directory tree.
  • updating
    • cvs update -PdA
    • The options mean:
      • P: Prune empty directories
      • d: create new directories
      • A: Reset sticky tags
    • This changes only files in your working copy. No changes are made to the respository.
    • If there were no conflicts between changes made in your working copy and changes made in the repository, then cvs update will sync your working copy with changes from the repository. This includes adding new files from the repository, deleting files that were deleted in the repository and changing files that were changed in the repository.
    • If you want your changes to be put in the repository you still must do a cvs commit.
    • cvs will do this recursively, starting in your current working directory and working down through the directory tree.
    • There are three classes of conflicts between the repository and your working copy:
      • Mutually exclusive changes; for example line 10 is changed in the repository but line 20 is changed in your working copy.
      • Changes that obviously conflict; for example you both changed line 10 and you did so differently.
      • Changes cvs thinks are mutually exclusive but which are, in fact, in conflict. Cvs can only detect that two people changed the same line. It is not a compiler so it cannot tell that the combination of two changes, on two different lines, will break the code.
    • cvs has the ability to merge mutually exclusive changes into the file in your working copy. If it does so, cvs will report it. You still must check that these changes really are mutually exclusive and not just apparently so - that is the reason for the "one final check" in the recommended use pattern .
    • If cvs detects changes that conflict, it will modify the file in your working copy so that it contains both versions of the code, delimited by change markers.
      >>>>>>>>>>>>>>> filename.cc
        this is line 10 in the file in my working copy.
      ===============
        this is line 10 in the file in the version 1.8 from the repository.
      <<<<<<<<<<<<<<< v 1.8
      

      It is your job to edit the file to make the correct merged change; this may required consulting with the author of the other change. Even if the correct merge seems obvious, it is good practice to inform the other author what you did.

    • After fixing conflicts, verify that the merged code works and commit the changes.
  • check the history and the commit comments for a specific file
    • cvs log filename
  • some useful history commands
    • cvs history -c -a -D "1 day ago" -z CDT
      find all changes submitted to the repository by anyone in the past day
    • cvs history -c -a -D "1 day ago" -f Mu2eG4/src -z CDT
      find all changes submitted to Mu2eG4/src (or any other subdirectory) by anyone in the past day
    • cvs history -c -u user "1 day ago" -f Mu2eG4/src -z CDT
      find all changes submitted by user to Mu2eG4/src in the past day
    • The -z CDT argument tells cvs to print the dates in CDT time ( Central Daylight Time - Fermilab summer time ). You can substitute other time zone abbreviations
  • command line help
    • cvs -H command e.g., cvs -H history
  • Tagging. Only experts should make tags.
    • cvs tag tag [files ...]
    • cvs tag -c tag [files ...]
    • cvs rtag tag module [module...]
    • Here tag is the name of the tag, for example v1_2_3.
    • "cvs tag" takes as arguments the names of checked out files whereas "rtag" takes as arguments the names of modules in the repository.
    • For cvs tag:
      • If a named file is a directory, then cvs tag will work recursively down through that directory.
      • If no files are named, then cvs tag will work recursively down from the current working directory.
      • Before tagging, make sure that your current working copy is up to date with the respository: the thing that is tagged is the version at the head of the repository, not your working copy. Another way to say this is that tag does not have an implied commit.
      • The -c option will check the named files to make sure that all files are up to date with the repository before tagging. If there are any problems, nothing is tagged.
    • For cvs rtag:
      • The tag is placed on files at the head of repository.
  • Moving tags. On very, very rare occasions it may be necessary to move tag from one version of file to another; perhaps you forgot to commit one file before tagging. The command to do this is:
    cvs tag -r revision -F tag [files ...]
    where revision is the internal cvs revsion number of the version which is to receive the tag and where tag is the name of the tag to be moved. Never move a tag on code that has been used to create results that are in any way "official"; if it is necessary to bug fix production code, use a branch instead of moving tags.
  • Checking the status of a file.
    • cvs status filename
      where filename is the name of a checked out file. This command will let you know if the checked out version of the file is in sync with the repository, if the file has been modified since you checked it out or if the repository version of the file has been modified since you checked it out.
  • Other information about a file
    • cvs log filename
      where filename is the name of a checked out file. This command will print out information about all existing versions of the file, including all of the comments made at commit-time. The printout includes the list of which revision numbers belong in which tag.
  • Importing a directory tree at the top level.
    • Here is an example: you want to make a top level cvs package named G4BeamlineScripts wih 4 subdirecotries, named BeamFiles, Field, Geometry and Inputs.
    • Cd to an empty directory in your own disk space; the name of this directory is not important.
    • mkdir the 4 subdirectories. As a precaution I usually add one file, named Placeholder.txt. in each subdirectory; I do this because cvs sometimes does not like empty directories.
    • cvs import -m "Starting a new package." G4BeamlineScripts empty start
      • The name G4BeamlineScripts is important. It is the package name.
      • The import command will import all files descended from the current working directory and place them in the package G4BeamlineScripts; the subdirectory structure is preserved.
      • The -m " " is the usual cvs comment.
      • The last two arguments are the "vendor tag" and the "release tag". For purposes of this example, the vendor-tag is not important; if we imported software from another code management system, this would be the tag by which it is known to that system. The release tag is the usual cvs tag; we can recover the original files by cvs co release-tag-name.
      • It is possible to import into a subdirecotry of a package:
        cvs import -m "Starting a new package." G4BeamlineScripts/subdir empty start
        In this case the imported files would be rooted at G4BeamlineScripts/subdir.



    Full CVS Documentation

    The version of cvs installed on interactive machines is 1.11.22. The full documentation for this version is available from: http://mu2e.fnal.gov/atwork/computing/cvs/cederqvist-1.11.22/cvs.html

    The documentation for many different versions of cvs is found at http://cvsman.com .

    On a unix machine, you can discover which version of cvs you are using with:

    cvs --version
    

    Additional Information

    • An excellent tutorial and reference are the CVS related chapeters in

    "Open Source Development with CVS", by Karl Fogel.