summaryrefslogtreecommitdiff
path: root/development
authorllornkcor <llornkcor>2002-06-23 14:32:50 (UTC)
committer llornkcor <llornkcor>2002-06-23 14:32:50 (UTC)
commit8672a04720e7421e7f41bbf49364bcc1df910bb2 (patch) (side-by-side diff)
tree2da9fe69cffd302f0b13fa6a4b03f5fb97ef4b63 /development
parentce9178fb13908eca5b7835e785fc0914a5022615 (diff)
downloadopie-8672a04720e7421e7f41bbf49364bcc1df910bb2.zip
opie-8672a04720e7421e7f41bbf49364bcc1df910bb2.tar.gz
opie-8672a04720e7421e7f41bbf49364bcc1df910bb2.tar.bz2
some dev docs
Diffstat (limited to 'development') (more/less context) (show whitespace changes)
-rw-r--r--development/cvsbook.html15663
-rw-r--r--development/tmake_ref.html478
2 files changed, 16141 insertions, 0 deletions
diff --git a/development/cvsbook.html b/development/cvsbook.html
new file mode 100644
index 0000000..2c869d1
--- a/dev/null
+++ b/development/cvsbook.html
@@ -0,0 +1,15663 @@
+<html lang="en"><head>
+<title>Open Source Development With CVS</title>
+<meta http-equiv="Content-Type" content="text/html">
+<meta name=description content="Open Source Development With CVS">
+<meta name=generator content="makeinfo 4.0">
+<link href="http://texinfo.org/" rel=generator-home>
+</head><body>
+
+<body bgcolor="#FFFFFF" fgcolor="#000000">
+
+<p>Copyright &copy; 1999, 2000 Karl Fogel &lt;kfogel@red-bean.com&gt;
+
+<p>This document is free software; you can redistribute and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+<p>This document is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+<p>This manual describes how to use and administer CVS (Concurrent Versions
+System). It is part of a larger work entitled <cite>Open Source
+Development With CVS</cite>; please see the introduction for details.
+
+<p>This is version 1.21 of this manual.
+
+
+<h1>Table of Contents</h1>
+<ul>
+<li><a href="#Top"></a>
+<li><a href="#Top">Top</a>
+<li><a href="#Introduction">Introduction</a>
+<li><a href="#An_Overview_of_CVS">An Overview of CVS</a>
+<ul>
+<li><a href="#Basic_Concepts">Basic Concepts</a>
+<li><a href="#A_Day_With_CVS">A Day With CVS</a>
+<ul>
+<li><a href="#Conventions_Used_In_This_Tour">Conventions Used In This Tour</a>
+<li><a href="#Invoking_CVS">Invoking CVS</a>
+<li><a href="#Accessing_A_Repository">Accessing A Repository</a>
+<li><a href="#Starting_A_New_Project">Starting A New Project</a>
+<li><a href="#Checking_Out_A_Working_Copy">Checking Out A Working Copy</a>
+<li><a href="#Version_Versus_Revision">Version Versus Revision</a>
+<li><a href="#Making_A_Change">Making A Change</a>
+<li><a href="#Finding_Out_What_You__And_Others__Did_--_update_And_diff">Finding Out What You (And Others) Did - update And diff</a>
+<li><a href="#CVS_And_Implied_Arguments">CVS And Implied Arguments</a>
+<li><a href="#Committing">Committing</a>
+<li><a href="#Revision_Numbers">Revision Numbers</a>
+<li><a href="#Detecting_And_Resolving_Conflicts">Detecting And Resolving Conflicts</a>
+<li><a href="#Finding_Out_Who_Did_What__Browsing_Log_Messages_">Finding Out Who Did What (Browsing Log Messages)</a>
+<li><a href="#Examining_And_Reverting_Changes">Examining And Reverting Changes</a>
+<li><a href="#The_Slow_Method_Of_Reverting">The Slow Method Of Reverting</a>
+<li><a href="#The_Fast_Method_Of_Reverting">The Fast Method Of Reverting</a>
+</ul>
+<li><a href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<ul>
+<li><a href="#Adding_Files">Adding Files</a>
+<li><a href="#Adding_Directories">Adding Directories</a>
+<li><a href="#CVS_And_Binary_Files">CVS And Binary Files</a>
+<li><a href="#Removing_Files">Removing Files</a>
+<li><a href="#Removing_Directories">Removing Directories</a>
+<li><a href="#Renaming_Files_And_Directories">Renaming Files And Directories</a>
+<li><a href="#Avoiding_Option_Fatigue">Avoiding Option Fatigue</a>
+<li><a href="#Getting_Snapshots__Dates_And_Tagging_">Getting Snapshots (Dates And Tagging)</a>
+<li><a href="#Acceptable_Date_Formats">Acceptable Date Formats</a>
+<li><a href="#Marking_A_Moment_In_Time__Tags_">Marking A Moment In Time (Tags)</a>
+</ul>
+<li><a href="#Branches">Branches</a>
+<ul>
+<li><a href="#Branching_Basics">Branching Basics</a>
+<li><a href="#Merging_Changes_From_Branch_To_Trunk">Merging Changes From Branch To Trunk</a>
+<li><a href="#Multiple_Merges">Multiple Merges</a>
+<li><a href="#Creating_A_Tag_Or_Branch_Without_A_Working_Copy">Creating A Tag Or Branch Without A Working Copy</a>
+</ul>
+</ul>
+<li><a href="#Repository_Administration">Repository Administration</a>
+<ul>
+<li><a href="#Getting_And_Installing_CVS">Getting And Installing CVS</a>
+<ul>
+<li><a href="#Getting_And_Building_CVS_Under_Unix">Getting And Building CVS Under Unix</a>
+<li><a href="#Getting_And_Installing_CVS_Under_Windows">Getting And Installing CVS Under Windows</a>
+<li><a href="#Getting_And_Installing_CVS_On_A_Macintosh">Getting And Installing CVS On A Macintosh</a>
+<li><a href="#Limitations_Of_The_Windows_And_Macintosh_Versions">Limitations Of The Windows And Macintosh Versions</a>
+</ul>
+<li><a href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>
+<ul>
+<li><a href="#Informational_Files">Informational Files</a>
+<li><a href="#Subdirectories">Subdirectories</a>
+<li><a href="#The_Cederqvist_Manual">The Cederqvist Manual</a>
+<li><a href="#Other_Sources_Of_Information">Other Sources Of Information</a>
+</ul>
+<li><a href="#Starting_A_Repository">Starting A Repository</a>
+<li><a href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a>
+<li><a href="#Anonymous_Access">Anonymous Access</a>
+<li><a href="#Repository_Structure">Repository Structure</a>
+<li><a href="#RCS_Format">RCS Format</a>
+<li><a href="#What_Happens_When_You_Remove_A_File">What Happens When You Remove A File</a>
+<li><a href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<ul>
+<li><a href="#The_config_File">The config File</a>
+<li><a href="#The_modules_File">The modules File</a>
+<li><a href="#The_commitinfo_And_loginfo_And_rcsinfo_Files">The commitinfo And loginfo And rcsinfo Files</a>
+<li><a href="#The_verifymsg_And_rcsinfo_Files">The verifymsg And rcsinfo Files</a>
+<li><a href="#The_taginfo_File">The taginfo File</a>
+<li><a href="#The_cvswrappers_File">The cvswrappers File</a>
+<li><a href="#The_editinfo_File">The editinfo File</a>
+<li><a href="#The_notify_File">The notify File</a>
+<li><a href="#The_checkoutlist_File">The checkoutlist File</a>
+</ul>
+<li><a href="#Commit_Emails">Commit Emails</a>
+<li><a href="#Finding_Out_More">Finding Out More</a>
+</ul>
+<li><a href="#Advanced_CVS">Advanced CVS</a>
+<ul>
+<li><a href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<ul>
+<li><a href="#How_Watches_Work">How Watches Work</a>
+<li><a href="#Enabling_Watches_In_The_Repository">Enabling Watches In The Repository</a>
+<li><a href="#Using_Watches_In_Development">Using Watches In Development</a>
+<li><a href="#Ending_An_Editing_Session">Ending An Editing Session</a>
+<li><a href="#Controlling_What_Actions_Are_Watched">Controlling What Actions Are Watched</a>
+<li><a href="#Finding_Out_Who_Is_Watching_What">Finding Out Who Is Watching What</a>
+<li><a href="#Reminding_People_To_Use_Watches">Reminding People To Use Watches</a>
+<li><a href="#What_Watches_Look_Like_In_The_Repository">What Watches Look Like In The Repository</a>
+</ul>
+<li><a href="#Log_Messages_And_Commit_Emails">Log Messages And Commit Emails</a>
+<li><a href="#Changing_A_Log_Message_After_Commit">Changing A Log Message After Commit</a>
+<li><a href="#Getting_Rid_Of_A_Working_Copy">Getting Rid Of A Working Copy</a>
+<li><a href="#History_--_A_Summary_Of_Repository_Activity">History - A Summary Of Repository Activity</a>
+<li><a href="#Annotations_--_A_Detailed_View_Of_Project_Activity">Annotations - A Detailed View Of Project Activity</a>
+<li><a href="#Annotations_And_Branches">Annotations And Branches</a>
+<li><a href="#Using_Keyword_Expansion">Using Keyword Expansion</a>
+<li><a href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>
+<ul>
+<li><a href="#Some_Principles_For_Working_With_Branches">Some Principles For Working With Branches</a>
+<li><a href="#Merging_Repeatedly_Into_The_Trunk">Merging Repeatedly Into The Trunk</a>
+<li><a href="#The_Dovetail_Approach_--_Merging_In_And_Out_Of_The_Trunk">The Dovetail Approach - Merging In And Out Of The Trunk</a>
+<li><a href="#The_Flying_Fish_Approach_--_A_Simpler_Way_To_Do_It">The Flying Fish Approach - A Simpler Way To Do It</a>
+<li><a href="#Branches_And_Keyword_Expansion_--_Natural_Enemies">Branches And Keyword Expansion - Natural Enemies</a>
+</ul>
+<li><a href="#Tracking_Third-Party_Sources__Vendor_Branches_">Tracking Third-Party Sources (Vendor Branches)</a>
+<li><a href="#Exporting_For_Public_Distribution">Exporting For Public Distribution</a>
+<li><a href="#The_Humble_Guru">The Humble Guru</a>
+</ul>
+<li><a href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>
+<ul>
+<li><a href="#The_Usual_Suspects">The Usual Suspects</a>
+<ul>
+<li><a href="#The_Working_Copy_Administrative_Area">The Working Copy Administrative Area</a>
+<li><a href="#Repository_Permissions">Repository Permissions</a>
+</ul>
+<li><a href="#General_Troubleshooting_Tips">General Troubleshooting Tips</a>
+<li><a href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<ul>
+<li><a href="#CVS_says_it_is_waiting_for_a_lock__what_does_that_mean_">CVS says it is waiting for a lock; what does that mean?</a>
+<li><a href="#CVS_claims_a_file_is_failing_Up-To-Date_check__what_do_I_do_">CVS claims a file is failing Up-To-Date check; what do I do?</a>
+<li><a href="#The_pserver_access_method_is_not_working">The pserver access method is not working</a>
+<li><a href="#The_pserver_access_method_is_STILL_not_working">The pserver access method is STILL not working</a>
+<li><a href="#My_commits_seem_to_happen_in_pieces_instead_of_atomically">My commits seem to happen in pieces instead of atomically</a>
+<li><a href="#CVS_keeps_changing_file_permissions__why_does_it_do_that_">CVS keeps changing file permissions; why does it do that?</a>
+<li><a href="#CVS_on_Windows_complains_it_cannot_find_my_.cvspass_file__why_">CVS on Windows complains it cannot find my .cvspass file; why?</a>
+<li><a href="#My_working_copy_is_on_several_different_branches__help_">My working copy is on several different branches; help?</a>
+<li><a href="#When_I_do_export_-d_I_sometimes_miss_recent_commits">When I do export -d I sometimes miss recent commits</a>
+<li><a href="#I_get_an_error_about_val-tags__what_should_I_do_">I get an error about val-tags; what should I do?</a>
+<li><a href="#I_am_having_problems_with_sticky_tags__how_do_I_get_rid_of_them_">I am having problems with sticky tags; how do I get rid of them?</a>
+<li><a href="#Checkouts_updates_exit_with_error_saying_cannot_expand_modules">Checkouts/updates exit with error saying cannot expand modules</a>
+<li><a href="#I_cannot_seem_to_turn_off_watches">I cannot seem to turn off watches</a>
+<li><a href="#My_binary_files_are_messed_up">My binary files are messed up</a>
+<li><a href="#CVS_is_not_doing_line-end_conversion_correctly">CVS is not doing line-end conversion correctly</a>
+<li><a href="#I_need_to_remove_a_subdirectory_in_my_project__how_do_I_do_it_">I need to remove a subdirectory in my project; how do I do it?</a>
+<li><a href="#Can_I_copy_.cvspass_files_or_portions_of_them_">Can I copy .cvspass files or portions of them?</a>
+<li><a href="#I_just_committed_some_files_with_the_wrong_log_message">I just committed some files with the wrong log message</a>
+<li><a href="#I_need_to_move_files_around_without_losing_revision_history">I need to move files around without losing revision history</a>
+<li><a href="#How_can_I_get_a_list_of_all_tags_in_a_project_">How can I get a list of all tags in a project?</a>
+<li><a href="#How_can_I_get_a_list_of_all_projects_in_a_repository_">How can I get a list of all projects in a repository?</a>
+<li><a href="#Some_commands_fail_remotely_but_not_locally__how_should_I_debug_">Some commands fail remotely but not locally; how should I debug?</a>
+<li><a href="#I_do_not_see_my_problem_covered_in_this_chapter">I do not see my problem covered in this chapter</a>
+<li><a href="#I_think_I_have_discovered_a_bug_in_CVS__what_do_I_do_">I think I have discovered a bug in CVS; what do I do?</a>
+<li><a href="#I_have_implemented_a_new_feature_for_CVS__to_whom_do_I_send_it_">I have implemented a new feature for CVS; to whom do I send it?</a>
+<li><a href="#How_can_I_keep_up_with_changes_to_CVS_">How can I keep up with changes to CVS?</a>
+</ul>
+</ul>
+<li><a href="#CVS_Reference">CVS Reference</a>
+<ul>
+<li><a href="#Commands_And_Options">Commands And Options</a>
+<ul>
+<li><a href="#Organization_And_Conventions">Organization And Conventions</a>
+<li><a href="#General_Patterns_In_CVS_Commands">General Patterns In CVS Commands</a>
+<li><a href="#Date_Formats">Date Formats</a>
+<li><a href="#Global_Options">Global Options</a>
+<li><a href="#add">add</a>
+<li><a href="#admin">admin</a>
+<li><a href="#annotate">annotate</a>
+<li><a href="#checkout">checkout</a>
+<li><a href="#commit">commit</a>
+<li><a href="#diff">diff</a>
+<li><a href="#edit">edit</a>
+<li><a href="#editors">editors</a>
+<li><a href="#export">export</a>
+<li><a href="#gserver">gserver</a>
+<li><a href="#history">history</a>
+<li><a href="#import">import</a>
+<li><a href="#init">init</a>
+<li><a href="#kserver">kserver</a>
+<li><a href="#log">log</a>
+<li><a href="#login">login</a>
+<li><a href="#logout">logout</a>
+<li><a href="#pserver">pserver</a>
+<li><a href="#rdiff">rdiff</a>
+<li><a href="#release">release</a>
+<li><a href="#remove">remove</a>
+<li><a href="#rtag">rtag</a>
+<li><a href="#server">server</a>
+<li><a href="#status">status</a>
+<li><a href="#tag">tag</a>
+<li><a href="#unedit">unedit</a>
+<li><a href="#update">update</a>
+<li><a href="#watch">watch</a>
+<li><a href="#watchers">watchers</a>
+</ul>
+<li><a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a>
+<ul>
+<li><a href="#Controlling_Keyword_Expansion">Controlling Keyword Expansion</a>
+<li><a href="#List_Of_Keywords">List Of Keywords</a>
+</ul>
+<li><a href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<ul>
+<li><a href="#Storage_And_Editing">Storage And Editing</a>
+<li><a href="#Shared_Syntax">Shared Syntax</a>
+<li><a href="#Shared_Variables">Shared Variables</a>
+<li><a href="#User_Variables">User Variables</a>
+<li><a href="#checkoutlist">checkoutlist</a>
+<li><a href="#commitinfo">commitinfo</a>
+<li><a href="#config">config</a>
+<li><a href="#cvsignore">cvsignore</a>
+<li><a href="#cvswrappers">cvswrappers</a>
+<li><a href="#editinfo">editinfo</a>
+<li><a href="#history_file">history file</a>
+<li><a href="#loginfo">loginfo</a>
+<li><a href="#modules">modules</a>
+<li><a href="#notify">notify</a>
+<li><a href="#passwd">passwd</a>
+<li><a href="#rcsinfo">rcsinfo</a>
+<li><a href="#taginfo">taginfo</a>
+<li><a href="#users">users</a>
+<li><a href="#val-tags">val-tags</a>
+<li><a href="#verifymsg">verifymsg</a>
+</ul>
+<li><a href="#Run_Control_Files">Run Control Files</a>
+<ul>
+<li><a href="#Run_Control_Files"><code>.cvsrc</code></a>
+<li><a href="#Run_Control_Files"><code>.cvsignore</code></a>
+<li><a href="#Run_Control_Files"><code>.cvspass</code></a>
+<li><a href="#Run_Control_Files"><code>.cvswrappers</code></a>
+</ul>
+<li><a href="#Working_Copy_Files">Working Copy Files</a>
+<ul>
+<li><a href="#Working_Copy_Files"><code>CVS/Base/</code>&nbsp;&nbsp;(directory)</a>
+<li><a href="#Working_Copy_Files"><code>CVS/Baserev</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Baserev.tmp</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Checkin.prog</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Entries</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Entries.Backup</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Entries.Log</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Entries.Static</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Notify</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Notify.tmp</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Repository</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Root</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Tag</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Template</code></a>
+<li><a href="#Working_Copy_Files"><code>CVS/Update.prog</code></a>
+</ul>
+<li><a href="#Environment_Variables">Environment Variables</a>
+<ul>
+<li><a href="#_COMSPEC">$COMSPEC</a>
+<li><a href="#_CVS_CLIENT_LOG">$CVS_CLIENT_LOG</a>
+<li><a href="#_CVS_CLIENT_PORT">$CVS_CLIENT_PORT</a>
+<li><a href="#_CVSEDITOR">$CVSEDITOR</a>
+<li><a href="#_CVSIGNORE">$CVSIGNORE</a>
+<li><a href="#_CVS_IGNORE_REMOTE_ROOT">$CVS_IGNORE_REMOTE_ROOT</a>
+<li><a href="#_CVS_PASSFILE">$CVS_PASSFILE</a>
+<li><a href="#_CVS_RCMD_PORT">$CVS_RCMD_PORT</a>
+<li><a href="#_CVSREAD">$CVSREAD</a>
+<li><a href="#_CVSROOT">$CVSROOT</a>
+<li><a href="#_CVS_RSH">$CVS_RSH</a>
+<li><a href="#_CVS_SERVER">$CVS_SERVER</a>
+<li><a href="#_CVS_SERVER_SLEEP">$CVS_SERVER_SLEEP</a>
+<li><a href="#_CVSUMASK">$CVSUMASK</a>
+<li><a href="#_CVSWRAPPERS">$CVSWRAPPERS</a>
+<li><a href="#_EDITOR">$EDITOR</a>
+<li><a href="#_HOME__HOMEDRIVE___HOMEPATH_">$HOME %HOMEDRIVE% %HOMEPATH%</a>
+<li><a href="#_PATH">$PATH</a>
+<li><a href="#_TEMP__TMP__TMPDIR">$TEMP $TMP $TMPDIR</a>
+<li><a href="#_VISUAL">$VISUAL</a>
+</ul>
+</ul>
+<li><a href="#Third-Party_Tools">Third-Party Tools</a>
+<ul>
+<li><a href="#pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs - An Emacs Interface To CVS</a>
+<ul>
+<li><a href="#Installing_pcl-cvs">Installing pcl-cvs</a>
+<li><a href="#Using_pcl-cvs">Using pcl-cvs</a>
+<li><a href="#Error_Handling_In_pcl-cvs">Error Handling In pcl-cvs</a>
+<li><a href="#The_Future_Of_pcl-cvs">The Future Of pcl-cvs</a>
+</ul>
+<li><a href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils - General Utilities For Use With CVS</a>
+<ul>
+<li><a href="#cvsu">cvsu</a>
+<li><a href="#cvsdo">cvsdo</a>
+<li><a href="#cvschroot">cvschroot</a>
+<li><a href="#cvsrmadm">cvsrmadm</a>
+<li><a href="#cvspurge">cvspurge</a>
+<li><a href="#cvsdiscard">cvsdiscard</a>
+<li><a href="#cvsco">cvsco</a>
+<li><a href="#cvsdate">cvsdate</a>
+</ul>
+<li><a href="#cvs2cl_--_Generate_GNU-Style_ChangeLogs">cvs2cl - Generate GNU-Style ChangeLogs</a>
+<li><a href="#cvsq_--_Queue_CVS_Commands_For_Later_Connection">cvsq - Queue CVS Commands For Later Connection</a>
+<li><a href="#cvslock_--_Lock_Repositories_For_Atomicity">cvslock - Lock Repositories For Atomicity</a>
+<li><a href="#Other_Packages">Other Packages</a>
+<li><a href="#Writing_Your_Own_Tools">Writing Your Own Tools</a>
+</ul>
+<li><a href="#Index">Index</a>
+<li><a href="#GNU_General_Public_License">GNU General Public License</a>
+<li><a href="#GNU_Free_Documentation_License">GNU Free Documentation License</a>
+</ul>
+
+<p><hr>
+Node:<a name="Top">Top</a>,
+Next:<a rel=next href="#Introduction">Introduction</a>,
+Up:<a rel=up href="#_top">(dir)</a>
+<br>
+
+<h1></h1>
+
+<h1>Top</h1>
+
+<ul>
+<li><a href="#Introduction">Introduction</a>: What is this book?
+<li><a href="#An_Overview_of_CVS">An Overview of CVS</a>: Basic CVS usage -- a tutorial.
+<li><a href="#Repository_Administration">Repository Administration</a>: How to run a CVS repository.
+<li><a href="#Advanced_CVS">Advanced CVS</a>: What the gurus know.
+<li><a href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>: FAQs and real-life experiences.
+<li><a href="#CVS_Reference">CVS Reference</a>: A reference to CVS commands, variables, etc.
+<li><a href="#Third-Party_Tools">Third-Party Tools</a>: Other tools that work with CVS.
+<li><a href="#Index">Index</a>:
+<li><a href="#GNU_General_Public_License">GNU General Public License</a>:
+<li><a href="#GNU_Free_Documentation_License">GNU Free Documentation License</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Introduction">Introduction</a>,
+Next:<a rel=next href="#An_Overview_of_CVS">An Overview of CVS</a>,
+Previous:<a rel=previous href="#Top">Top</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>Introduction</h1>
+
+<p>This is a set of free, online chapters about using CVS (Concurrent
+Versions System) for collaboration and version control. It covers
+everything from CVS installation and basic concepts all the way to
+advanced usage and administration. It is intended for anyone who uses
+or plans to use CVS.
+
+<p>These chapters are excerpted from a larger work called <cite>Open Source
+Development With CVS</cite> (published by <a href="http://www.coriolis.com/">The Coriolis Group</a>, ISBN 1-57610-490-7). The remainder of that book -
+chapters 1, 3, 5, and 7 - deals with the challenges and philosophical
+issues of running an Open Source project using CVS.
+
+<p>While the free chapters here constitute a complete CVS book by
+themselves, we certainly hope you'll like them enough to purchase a
+treeware copy of the entire book! You can order it directly from the
+publisher, at
+<a href="http://www.coriolis.com/bookstore/bookdetail.cfm?id=1576104907">http://www.coriolis.com/bookstore/bookdetail.cfm?id=1576104907</a>.
+
+<p>These chapters are released under the
+<a href="http://www.gnu.org/copyleft/gpl.html">GNU General Public License</a>.
+For more information about free software in general, visit
+<a href="http://www.gnu.org/">http://www.gnu.org/</a>, and particularly
+<a href="http://www.gnu.org/philosophy/free-sw.html">http://www.gnu.org/philosophy/free-sw.html</a>.
+
+<p>To submit comments or errata regarding any of this material, please send
+email to <a href="mailto:bug-cvsbook@red-bean.com">bug-cvsbook@red-bean.com</a>. For news and updates, visit
+<a href="http://cvsbook.red-bean.com/">http://cvsbook.red-bean.com/</a>.
+
+<p><hr>
+Node:<a name="An_Overview_of_CVS">An Overview of CVS</a>,
+Next:<a rel=next href="#Repository_Administration">Repository Administration</a>,
+Previous:<a rel=previous href="#Introduction">Introduction</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>An Overview of CVS</h1>
+
+<blockquote>
+<em>I can't imagine programming without it... that would be like
+parachuting without a parachute!</em>
+
+<p align="center"><em>-Brian Fitzpatrick on CVS</em></p>
+
+</blockquote>
+
+<p>This chapter introduces the fundamentals of CVS, and then provides an
+in-depth guided tour of everyday CVS usage. Concepts are presented
+sequentially, so if you're new to CVS, the best way to read this is to
+start at the beginning and go straight through, without skipping
+anything.
+
+<ul>
+<li><a href="#Basic_Concepts">Basic Concepts</a>: How to think like CVS.
+<li><a href="#A_Day_With_CVS">A Day With CVS</a>: Guided tour through a sample CVS session.
+<li><a href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>: Random useful things.
+<li><a href="#Branches">Branches</a>: Splitting development into parallel streams.
+</ul>
+
+<p><hr>
+Node:<a name="Basic_Concepts">Basic Concepts</a>,
+Next:<a rel=next href="#A_Day_With_CVS">A Day With CVS</a>,
+Up:<a rel=up href="#An_Overview_of_CVS">An Overview of CVS</a>
+<br>
+
+<h2>Basic Concepts</h2>
+
+<p>If you've never used CVS (or any version control system) before, it's
+easy to get tripped up by some of its underlying assumptions. What
+seems to cause the most initial confusion about CVS is that it is used
+for two apparently unrelated purposes: record keeping and collaboration.
+It turns out, however, that these two functions are closely connected.
+
+<p>Record keeping became necessary because people wanted to compare a
+program's current state with how it was at some point in the past. For
+example, in the normal course of implementing a new feature, a developer
+may bring the program into a thoroughly broken state, where it will
+probably remain until the feature is mostly finished. Unfortunately,
+this is just the time when someone usually calls to report a bug in the
+last publicly released version. To debug the problem (which may also
+exist in the current version of the sources), the program has to be
+brought back to a useable state.
+
+<p>Restoring the state poses no difficulty if the source code history is
+kept under CVS. The developer can simply say, in effect, "Give me the
+program as it was three weeks ago", or perhaps "Give me the program as
+it was at the time of our last public release". If you've never had
+this kind of convenient access to historical snapshots before, you may
+be surprised at how quickly you come to depend on it. Personally, I
+always use revision control on my coding projects now - it's saved me
+many times.
+
+<p>To understand what this has to do with facilitating collaboration, we'll
+need to take a closer look at the mechanism that CVS provides to help
+numerous people work on the same project. But before we do that, let's
+take a look at a mechanism that CVS doesn't provide (or at least,
+doesn't encourage): file locking. If you've used other version control
+systems, you may be familiar with the lock-modify-unlock development
+model, wherein a developer first obtains exclusive write access (a lock)
+to the file to be edited, makes the changes, and then releases the lock
+to allow other developers access to the file. If someone else already
+has a lock on the file, they have to "release" it before you can lock it
+and start making changes (or, in some implementations, you may "steal"
+their lock, but that is often an unpleasant surprise for them and not
+good practice!).
+
+<p>This system is workable if the developers know each other, know who's
+planning to do what at any given time, and can communicate with each
+other quickly if someone cannot work because of access contention.
+However, if the developer group becomes too large or too spread out,
+dealing with all the locking issues begins to chip away at coding time;
+it becomes a constant hassle that can discourage people from getting
+real work done.
+
+<p>CVS takes a more mellow approach. Rather than requiring that developers
+coordinate with each other to avoid conflicts, CVS enables developers to
+edit simultaneously, assumes the burden of integrating all the changes,
+and keeps track of any conflicts. This process uses the
+copy-modify-merge model, which works as follows:
+
+<ol type=1 start=1>
+
+</p><li>Developer A requests a working copy (a directory tree containing the
+files that make up the project) from CVS. This is also known as
+"checking out" a working copy, like checking a book out of the library.
+
+<li>Developer A edits freely in her working copy. At the same time, other
+developers may be busy in their own working copies. Because these are
+all separate copies, there is no interference - it is as though all of
+the developers have their own copy of the same library book, and they're
+all at work scribbling comments in the margins or rewriting certain
+pages independently.
+
+<li>Developer A finishes her changes and commits them into CVS along with a
+"log message", which is a comment explaining the nature and purpose of
+the changes. This is like informing the library of what changes she
+made to the book and why. The library then incorporates these changes
+into a "master" copy, where they are recorded for all time.
+
+<li>Meanwhile, other developers can have CVS query the library to see if the
+master copy has changed recently. If it has, CVS automatically updates
+their working copies. (This part is magical and wonderful, and I hope
+you appreciate it. Imagine how different the world would be if real
+books worked this way!)
+
+</ol>
+
+<p>As far as CVS is concerned, all developers on a project are equal.
+Deciding when to update or when to commit is largely a matter of
+personal preference or project policy. One common strategy for coding
+projects is to always update before commencing work on a major change
+and to commit only when the changes are complete and tested so that the
+master copy is always in a "runnable" state.
+
+<p>Perhaps you're wondering what happens when developers A and B, each in
+their own working copy, make different changes to the same area of text
+and then both commit their changes? This is called a <dfn>conflict</dfn>, and
+CVS notices it as soon as developer B tries to commit changes. Instead
+of allowing developer B to proceed, CVS announces that it has discovered
+a conflict and places conflict markers (easily recognizable textual
+flags) at the conflicting location in his copy. That location also
+shows both sets of changes, arranged for easy comparison. Developer B
+must sort it all out and commit a new revision with the conflict
+resolved. Perhaps the two developers will need to talk to each other to
+settle the issue. CVS only alerts the developers that there is a
+conflict; it's up to human beings to actually resolve it.
+
+<p>What about the master copy? In official CVS terminology, it is called
+the project's repository. The repository is simply a file tree kept on
+a central server. Without going into too much detail about its
+structure (but see <a href="#Repository_Administration">Repository Administration</a>), let's look at what
+the repository must do to meet the requirements of the
+checkout-commit-update cycle. Consider the following scenario:
+
+<ol type=1 start=1>
+
+</p><li>Two developers, A and B, check out working copies of a project at the
+same time. The project is at its starting point - no changes have been
+committed by anyone yet, so all the files are in their original,
+pristine state.
+
+<li>Developer A gets right to work and soon commits her first batch of
+changes.
+
+<li>Meanwhile, developer B watches television.
+
+<li>Developer A, hacking away like there's no tomorrow, commits her second
+batch of changes. Now, the repository's history contains the original
+files, followed by A's first batch of changes, followed by this set of
+changes.
+
+<li>Meanwhile, developer B plays video games.
+
+<li>Suddenly, developer C joins the project and checks out a working copy
+from the repository. Developer C's copy reflects A's first two sets of
+changes, because they were already in the repository when C checked out
+her copy.
+
+<li>Developer A, continuing to code as one possessed by spirits, completes
+and commits her third batch of changes.
+
+<li>Finally, blissfully unaware of the recent frenzy of activity, developer
+B decides it's time to start work. He doesn't bother to update his
+copy; he just commences editing files, some of which may be files that A
+has worked in. Shortly thereafter, developer B commits his first
+changes.
+
+</ol>
+
+<p>At this point, one of two things can happen. If none of the files
+edited by developer B have been edited by A, the commit succeeds.
+However, if CVS realizes that some of B's files are out of date with
+respect to the repository's latest copies, and those files have also
+been changed by B in his working copy, CVS informs B that he must do an
+update before committing those files.
+
+<p>When developer B runs the update, CVS merges all of A's changes into B's
+local copies of the files. Some of A's work may conflict with B's
+uncommitted changes, and some may not. Those parts that don't are
+simply applied to B's copies without further complication, but the
+conflicting changes must be resolved by B before being committed.
+
+<p>If developer C does an update now, she'll receive various new changes
+from the repository: those from A's third commit, and those from B's
+first <em>successful</em> commit (which might really come from B's second
+attempt to commit, assuming B's first attempt resulted in B being forced
+to resolve conflicts).
+
+<p>In order for CVS to serve up changes, in the correct sequence, to
+developers whose working copies may be out of sync by varying degrees,
+the repository needs to store all commits since the project's beginning.
+In practice, the CVS repository stores them all as successive diffs.
+Thus, even for a very old working copy, CVS is able to calculate the
+difference between the working copy's files and the current state of the
+repository, and is thereby able to bring the working copy up to date
+efficiently. This makes it easy for developers to view the project's
+history at any point and to revive even very old working copies.
+
+<p>Although, strictly speaking, the repository could achieve the same
+results by other means, in practice, storing diffs is a simple,
+intuitive means of implementing the necessary functionality. The
+process has the added benefit that, by using patch appropriately, CVS
+can reconstruct any previous state of the file tree and thus bring any
+working copy from one state to another. It can allow someone to check
+out the project as it looked at any particular time. It can also show
+the differences, in diff format, between two states of the tree without
+affecting someone's working copy.
+
+<p>Thus, the very features necessary to give convenient access to a
+project's history are also useful for providing a decentralized,
+uncoordinated developer team with the ability to collaborate on the
+project.
+
+<p>For now, you can ignore the details of setting up a repository,
+administering user access, and navigating CVS-specific file formats
+(those will be covered in <a href="#Repository_Administration">Repository Administration</a>). For the
+moment, we'll concentrate on how to make changes in a working copy.
+
+<p>But first, here is a quick review of terms:
+
+<ul>
+
+<li><dfn>Revision</dfn> A committed change in the history of a file or set of
+files. A revision is one "snapshot" in a constantly changing project.
+
+<li><dfn>Repository</dfn> The master copy where CVS stores a project's full
+revision history. Each project has exactly one repository.
+
+<li><dfn>Working copy</dfn> The copy in which you actually make changes to a
+project. There can be many working copies of a given project; generally
+each developer has his or her own copy.
+
+<li><dfn>Check out</dfn> To request a working copy from the repository. Your
+working copy reflects the state of the project as of the moment you
+checked it out; when you and other developers make changes, you must use
+commit and update to "publish" your changes and view others' changes.
+
+<li><dfn>Commit</dfn> To send changes from your working copy into the central
+repository. Also known as <dfn>check-in</dfn>.
+
+<li><dfn>Log message</dfn> A comment you attach to a revision when you commit it,
+describing the changes. Others can page through the log messages to get
+a summary of what's been going on in a project.
+
+<li><dfn>Update</dfn> To bring others' changes from the repository into your
+working copy and to show if your working copy has any uncommitted
+changes. Be careful not to confuse this with commit; they are
+complementary operations. Mnemonic: update brings your working copy up
+to date with the repository copy.
+
+<li><dfn>Conflict</dfn> The situation when two developers try to commit changes
+to the same region of the same file. CVS notices and points out
+conflicts, but the developers must resolve them.
+
+</ul>
+
+<p><hr>
+Node:<a name="A_Day_With_CVS">A Day With CVS</a>,
+Next:<a rel=next href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>,
+Previous:<a rel=previous href="#Basic_Concepts">Basic Concepts</a>,
+Up:<a rel=up href="#An_Overview_of_CVS">An Overview of CVS</a>
+<br>
+
+<h2>A Day With CVS</h2>
+
+<p>This section describes some basic CVS operations, then follows with a
+sample session covering typical CVS usage. As the guided tour
+progresses, we'll also start to look at how CVS works internally.
+
+<p>Although you don't need to understand every last detail of CVS's
+implementation to use it, a basic knowledge of how it works is
+invaluable in choosing the best way to achieve a given result. CVS is
+more like a bicycle than an automobile, in the sense that its mechanisms
+are entirely transparent to anyone who cares to look. As with a
+bicycle, you can just hop on and start riding immediately. However, if
+you take a few moments to study how the gears work, you'll be able to
+ride it much more efficiently. (In the case of CVS, I'm not sure
+whether transparency was a deliberate design decision or an accident,
+but it does seem to be a property shared by many free programs.
+Externally visible implementations have the advantage of encouraging the
+users to become contributing developers by exposing them to the system's
+inner workings right from the start.)
+
+<p>Each part of the tour may make use of knowledge introduced in previous
+parts. Therefore, if this is your first time, I recommend that you
+simply start at the beginning and take the tour sequentially, without
+skipping over anything. The menu below is merely meant as a convenience
+for repeat visitors - you shouldn't use it to jump directly to a
+section that interests you unless you're already familiar with the
+material in the previous sections.
+
+<ul>
+<li><a href="#Conventions_Used_In_This_Tour">Conventions Used In This Tour</a>:
+<li><a href="#Invoking_CVS">Invoking CVS</a>:
+<li><a href="#Accessing_A_Repository">Accessing A Repository</a>:
+<li><a href="#Starting_A_New_Project">Starting A New Project</a>:
+<li><a href="#Checking_Out_A_Working_Copy">Checking Out A Working Copy</a>:
+<li><a href="#Version_Versus_Revision">Version Versus Revision</a>:
+<li><a href="#Making_A_Change">Making A Change</a>:
+<li><a href="#Finding_Out_What_You__And_Others__Did_--_update_And_diff">Finding Out What You (And Others) Did -- update And diff</a>:
+<li><a href="#CVS_And_Implied_Arguments">CVS And Implied Arguments</a>:
+<li><a href="#Committing">Committing</a>:
+<li><a href="#Revision_Numbers">Revision Numbers</a>:
+<li><a href="#Detecting_And_Resolving_Conflicts">Detecting And Resolving Conflicts</a>:
+<li><a href="#Finding_Out_Who_Did_What__Browsing_Log_Messages_">Finding Out Who Did What (Browsing Log Messages)</a>:
+<li><a href="#Examining_And_Reverting_Changes">Examining And Reverting Changes</a>:
+<li><a href="#The_Slow_Method_Of_Reverting">The Slow Method Of Reverting</a>:
+<li><a href="#The_Fast_Method_Of_Reverting">The Fast Method Of Reverting</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Conventions_Used_In_This_Tour">Conventions Used In This Tour</a>,
+Next:<a rel=next href="#Invoking_CVS">Invoking CVS</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Conventions Used In This Tour</h3>
+
+<p>The tour takes place in a Unix environment. CVS also runs on Windows
+and Macintosh operating systems, and Tim Endres of Ice Engineering has
+even written a Java client (see http://www.trustice.com/java/jcvs/),
+which can be
+run anywhere Java runs. However, I'm going to take a wild guess and
+assume that the majority of CVS users - present and potential - are
+most likely working in a Unix command-line environment. If you aren't
+one of these, the examples in the tour should be easy to translate to
+other interfaces. Once you understand the concepts, you can sit down at
+any CVS front end and work with it (trust me, I've done it many times).
+
+<p>The examples in the tour are oriented toward people who will be using
+CVS to keep track of programming projects. However, CVS operations are
+applicable to all text documents, not just source code.
+
+<p>The tour also assumes that you already have CVS installed (it's present
+by default on many of the popular free Unix systems, so you might
+already have it without knowing it) and that you have access to a
+repository. Even if you are not set up, you can still benefit from
+reading the tour. In <a href="#Repository_Administration">Repository Administration</a>, you'll learn how
+to install CVS and set up repositories.
+
+<p>Assuming CVS is installed, you should take a moment to find the online
+CVS manual. Known familiarly as the "Cederqvist" (after Per Cederqvist,
+its original author), it comes with the CVS source distribution and is
+usually the most up-to-date reference available. It's written in
+Texinfo format and should be available on Unix systems in the "Info"
+documentation hierarchy. You can read it either with the command line
+info program
+
+<pre>floss$ info cvs
+</pre>
+
+<p>or by pressing Ctrl+H and then typing "i" inside Emacs. If neither of
+these works for you, consult your local Unix guru (or see
+<a href="#Repository_Administration">Repository Administration</a> regarding installation issues). You'll
+definitely want to have the Cederqvist at your fingertips if you're
+going to be using CVS regularly.
+
+<p><hr>
+Node:<a name="Invoking_CVS">Invoking CVS</a>,
+Next:<a rel=next href="#Accessing_A_Repository">Accessing A Repository</a>,
+Previous:<a rel=previous href="#Conventions_Used_In_This_Tour">Conventions Used In This Tour</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Invoking CVS</h3>
+
+<p>CVS is one program, but it can perform many different actions: updating,
+committing, branching, diffing, and so on. When you invoke CVS, you
+must specify which action you want to perform. Thus, the format of a
+CVS invocation is:
+
+<pre>floss$ cvs command
+</pre>
+
+<p>For example, you can use
+
+<pre>floss$ cvs update
+floss$ cvs diff
+floss$ cvs commit
+</pre>
+
+<p>and so on. (Don't bother to try running any of those particular
+commands yet, though; they won't do anything until you're in a working
+copy, which we'll get to shortly.)
+
+<p>Both CVS and the command can take options. Options that affect the
+behavior of CVS, independently of the command being run, are called
+global options; command-specific options are just called command
+options. Global options always go to the left of the command; command
+options, to its right. So in
+
+<pre>floss$ cvs -Q update -p
+</pre>
+
+<p>-Q is a global option, and -p is a command option. (If you're curious,
+-Q means "quietly"-that is, suppress all diagnostic output, and print
+error messages only if the command absolutely cannot be completed for
+some reason; -p means to send the results of update to standard output
+instead of to files.)
+
+<p><hr>
+Node:<a name="Accessing_A_Repository">Accessing A Repository</a>,
+Next:<a rel=next href="#Starting_A_New_Project">Starting A New Project</a>,
+Previous:<a rel=previous href="#Invoking_CVS">Invoking CVS</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Accessing A Repository</h3>
+
+<p>Before you can do anything, you must tell CVS the location of the
+repository you'll be accessing. This isn't a concern if you already
+have a working copy checked out - any working copy knows what
+repository it came from, so CVS can automatically deduce the repository
+for a given working copy. However, let's assume you don't have a
+working copy yet, so you need to tell CVS explicitly where to go. This
+is done with the -d global option (the -d stands for "directory", an
+abbreviation for which there is a historical justification, although -r
+for "repository" might have been better), followed by the path to the
+repository. For example, assuming the repository is on the local
+machine in /usr/local/cvs (a fairly standard location):
+
+<pre>floss$ cvs -d /usr/local/cvs command
+</pre>
+
+<p>In many cases, however, the repository is on another machine and must
+therefore be reached over the network. CVS provides a choice of network
+access methods; which one you'll use depends mostly on the security
+needs of the repository machine (hereinafter referred to as "the
+server"). Setting up the server to allow various remote access methods
+is covered in <a href="#Repository_Administration">Repository Administration</a>; here we'll deal only with
+the client side.
+
+<p>Fortunately, all the remote access methods share a common invocation
+syntax. In general, to specify a remote repository as opposed to a
+local one, you just use a longer repository path. You first name the
+access method, delimited on each side by colons, followed by the
+username and the server name (joined with an @ sign), another separator
+colon, and finally the path to the repository directory on the server.
+
+<p>Let's look at the <dfn>pserver</dfn> access method, which stands for
+"password-authenticated server":
+
+<pre>floss$ cvs -d :pserver:jrandom@cvs.foobar.com:/usr/local/cvs login
+(Logging in to jrandom@cvs.foobar.com)
+CVS password: (enter your CVS password here)
+floss$
+</pre>
+
+<p>The long repository path following -d told CVS to use the pserver access
+method, with the username jrandom, on the server cvs.foobar.com, which
+has a CVS repository in /usr/local/cvs. There's no requirement that the
+hostname be "cvs.something.com" by the way; that's a common convention,
+but it could just as easily have been:
+
+<pre>floss$ cvs -d :pserver:jrandom@fish.foobar.org:/usr/local/cvs command
+</pre>
+
+<p>The command actually run was login, which verifies that you are
+authorized to work with this repository. It prompts for a password,
+then contacts the server to verify the password. Following Unix custom,
+cvs login returns silently if the login succeeds; it shows an error
+message if it fails (for instance, because the password is incorrect).
+
+<p>You only have to log in once from your local machine to a given CVS
+server. After a successful login, CVS stores the password in your home
+directory, in a file called .cvspass. It consults that file every time
+a repository is contacted via the pserver method, so you only have to
+run login the first time you access a given CVS server from a particular
+client machine. Of course, you can rerun cvs login anytime if the
+password changes.
+
+<p>Note: pserver is currently the only access method requiring an initial
+login like this; with the others, you can start running regular CVS
+commands immediately.
+
+<p>Once you've stored the authentication information in your .cvspass file,
+you can run other CVS commands using the same command-line syntax:
+
+<pre>floss$ cvs -d :pserver:jrandom@cvs.foobar.com:/usr/local/cvs command
+</pre>
+
+<p>Getting pserver to work in Windows may require an extra step. Windows
+doesn't have the Unix concept of a home directory, so CVS doesn't know
+where to put the .cvspass file. You'll have to specify a location.
+It's normal to designate the root of the C: drive as the home directory:
+
+<pre>C:\WINDOWS&gt; set HOME=C:
+C:\WINDOWS&gt; cvs -d :pserver:jrandom@cvs.foobar.com:/usr/local/cvs login
+(Logging in to jrandom@cvs.foobar.com)
+CVS password: (enter password here)
+C:\WINDOWS&gt;
+</pre>
+
+<p>Any folder in the file system will suffice. You may want to avoid
+network drives, though, because the contents of your .cvspass file would
+then be visible to anyone with access to the drive.
+
+<p>In addition to pserver, CVS supports the ext method (which uses an
+external connection program, such as rsh or ssh), kserver (for the
+Kerberos security system version 4), and gserver (which uses the GSSAPI,
+or Generic Security Services API, and also handles Kerberos versions 5
+and higher). These methods are similar to pserver, but each has its own
+idiosyncrasies.
+
+<p>Of these, the <code>ext</code> method is probably the most commonly used. If
+you can log into the server with rsh or ssh, you can use the <code>ext</code>
+method. You can test it like this:
+
+<pre>floss$ rsh -l jrandom cvs.foobar.com
+Password: enter your login password here
+</pre>
+
+<p>Okay, let's assume you successfully logged in and logged out of the
+server with rsh, so now you're back on the original client machine:
+
+<pre>floss$ CVS_RSH=rsh; export CVS_RSH
+floss$ cvs -d :ext:jrandom@cvs.foobar.com:/usr/local/cvs command
+</pre>
+
+<p>The first line sets (in Unix Bourne shell syntax) the CVS_RSH
+environment variable to rsh, which tells CVS to use the rsh program to
+connect. The second line can be any CVS command; you will be prompted
+for your password so CVS can log into the server.
+
+<p>If you're in C shell rather than in Bourne shell, try this:
+
+<pre>floss% setenv CVS_RSH rsh
+</pre>
+
+<p>and for Windows, try this:
+
+<pre>C:\WINDOWS&gt; set CVS_RSH=rsh
+</pre>
+
+<p>The rest of the tour will use the Bourne syntax; translate for your
+environment as necessary.
+
+<p>To use ssh (the Secure Shell) instead of rsh, just set the CVS_RSH
+variable appropriately:
+
+<pre>floss$ CVS_RSH=ssh; export CVS_RSH
+</pre>
+
+<p>Don't get thrown by the fact that the variable's name is CVS_RSH but
+you're setting its value to ssh. There are historical reasons for this
+(the catch-all Unix excuse, I know). CVS_RSH can point to the name of
+any program capable of logging you into the remote server, running
+commands, and receiving their output. After rsh, ssh is probably the
+most common such program, although there are probably others. Note that
+this program must not modify its data stream in any way. This
+disqualifies the Windows NT rsh, because it converts (or attempts to
+convert) between the DOS and Unix line-ending conventions. You'd have
+to get some other rsh for Windows or use a different access method.
+
+<p>The gserver and kserver methods are not used as often as the others and
+are not covered here. They're quite similar to what we've covered so
+far; see the Cederqvist for details.
+
+<p>If you only use one repository and don't want to type -d repos each
+time, just set the CVSROOT environment variable (which perhaps should
+have been named CVSREPOS, but it's too late to change that now):
+
+<pre>floss$ CVSROOT=/usr/local/cvs
+floss$ export CVSROOT
+floss$ echo $CVSROOT
+/usr/local/cvs
+floss$
+</pre>
+
+<p>or maybe
+
+<pre>floss$ CVSROOT=:pserver:jrandom@cvs.foobar.com:/usr/local/cvs
+floss$ export CVSROOT
+floss$ echo $CVSROOT
+:pserver:jrandom@cvs.foobar.com:/usr/local/cvs
+floss$
+</pre>
+
+<p>The rest of this tour assumes that you've set CVSROOT to point to your
+repository, so the examples will not show the -d option. If you need to
+access many different repositories, you should not set CVSROOT and
+should just use -d repos when you need to specify the repository.
+
+<p><hr>
+Node:<a name="Starting_A_New_Project">Starting A New Project</a>,
+Next:<a rel=next href="#Checking_Out_A_Working_Copy">Checking Out A Working Copy</a>,
+Previous:<a rel=previous href="#Accessing_A_Repository">Accessing A Repository</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Starting A New Project</h3>
+
+<p>If you're learning CVS in order to work on a project that's already
+under CVS control (that is, it is kept in a repository somewhere),
+you'll probably want to skip down to the next section, "Checking Out A
+Working Copy." On the other hand, if you want to take existing source
+code and put it into CVS, this is the section for you. Note that it
+still assumes you have access to an existing repository; see
+<a href="#Repository_Administration">Repository Administration</a> if you need to set up a repository
+first.
+
+<p>Putting a new project into a CVS repository is known as <dfn>importing</dfn>.
+The CVS command, as you may have guessed, is
+
+<pre>floss$ cvs import
+</pre>
+
+<p>except that it needs some more options (and needs to be in the right
+location) to succeed. First, go into the top-level directory of your
+project tree:
+
+<pre>floss$ cd myproj
+floss$ ls
+README.txt a-subdir/ b-subdir/ hello.c
+floss$
+</pre>
+
+<p>This project has two files - README.txt and hello.c - in the top
+level, plus two subdirectories - a-subdir and b-subdir - plus some
+more files (not shown in the example) inside those subdirectories. When
+you import a project, CVS imports everything in the tree, starting from
+the current directory and working its way down. Therefore, you should
+make sure that the only files in the tree are ones you want to be
+permanent parts of the project. Any old backup files, scratch files,
+and so on should all be cleaned out.
+
+<p>The general syntax of an import command is
+
+<pre>floss$ cvs import -m "log msg" projname vendortag releasetag
+</pre>
+
+<p>The -m flag (for message) is for specifying a short message describing
+the import. This will be the first log message for the entire project;
+every commit thereafter will also have its own log message. These
+messages are mandatory; if you don't give the -m flag, CVS automatically
+starts up an editor (by consulting the EDITOR environment variable) for
+you to type a log message in. After you save the log message and exit
+the editor, the import then continues.
+
+<p>The next argument is the project's name (we'll use "myproj"). This is
+the name under which you'll check out the project from the repository.
+(What actually happens is that a directory of that name gets created in
+the repository, but more on that in <a href="#Repository_Administration">Repository Administration</a>.)
+The name you choose now does not need to be the same as the name of the
+current directory, although in most cases it usually is.
+
+<p>The vendortag and releasetag arguments are a bit of bookkeeping for CVS.
+Don't worry about them now; it hardly matters what you use. In
+<a href="#Advanced_CVS">Advanced CVS</a> you'll learn about the rare circumstances where
+they're significant. For now, we'll use a username and "start" for
+those arguments.
+
+<p>We're ready to run import:
+
+<pre>floss$ cvs import -m "initial import into CVS" myproj jrandom start
+N myproj/hello.c
+N myproj/README.txt
+cvs import: Importing /usr/local/cvs/myproj/a-subdir
+N myproj/a-subdir/whatever.c
+cvs import: Importing /usr/local/cvs/myproj/a-subdir/subsubdir
+N myproj/a-subdir/subsubdir/fish.c
+cvs import: Importing /usr/local/cvs/myproj/b-subdir
+N myproj/b-subdir/random.c
+
+No conflicts created by this import
+floss$
+</pre>
+
+<p>Congratulations! If you ran that command (or something similar), you've
+finally done something that affects the repository.
+
+<p>Reading over the output of the import command, you'll notice that CVS
+precedes each filename with a single letter - in this case, "N" for
+"new file". The use of a single letter on the left to indicate the
+status of a file is a general pattern in CVS command output. We'll see
+it later in checkout and update as well.
+
+<p>You might think that, having just imported the project, you can start
+working in the tree immediately. This is not the case, however. The
+current directory tree is still not a CVS working copy. It was the
+source for the import command, true, but it wasn't magically changed
+into a CVS working copy merely by virtue of having been imported. To
+get a working copy, you need to check one out from the repository.
+
+<p>First, though, you might want to archive the current project tree. The
+reason is that once the sources are in CVS, you don't want to confuse
+yourself by accidentally editing copies that aren't in version control
+(because those changes won't become part of the project's history). You
+want to do all of your editing in a working copy from now on. However,
+you also don't want to remove the imported tree entirely, because you
+haven't yet verified that the repository actually has the files. Of
+course, you can be 99.999 percent certain that it does because the
+import command returned with no error, but why take chances? Paranoia
+pays, as every programmer knows. Therefore, do something like this:
+
+<pre>floss$ ls
+README.txt a-subdir/ b-subdir/ hello.c
+floss$ cd ..
+floss$ ls
+myproj/
+floss$ mv myproj was_myproj
+floss$ ls
+was_myproj/
+floss$
+</pre>
+
+<p>There. You still have the original files, but they're clearly named as
+an obsolete version, so they won't be in the way when you get a real
+working copy. Now you're ready to check out.
+
+<p><hr>
+Node:<a name="Checking_Out_A_Working_Copy">Checking Out A Working Copy</a>,
+Next:<a rel=next href="#Version_Versus_Revision">Version Versus Revision</a>,
+Previous:<a rel=previous href="#Starting_A_New_Project">Starting A New Project</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Checking Out A Working Copy</h3>
+
+<p>The command to check out a project is exactly what you think it is:
+
+<pre>floss$ cvs checkout myproj
+cvs checkout: Updating myproj
+U myproj/README.txt
+U myproj/hello.c
+cvs checkout: Updating myproj/a-subdir
+U myproj/a-subdir/whatever.c
+cvs checkout: Updating myproj/a-subdir/subsubdir
+U myproj/a-subdir/subsubdir/fish.c
+cvs checkout: Updating myproj/b-subdir
+U myproj/b-subdir/random.c
+
+floss$ ls
+myproj/ was_myproj/
+floss$ cd myproj
+floss$ ls
+CVS/ README.txt a-subdir/ b-subdir/ hello.c
+floss$
+</pre>
+
+<p>Behold - your first working copy! Its contents are exactly the same as
+what you imported, with the addition of a subdirectory named "CVS".
+That's where CVS stores version control information. Actually, each
+directory in the project has a CVS subdirectory:
+
+<pre>floss$ ls a-subdir
+CVS/ subsubdir/ whatever.c
+floss$ ls a-subdir/subsubdir/
+CVS/ fish.c
+floss$ ls b-subdir
+CVS/ random.c
+</pre>
+
+<p>The fact that CVS keeps its revision information in subdirectories named
+CVS means that your project can never contain subdirectories of its own
+named CVS. In practice, I've never heard of this being a problem.
+
+<p>Before editing any files, let's take a peek inside the black box:
+
+<pre>floss$ cd CVS
+floss$ ls
+Entries Repository Root
+floss$ cat Root
+/usr/local/cvs
+floss$ cat Repository
+myproj
+floss$
+</pre>
+
+<p>Nothing too mysterious there. The Root file points to repository, and
+the Repository file points to a project inside the repository. If
+that's a little confusing, let me explain.
+
+<p>There is a longstanding confusion about terminology in CVS. The word
+"repository" is used to refer to two different things. Sometimes, it
+means the root directory of a repository (for example, /usr/local/cvs),
+which can contain many projects; this is what the Root file refers to.
+But other times, it means one particular project-specific subdirectory
+within a repository root (for example, /usr/local/cvs/myproj,
+/usr/local/cvs/yourproj, or /usr/local/cvs/fish). The Repository file
+inside a CVS subdirectory takes the latter meaning.
+
+<p>In this book, "repository" generally means Root (that is, the top-level
+repository), although it may occasionally be used to mean a
+project-specific subdirectory. If the intended sense can't be figured
+out from the context, there will be clarifying text. Note that the
+Repository file may sometimes contain an absolute path to the project
+name instead of a relative path. This can make it slightly redundant
+with the Root file:
+
+<pre>floss$ cd CVS
+floss$ cat Root
+:pserver:jrandom@cvs.foobar.com:/usr/local/cvs
+floss$ cat Repository
+/usr/local/cvs/myproj
+floss$
+</pre>
+
+<p>The Entries file stores information about the individual files in the
+project. Each line deals with one file, and there are only lines for
+files or subdirectories in the immediate parent directory. Here's the
+top-level CVS/Entries file in myproj:
+
+<pre>floss$ cat Entries
+/README.txt/1.1.1.1/Sun Apr 18 18:18:22 1999//
+/hello.c/1.1.1.1/Sun Apr 18 18:18:22 1999//
+D/a-subdir////
+D/b-subdir////
+</pre>
+
+<p>The format of each line is
+
+<pre>/filename/revision number/last modification date//
+</pre>
+
+<p>and the directory lines are prefixed with "D". (CVS doesn't really keep
+a change history for directories, so the fields for revision number and
+datestamp are empty.)
+
+<p>The datestamps record the date and time of the last update (in Universal
+Time, not local time) of the files in the working copy. That way, CVS
+can easily tell whether a file has been modified since the last
+checkout, update, or commit. If the file system timestamp differs from
+the timestamp in the CVS/Entries file, CVS knows (without even having to
+consult the repository) that the file was probably modified.
+
+<p>If you take a look at the CVS/* files in one of the subdirectories
+
+<pre>floss$ cd a-subdir/CVS
+floss$ cat Root
+/usr/local/cvs
+floss$ cat Repository
+myproj/a-subdir
+floss$ cat Entries
+/whatever.c/1.1.1.1/Sun Apr 18 18:18:22 1999//
+D/subsubdir////
+floss$
+</pre>
+
+<p>you can see that the root repository has not changed, but the Repository
+file spells out the location of this subdirectory of the project, and
+the Entries file contains different lines.
+
+<p>Immediately after import, the revision number of every file in the
+project is shown as 1.1.1.1. This initial revision number is a bit of a
+special case, so we won't examine it in detail just yet; we'll take a
+closer look at revision numbers after we've committed some changes.
+
+<p><hr>
+Node:<a name="Version_Versus_Revision">Version Versus Revision</a>,
+Next:<a rel=next href="#Making_A_Change">Making A Change</a>,
+Previous:<a rel=previous href="#Checking_Out_A_Working_Copy">Checking Out A Working Copy</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Version Versus Revision</h3>
+
+<p>The internal revision number that CVS keeps for each file is unrelated
+to the version number of the software product of which the files are
+part. For example, you may have a project composed of three files,
+whose internal revision numbers on May 3, 1999, were 1.2, 1.7, and 2.48.
+On that day, you package up a new release of the software and release it
+as SlickoSoft Version 3. This is purely a marketing decision and
+doesn't affect the CVS revisions at all. The CVS revision numbers are
+invisible to your customers (unless you give them repository access);
+the only publicly visible number is the "3" in Version 3. You could
+have called it Version 1729 as far as CVS is concerned - the version
+number (or "release" number) has nothing to do with CVS's internal
+change tracking.
+
+<p>To avoid confusion, I'll use the word "revision" to refer exclusively to
+the internal revision numbers of files under CVS control. I may still
+call CVS a "version control system", however, because "revision control
+system" just sounds too awkward.
+
+<p><hr>
+Node:<a name="Making_A_Change">Making A Change</a>,
+Next:<a rel=next href="#Finding_Out_What_You__And_Others__Did_--_update_And_diff">Finding Out What You (And Others) Did -- update And diff</a>,
+Previous:<a rel=previous href="#Version_Versus_Revision">Version Versus Revision</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Making A Change</h3>
+
+<p>The project as it stands doesn't do much. Here are the contents of
+hello.c:
+
+<pre>floss$ cat hello.c
+#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+}
+</pre>
+
+<p>Let's make the first change to the project since importing it; we'll add
+the line
+
+<pre>printf ("Goodbye, world!\n");
+</pre>
+
+<p>right after the Hello, world!. Invoke your favorite editor and make the
+change:
+
+<pre>floss$ emacs hello.c
+ ...
+</pre>
+
+<p>This was a fairly simple change, one where you're not likely to forget
+what you did. But in a larger, more complex project, it's quite
+possible you may edit a file, be interrupted by something else, and
+return several days later and be unable to remember exactly what you
+did, or even to remember if you changed anything at all. Which brings
+us to our first "CVS Saves Your Life" situation: comparing your working
+copy against the repository.
+
+<p><hr>
+Node:<a name="Finding_Out_What_You__And_Others__Did_--_update_And_diff">Finding Out What You (And Others) Did -- update And diff</a>,
+Next:<a rel=next href="#CVS_And_Implied_Arguments">CVS And Implied Arguments</a>,
+Previous:<a rel=previous href="#Making_A_Change">Making A Change</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Finding Out What You (And Others) Did - update And diff</h3>
+
+<p>Previously, I've talked about updating as a way of bringing changes down
+from the repository into your working copy - that is, as a way of
+getting other people's changes. However, update is really a bit more
+complex; it compares the overall state of the working copy with the
+state of the project in the repository. Even if nothing in the
+repository has changed since checkout, something in the working copy may
+have, and update will show that, too:
+
+<pre>floss$ cvs update
+cvs update: Updating .
+M hello.c
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+</pre>
+
+<p>The M next to hello.c means the file has been modified since it was last
+checked out, and the modifications have not yet been committed to the
+repository.
+
+<p>Sometimes, merely knowing which files you've edited is all you need.
+However, if you want a more detailed look at the changes, you can get a
+full report in diff format. The diff command compares the possibly
+modified files in the working copy to their counterparts in the
+repository and displays any differences:
+
+<pre>floss$ cvs diff
+cvs diff: Diffing .
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.1.1.1
+diff -r1.1.1.1 hello.c
+6a7
+&gt; printf ("Goodbye, world!\n");
+cvs diff: Diffing a-subdir
+cvs diff: Diffing a-subdir/subsubdir
+cvs diff: Diffing b-subdir
+</pre>
+
+<p>That's helpful, if a bit obscure, but there's still a lot of cruft in
+the output. For starters, you can ignore most of the first few lines.
+They just name the repository file and give the number of the last
+checked-in revision. These are useful pieces of information under other
+circumstances (we'll look more closely at them later), but you don't
+need them when you're just trying to get a sense of what changes have
+been made in the working copy.
+
+<p>A more serious impediment to reading the diff is that CVS is announcing
+its entry as it goes into each directory during the update. This can be
+useful during long updates on large projects, as it gives you a sense of
+how much longer the command will take, but right now it's just getting
+in the way of reading the diff. Let's tell CVS to be quiet about where
+it's working, with the -Q global option:
+
+<pre>floss$ cvs -Q diff
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.1.1.1
+diff -r1.1.1.1 hello.c
+6a7
+&gt; printf ("Goodbye, world!\n");
+</pre>
+
+<p>Better - at least some of the cruft is gone. However, the diff is
+still hard to read. It's telling you that at line 6, a new line was
+added (that is, what became line 7), whose contents were:
+
+<pre>printf ("Goodbye, world!\n");
+</pre>
+
+<p>The preceding "&gt;" in the diff tells you that this line is present in the
+newer version of the file but not in the older one.
+
+<p>The format could be made even more readable, however. Most people find
+"context" diff format easier to read because it displays a few lines of
+context on either side of a change. Context diffs are generated by
+passing the -c flag to diff:
+
+<pre>floss$ cvs -Q diff -c
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 hello.c
+*** hello.c 1999/04/18 18:18:22 1.1.1.1
+--- hello.c 1999/04/19 02:17:07
+***************
+*** 4,7 ****
+---4,8 --
+ main ()
+ {
+ printf ("Hello, world!\n");
++ printf ("Goodbye, world!\n");
+ }
+</pre>
+
+<p>Now that's clarity! Even if you're not used to reading context diffs, a
+glance at the preceding output will probably make it obvious what
+happened: a new line was added (the + in the first column signifies an
+added line) between the line that prints Hello, world! and the final
+curly brace.
+
+<p>We don't need to be able to read context diffs perfectly (that's patch's
+job), but it's worth taking the time to acquire at least a passing
+familiarity with the format. The first two lines (after the
+introductory cruft) are
+
+<pre>*** hello.c 1999/04/18 18:18:22 1.1.1.1
+--- hello.c 1999/04/19 02:17:07
+</pre>
+
+<p>and they tell you what is being diffed against what. In this case,
+revision 1.1.1.1 of hello.c is being compared against a modified version
+of the same file (thus, there's no revision number for the second line,
+because only the working copy's changes haven't been committed to the
+repository yet). The lines of asterisks and dashes identify sections
+farther down in the diff. Later on, a line of asterisks, with a line
+number range embedded, precedes a section from the original file. Then
+a line of dashes, with a new and potentially different line number range
+embedded, precedes a section from the modified file. These sections are
+organized into contrasting pairs (known as "hunks"), one side from the
+old file and the other side from the new.
+
+<p>Our diff has one hunk:
+
+<pre>***************
+*** 4,7 ****
+--- 4,8 --
+ main ()
+ {
+ printf ("Hello, world!\n");
++ printf ("Goodbye, world!\n");
+ }
+</pre>
+
+<p>The first section of the hunk is empty, meaning that no material was
+removed from the original file. The second section shows that, in the
+corresponding place in the new file, one line has been added; it's
+marked with a "+". (When diff quotes excerpts from files, it reserves
+the first two columns on the left for special codes, such as "+" so the
+entire excerpt appears to be indented by two spaces. This extra
+indentation is stripped off when the diff is applied, of course.)
+
+<p>The line number ranges show the hunk's coverage, including context
+lines. In the original file, the hunk was in lines 4 through 7; in the
+new file, it's lines 4 through 8 (because a line has been added). Note
+that the diff didn't need to show any material from the original file
+because nothing was removed; it just showed the range and moved on to
+the second half of the hunk.
+
+<p>Here's another context diff, from an actual project of mine:
+
+<pre>floss$ cvs -Q diff -c
+Index: cvs2cl.pl
+===================================================================
+RCS file: /usr/local/cvs/kfogel/code/cvs2cl/cvs2cl.pl,v
+retrieving revision 1.76
+diff -c -r1.76 cvs2cl.pl
+*** cvs2cl.pl 1999/04/13 22:29:44 1.76
+--- cvs2cl.pl 1999/04/19 05:41:37
+***************
+*** 212,218 ****
+ # can contain uppercase and lowercase letters, digits, '-',
+ # and '_'. However, it's not our place to enforce that, so
+ # we'll allow anything CVS hands us to be a tag:
+! /^\s([^:]+): ([0-9.]+)$/;
+ push (@{$symbolic_names{$2}}, $1);
+ }
+ }
+-- 212,218 --
+ # can contain uppercase and lowercase letters, digits, '-',
+ # and '_'. However, it's not our place to enforce that, so
+ # we'll allow anything CVS hands us to be a tag:
+! /^\s([^:]+): ([\d.]+)$/;
+ push (@{$symbolic_names{$2}}, $1);
+ }
+ }
+</pre>
+
+<p>The exclamation point shows that the marked line differs between the old
+and new files. Since there are no "+" or "-" signs, we know that the
+total number of lines in the file has remained the same.
+
+<p>Here's one more context diff from the same project, slightly more
+complex this time:
+
+<pre>floss$ cvs -Q diff -c
+Index: cvs2cl.pl
+===================================================================
+RCS file: /usr/local/cvs/kfogel/code/cvs2cl/cvs2cl.pl,v
+retrieving revision 1.76
+diff -c -r1.76 cvs2cl.pl
+*** cvs2cl.pl 1999/04/13 22:29:44 1.76
+--- cvs2cl.pl 1999/04/19 05:58:51
+***************
+*** 207,217 ****
+}
+ else # we're looking at a tag name, so parse &amp; store it
+ {
+- # According to the Cederqvist manual, in node "Tags", "Tag
+- # names must start with an uppercase or lowercase letter and
+- # can contain uppercase and lowercase letters, digits, '-',
+- # and '_'. However, it's not our place to enforce that, so
+- # we'll allow anything CVS hands us to be a tag:
+ /^\s([^:]+): ([0-9.]+)$/;
+ push (@{$symbolic_names{$2}}, $1);
+ }
+- 207,212 --
+***************
+*** 223,228 ****
+--- 218,225 --
+ if (/^revision (\d\.[0-9.]+)$/) {
+ $revision = "$1";
+ }
++
++ # This line was added, I admit, solely for the sake of a diff example.
+
+ # If have file name but not time and author, and see date or
+ # author, then grab them:
+</pre>
+
+<p>This diff has two hunks. In the first, five lines were removed (these
+lines are only shown in the first section of the hunk, and the second
+section's line count shows that it has five fewer lines). An unbroken
+line of asterisks forms the boundary between hunks, and in the second
+hunk we see that two lines have been added: a blank line and a pointless
+comment. Note how the line numbers compensate for the effect of the
+previous hunk. In the original file, the second hunk's range of the
+area was lines 223 through 228; in the new file, because of the deletion
+that took place in the first hunk, the range is in lines 218 through
+225.
+
+<p>Congratulations, you are probably now as expert as you'll ever need to
+be at reading diffs.
+
+<p><hr>
+Node:<a name="CVS_And_Implied_Arguments">CVS And Implied Arguments</a>,
+Next:<a rel=next href="#Committing">Committing</a>,
+Previous:<a rel=previous href="#Finding_Out_What_You__And_Others__Did_--_update_And_diff">Finding Out What You (And Others) Did -- update And diff</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>CVS And Implied Arguments</h3>
+
+<p>In each of the CVS commands so far, you may have noticed that no files
+were specified on the command line. We ran
+
+<pre>floss$ cvs diff
+</pre>
+
+<p>instead of
+
+<pre>floss$ cvs diff hello.c
+</pre>
+
+<p>and
+
+<pre>floss$ cvs update
+</pre>
+
+<p>instead of
+
+<pre>floss$ cvs update hello.c
+</pre>
+
+<p>The principle at work here is that if you don't name any files, CVS acts
+on all files for which the command could possibly be appropriate. This
+even includes files in subdirectories beneath the current directory; CVS
+automatically descends from the current directory through every
+subdirectory in the tree. For example, if you modified
+b-subdir/random.c and a-subdir/subsubdir/fish.c, running update may
+result in this:
+
+<pre>floss$ cvs update
+cvs update: Updating .
+M hello.c
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+M a-subdir/subsubdir/fish.c
+cvs update: Updating b-subdir
+M b-subdir/random.c
+floss$
+</pre>
+
+<p>or better yet:
+
+<pre>floss$ cvs -q update
+M hello.c
+M a-subdir/subsubdir/fish.c
+M b-subdir/random.c
+floss$
+</pre>
+
+<p>Note: The -q flag is a less emphatic version of -Q. Had we used -Q, the
+command would have printed out nothing at all, because the modification
+notices are considered nonessential informational messages. Using the
+lowercase -q is less strict; it suppresses the messages we probably
+don't want, while allowing certain, more useful messages to pass
+through.
+
+<p>You can also name specific files for the update:
+
+<pre>floss$ cvs update hello.c b-subdir/random.c
+M hello.c
+M b-subdir/random.c
+floss$
+</pre>
+
+<p>and CVS will only examine those files, ignoring all others.
+
+<p>In truth, it's more common to run update without restricting it to
+certain files. In most situations, you'll want to update the entire
+directory tree at once. Remember, the updates we're doing here only
+show that some files have been locally modified, because nothing has
+changed yet in the repository. When other people are working on the
+project with you, there's always the chance that running update will
+pull some new changes down from the repository and incorporate them into
+your local files. In that case, you may find it slightly more useful to
+name which files you want updated.
+
+<p>The same principle can be applied to other CVS commands. For example,
+with diff, you can choose to view the changes one file at a time
+
+<pre>floss$ cvs diff -c b-subdir/random.c
+Index: b-subdir/random.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 random.c
+*** b-subdir/random.c 1999/04/18 18:18:22 1.1.1.1
+--- b-subdir/random.c 1999/04/19 06:09:48
+***************
+*** 1 ****
+! /* A completely empty C file. */
+--- 1,8 --
+! /* Print out a random number. */
+!
+! #include &lt;stdio.h&gt;
+!
+! void main ()
+! {
+! printf ("a random number\n");
+! }
+</pre>
+
+<p>or see all the changes at once (hang on to your seat, this is going to
+be a big diff):
+
+<pre>floss$ cvs -Q diff -c
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 hello.c
+*** hello.c 1999/04/18 18:18:22 1.1.1.1
+--- hello.c 1999/04/19 02:17:07
+***************
+*** 4,7 ****
+--- 4,8 --
+ main ()
+ {
+ printf ("Hello, world!\n");
++ printf ("Goodbye, world!\n");
+ }
+Index: a-subdir/subsubdir/fish.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/a-subdir/subsubdir/fish.c,v
+retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 fish.c
+*** a-subdir/subsubdir/fish.c 1999/04/18 18:18:22 1.1.1.1
+--- a-subdir/subsubdir/fish.c 1999/04/19 06:08:50
+***************
+*** 1 ****
+! /* A completely empty C file. */
+--- 1,8 --
+! #include &lt;stdio.h&gt;
+!
+! void main ()
+! {
+! while (1) {
+! printf ("fish\n");
+! }
+! }
+Index: b-subdir/random.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+retrieving revision 1.1.1.1
+diff -c -r1.1.1.1 random.c
+*** b-subdir/random.c 1999/04/18 18:18:22 1.1.1.1
+--- b-subdir/random.c 1999/04/19 06:09:48
+***************
+*** 1 ****
+! /* A completely empty C file. */
+--- 1,8 --
+! /* Print out a random number. */
+!
+! #include &lt;stdio.h&gt;
+!
+! void main ()
+! {
+! printf ("a random number\n");
+! }
+</pre>
+
+<p>Anyway, as you can see from these diffs, this project is clearly ready
+for prime time. Let's commit the changes to the repository.
+
+<p><hr>
+Node:<a name="Committing">Committing</a>,
+Next:<a rel=next href="#Revision_Numbers">Revision Numbers</a>,
+Previous:<a rel=previous href="#CVS_And_Implied_Arguments">CVS And Implied Arguments</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Committing</h3>
+
+<p>The <dfn>commit</dfn> command sends modifications to the repository. If you
+don't name any files, a commit will send all changes to the repository;
+otherwise, you can pass the names of one or more files to be committed
+(other files would be ignored, in that case).
+
+<p>Here, we commit one file by name and two by inference:
+
+<pre>floss$ cvs commit -m "print goodbye too" hello.c
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;-- hello.c
+new revision: 1.2; previous revision: 1.1
+done
+floss$ cvs commit -m "filled out C code"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in a-subdir/subsubdir/fish.c;
+/usr/local/cvs/myproj/a-subdir/subsubdir/fish.c,v &lt;-- fish.c
+new revision: 1.2; previous revision: 1.1
+done
+Checking in b-subdir/random.c;
+/usr/local/cvs/myproj/b-subdir/random.c,v &lt;-- random.c
+new revision: 1.2; previous revision: 1.1
+done
+floss$
+</pre>
+
+<p>Take a moment to read over the output carefully. Most of what it says
+is pretty self-explanatory. One thing you may notice is that revision
+numbers have been incremented (as expected), but the original revisions
+are listed as 1.1 instead of 1.1.1.1 as we saw in the Entries file
+earlier.
+
+<p>There is an explanation for this discrepancy, but it's not very
+important. It concerns a special meaning that CVS attaches to revision
+1.1.1.1. For most purposes, we can just say that files receive a
+revision number of 1.1 when imported, but the number is displayed - for
+reasons known only to CVS - as 1.1.1.1 in the Entries file, until the
+first commit.
+
+<p><hr>
+Node:<a name="Revision_Numbers">Revision Numbers</a>,
+Next:<a rel=next href="#Detecting_And_Resolving_Conflicts">Detecting And Resolving Conflicts</a>,
+Previous:<a rel=previous href="#Committing">Committing</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Revision Numbers</h3>
+
+<p>Each file in a project has its own revision number. When a file is
+committed, the last portion of the revision number is incremented by
+one. Thus, at any given time, the various files comprising a project
+may have very different revision numbers. This just means that some
+files have been changed (committed) more often than others.
+
+<p>(You may be wondering, what's the point of the part to the left of the
+decimal point, if only the part on the right ever changes? Actually,
+although CVS never automatically increments the number on the left, that
+number can be incremented on request by a user. This is a rarely used
+feature, and we won't cover it in this tour.)
+
+<p>In the example project that we've been using, we just committed changes
+to three files. Each of those files is now revision 1.2, but the
+remaining files in the project are still revision 1.1. When you check
+out a project, you get each file at its highest revision so far. Here
+is what qsmith would see if he checked out myproj right now and looked
+at the revision numbers for the top-level directory:
+
+<pre>paste$ cvs -q -d :pserver:qsmith@cvs.foobar.com:/usr/local/cvs co myproj
+U myproj/README.txt
+U myproj/hello.c
+U myproj/a-subdir/whatever.c
+U myproj/a-subdir/subsubdir/fish.c
+U myproj/b-subdir/random.c
+paste$ cd myproj/CVS
+paste$ cat Entries
+/README.txt/1.1.1.1/Sun Apr 18 18:18:22 1999//
+/hello.c/1.2/Mon Apr 19 06:35:15 1999//
+D/a-subdir////
+D/b-subdir////
+paste$
+</pre>
+
+<p>The file hello.c (among others) is now at revision 1.2, while README.txt
+is still at the initial revision (revision 1.1.1.1, also known as 1.1).
+
+<p>If he adds the line
+
+<pre>printf ("between hello and goodbye\n");
+</pre>
+
+<p>to hello.c and commit it, the file's revision number will be incremented
+once more:
+
+<pre>paste$ cvs ci -m "added new middle line"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;-- hello.c
+new revision: 1.3; previous revision: 1.2
+done
+paste$
+</pre>
+
+<p>Now hello.c is revision 1.3, fish.c and random.c still are revision 1.2,
+and every other file is revision 1.1.
+
+<p>Note: that the command was given as cvs ci instead of cvs commit. Most
+CVS commands have short forms, to make typing easier. For checkout,
+update, and commit, the abbreviated versions are co, up, and ci,
+respectively. You can get a list of all of the short forms by running
+the command <code>cvs&nbsp;--help-synonyms</code>.
+
+<p>You can usually ignore a file's revision number. In most situations,
+the numbers are just internal bookkeeping that CVS handles
+automatically. However, being able to find and compare revision numbers
+is extremely handy when you have to retrieve (or diff against) an
+earlier copy of a file.
+
+<p>Examining the Entries file isn't the only way to discover a revision
+number. You can also use the status command
+
+<pre>paste$ cvs status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+
+ Working revision: 1.3 Tue Apr 20 02:34:42 1999
+ Repository revision: 1.3 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+</pre>
+
+<p>which, if invoked without any files being named, shows the status of
+every file in the project:
+
+<pre>paste$ cvs status
+cvs status: Examining.
+===================================================================
+File: README.txt Status: Up-to-date
+
+ Working revision: 1.1.1.1 Sun Apr 18 18:18:22 1999
+ Repository revision: 1.1.1.1 /usr/local/cvs/myproj/README.txt,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+===================================================================
+File: hello.c Status: Up-to-date
+
+ Working revision: 1.3 Tue Apr 20 02:34:42 1999
+ Repository revision: 1.3 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+cvs status: Examining a-subdir
+===================================================================
+File: whatever.c Status: Up-to-date
+
+ Working revision: 1.1.1.1 Sun Apr 18 18:18:22 1999
+ Repository revision: 1.1.1.1 /usr/local/cvs/myproj/a-subdir/whatever.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+cvs status: Examining a-subdir/subsubdir
+===================================================================
+File: fish.c Status: Up-to-date
+
+ Working revision: 1.2 Mon Apr 19 06:35:27 1999
+ Repository revision: 1.2 /usr/local/cvs/myproj/
+ a-subdir/subsubdir/fish.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+cvs status: Examining b-subdir
+===================================================================
+File: random.c Status: Up-to-date
+
+ Working revision: 1.2 Mon Apr 19 06:35:27 1999
+ Repository revision: 1.2 /usr/local/cvs/myproj/b-subdir/random.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+paste$
+</pre>
+
+<p>Just ignore the parts of that output that you don't understand. In
+fact, that's generally good advice with CVS. Often, the one little bit
+of information you're looking for will be accompanied by reams of
+information that you don't care about at all, and maybe don't even
+understand. This situation is normal. Just pick out what you need, and
+don't worry about the rest.
+
+<p>In the previous example, the parts we care about are the first three
+lines (not counting the blank line) of each file's status output. The
+first line is the most important; it tells you the file's name, and its
+status in the working copy. All of the files are currently in sync with
+the repository, so they all say <code>Up-to-date</code>. However, if random.c
+has been modified but not committed, it might read like this:
+
+<pre>===================================================================
+File: random.c Status: Locally Modified
+
+ Working revision: 1.2 Mon Apr 19 06:35:27 1999
+ Repository revision: 1.2 /usr/local/cvs/myproj/b-subdir/random.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+</pre>
+
+<p>The Working revision and Repository revision tell you whether the file
+is out of sync with the repository. Returning to our original working
+copy (jrandom's copy, which hasn't seen the new change to hello.c yet),
+we see:
+
+<pre>floss$ cvs status hello.c
+===================================================================
+File: hello.c Status: Needs Patch
+
+ Working revision: 1.2 Mon Apr 19 02:17:07 1999
+ Repository revision: 1.3 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+floss$
+</pre>
+
+<p>This tells us that someone has committed a change to hello.c, bringing
+the repository copy to revision 1.3, but that this working copy is still
+on revision 1.2. The line Status: Needs Patch means that the next update
+will retrieve those changes from the repository and "patch" them into
+the working copy's file.
+
+<p>Let's pretend for the moment that we don't know anything about qsmith's
+change to hello.c, so we don't run status or update. Instead, we just
+start editing the file, making a slightly different change at the same
+location. This brings us to our first conflict.
+
+<p><hr>
+Node:<a name="Detecting_And_Resolving_Conflicts">Detecting And Resolving Conflicts</a>,
+Next:<a rel=next href="#Finding_Out_Who_Did_What__Browsing_Log_Messages_">Finding Out Who Did What (Browsing Log Messages)</a>,
+Previous:<a rel=previous href="#Revision_Numbers">Revision Numbers</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Detecting And Resolving Conflicts</h3>
+
+<p>Detecting a conflict is easy enough. When you run update, CVS tells
+you, in no uncertain terms, that there's a conflict. But first, let's
+create the conflict. We edit hello.c to insert the line
+
+<pre>printf ("this change will conflict\n");
+</pre>
+
+<p>right where qsmith committed this:
+
+<pre>printf ("between hello and goodbye\n");
+</pre>
+
+<p>At this point, the status of our copy of hello.c is
+
+<pre>floss$ cvs status hello.c
+===================================================================
+File: hello.c Status: Needs Merge
+
+ Working revision: 1.2 Mon Apr 19 02:17:07 1999
+ Repository revision: 1.3 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+floss$
+</pre>
+
+<p>meaning that there are changes both in the repository and the working
+copy, and these changes need to be merged. (CVS isn't aware that the
+changes will conflict, because we haven't run update yet.) When we do
+the update, we see this:
+
+<pre>floss$ cvs update hello.c
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.2
+retrieving revision 1.3
+Merging differences between 1.2 and 1.3 into hello.c
+rcsmerge: warning: conflicts during merge
+cvs update: conflicts found in hello.c
+C hello.c
+floss$
+</pre>
+
+<p>The last line of output is the giveaway. The C in the left margin next
+to the filename indicates that changes have been merged, but that they
+conflict. The contents of hello.c now shows both changes:
+
+<pre>#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; hello.c
+ printf ("this change will conflict\n");
+=======
+ printf ("between hello and goodbye\n");
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; 1.3
+ printf ("Goodbye, world!\n");
+}
+</pre>
+
+<p>Conflicts are always shown delimited by conflict markers, in the
+following format:
+
+<pre>&lt;&lt;&lt;&lt;&lt;&lt;&lt; (filename)
+ the uncommitted changes in the working copy
+ blah blah blah
+=======
+ the new changes that came from the repository
+ blah blah blah
+ and so on
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; (latest revision number in the repository)
+</pre>
+
+<p>The Entries file also shows that the file is in a halfway state at the
+moment:
+
+<pre>floss$ cat CVS/Entries
+/README.txt/1.1.1.1/Sun Apr 18 18:18:22 1999//
+D/a-subdir////
+D/b-subdir////
+/hello.c/1.3/Result of merge+Tue Apr 20 03:59:09 1999//
+floss$
+</pre>
+
+<p>The way to resolve the conflict is to edit the file so that it contains
+whatever text is appropriate, removing the conflict markers in the
+process, and then to commit. This doesn't necessarily mean choosing one
+change over another; you could decide neither change is sufficient and
+rewrite the conflicting section (or indeed the whole file) completely.
+In this case, we'll adjust in favor of the first change, but with
+capitalization and punctuation slightly different from qsmith's:
+
+<pre>floss$ emacs hello.c
+ (make the edits...)
+floss$ cat hello.c
+#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+ printf ("BETWEEN HELLO AND GOODBYE.\n");
+ printf ("Goodbye, world!\n");
+}
+floss$ cvs ci -m "adjusted middle line"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;- hello.c
+new revision: 1.4; previous revision: 1.3
+done
+floss$
+</pre>
+
+<p><hr>
+Node:<a name="Finding_Out_Who_Did_What__Browsing_Log_Messages_">Finding Out Who Did What (Browsing Log Messages)</a>,
+Next:<a rel=next href="#Examining_And_Reverting_Changes">Examining And Reverting Changes</a>,
+Previous:<a rel=previous href="#Detecting_And_Resolving_Conflicts">Detecting And Resolving Conflicts</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Finding Out Who Did What (Browsing Log Messages)</h3>
+
+<p>By now, the project has undergone several changes. If you're trying to
+get an overview of what has happened so far, you don't necessarily want
+to examine every diff in detail. Browsing the log messages would be
+ideal, and you can accomplish this with the log command:
+
+<pre>floss$ cvs log
+(pages upon pages of output omitted)
+</pre>
+
+<p>The log output tends to be a bit verbose. Let's look at the log
+messages for just one file:
+
+<pre>floss$ cvs log hello.c
+RCS file: /usr/local/cvs/myproj/hello.c,v
+Working file: hello.c
+head: 1.4
+branch:
+locks: strict
+access list:
+symbolic names:
+ start: 1.1.1.1
+ jrandom: 1.1.1
+keyword substitution: kv
+total revisions: 5; selected revisions: 5
+description:
+--------------
+revision 1.4
+date: 1999/04/20 04:14:37; author: jrandom; state: Exp; lines: +1 -1
+adjusted middle line
+--------------
+revision 1.3
+date: 1999/04/20 02:30:05; author: qsmith; state: Exp; lines: +1 -0
+added new middle line
+--------------
+revision 1.2
+date: 1999/04/19 06:35:15; author: jrandom; state: Exp; lines: +1 -0
+print goodbye too
+--------------
+revision 1.1
+date: 1999/04/18 18:18:22; author: jrandom; state: Exp;
+branches: 1.1.1;
+Initial revision
+--------------
+revision 1.1.1.1
+date: 1999/04/18 18:18:22; author: jrandom; state: Exp; lines: +0 -0
+initial import into CVS
+=========================================================================
+floss$
+</pre>
+
+<p>As usual, there's a lot of information at the top that you can just
+ignore. The good stuff comes after each line of dashes, in a format that
+is self-explanatory.
+
+<p>When many files are sent in the same commit, they all share the same log
+message; a fact that can be useful in tracing changes. For example,
+remember back when we committed fish.c and random.c simultaneously? It
+was done like this:
+
+<pre>floss$ cvs commit -m "filled out C code"
+Checking in a-subdir/subsubdir/fish.c;
+/usr/local/cvs/myproj/a-subdir/subsubdir/fish.c,v &lt;- fish.c
+new revision: 1.2; previous revision: 1.1
+done
+Checking in b-subdir/random.c;
+/usr/local/cvs/myproj/b-subdir/random.c,v &lt;- random.c
+new revision: 1.2; previous revision: 1.1
+done
+floss$
+</pre>
+
+<p>The effect of this was to commit both files with the same log message:
+"Filled out C code." (As it happened, both files started at revision
+1.1 and went to 1.2, but that's just a coincidence. If random.c had
+been at revision 1.29, it would have moved to 1.30 with this commit, and
+its revision 1.30 would have had the same log message as fish.c's
+revision 1.2.)
+
+<p>When you run cvs log on them, you'll see the shared message:
+
+<pre>floss$ cvs log a-subdir/subsubdir/fish.c b-subdir/random.c
+
+RCS file: /usr/local/cvs/myproj/a-subdir/subsubdir/fish.c,v
+Working file: a-subdir/subsubdir/fish.c
+head: 1.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ start: 1.1.1.1
+ jrandom: 1.1.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+--------------
+revision 1.2
+date: 1999/04/19 06:35:27; author: jrandom; state: Exp; lines: +8 -1
+filled out C code
+--------------
+revision 1.1
+date: 1999/04/18 18:18:22; author: jrandom; state: Exp;
+branches: 1.1.1;
+Initial revision
+--------------
+revision 1.1.1.1
+date: 1999/04/18 18:18:22; author: jrandom; state: Exp; lines: +0 -0
+initial import into CVS
+=========================================================================
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+Working file: b-subdir/random.c
+head: 1.2
+branch:
+locks: strict
+access list:
+symbolic names:
+ start: 1.1.1.1
+ jrandom: 1.1.1
+keyword substitution: kv
+total revisions: 3; selected revisions: 3
+description:
+--------------
+revision 1.2
+date: 1999/04/19 06:35:27; author: jrandom; state: Exp; lines: +8 -1
+filled out C code
+--------------
+revision 1.1
+date: 1999/04/18 18:18:22; author: jrandom; state: Exp;
+branches: 1.1.1;
+Initial revision
+--------------
+revision 1.1.1.1
+date: 1999/04/18 18:18:22; author: jrandom; state: Exp; lines: +0 -0
+initial import into CVS
+=========================================================================
+floss$
+</pre>
+
+<p>From this output, you'll know that the two revisions were part of the
+same commit (the fact that the timestamps on the two revisions are the
+same, or very close, is further evidence).
+
+<p>Browsing log messages is a good way to get a quick overview of what's
+been going on in a project or to find out what happened to a specific
+file at a certain time. There are also free tools available to convert
+raw cvs log output to more concise and readable formats (such as GNU
+ChangeLog style); we won't cover those tools in this tour, but they'll
+be introduced in <a href="#Third-Party_Tools">Third-Party Tools</a>.
+
+<p><hr>
+Node:<a name="Examining_And_Reverting_Changes">Examining And Reverting Changes</a>,
+Next:<a rel=next href="#The_Slow_Method_Of_Reverting">The Slow Method Of Reverting</a>,
+Previous:<a rel=previous href="#Finding_Out_Who_Did_What__Browsing_Log_Messages_">Finding Out Who Did What (Browsing Log Messages)</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>Examining And Reverting Changes</h3>
+
+<p>Suppose that, in the course of browsing the logs, qsmith sees that
+jrandom made the most recent change to hello.c:
+
+<pre>revision 1.4
+date: 1999/04/20 04:14:37; author: jrandom; state: Exp; lines: +1 -1
+adjusted middle line
+</pre>
+
+<p>and wonders what jrandom did? In formal terms, the question that qsmith
+is asking is, "What's the difference between my revision (1.3) of
+hello.c, and jrandom's revision right after it (1.4)?" The way to find
+out is with the diff command, but this time by comparing two past
+revisions using the -r command option to specify both of them:
+
+<pre>paste$ cvs diff -c -r 1.3 -r 1.4 hello.c
+Index: hello.c
+===========================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.3
+retrieving revision 1.4
+diff -c -r1.3 -r1.4
+*** hello.c 1999/04/20 02:30:05 1.3
+--- hello.c 1999/04/20 04:14:37 1.4
+***************
+*** 4,9 ****
+ main ()
+ {
+ printf ("Hello, world!\n");
+! printf ("between hello and goodbye\n");
+ printf ("Goodbye, world!\n");
+ }
+--- 4,9 --
+ main ()
+ {
+ printf ("Hello, world!\n");
+! printf ("BETWEEN HELLO AND GOODBYE.\n");
+ printf ("Goodbye, world!\n");
+ }
+paste$
+</pre>
+
+<p>The change is pretty clear, when viewed this way. Because the revision
+numbers are given in chronological order (usually a good idea), the diff
+shows them in order. If only one revision number is given, CVS uses the
+revision of the current working copy for the other.
+
+<p>When qsmith sees this change, he instantly decides he likes his way
+better and resolves to "undo"-that is, to step back by one revision.
+
+<p>However, this doesn't mean that he wants to lose his revision 1.4.
+Although, in an absolute technical sense, it's probably possible to
+achieve that effect in CVS, there's almost never any reason to do so.
+It's much preferable to keep revision 1.4 in the history and make a new
+revision 1.5 that looks exactly like 1.3. That way the undo event
+itself is part of the file's history.
+
+<p>The only question is, how can you retrieve the contents of revision 1.3
+and put them into 1.5?
+
+<p>In this particular case, because the change is a very simple one, qsmith
+can probably just edit the file by hand to mirror revision 1.3 and then
+commit. However, if the changes are more complex (as they usually are
+in a real-life project), trying to re-create the old revision manually
+will be hopelessly error-prone. Therefore, we'll have qsmith use CVS to
+retrieve and recommit the older revision's contents.
+
+<p>There are two equally good ways to do this: the slow, plodding way and
+the fast, fancy way. We'll examine the slow, plodding way first.
+
+<p><hr>
+Node:<a name="The_Slow_Method_Of_Reverting">The Slow Method Of Reverting</a>,
+Next:<a rel=next href="#The_Fast_Method_Of_Reverting">The Fast Method Of Reverting</a>,
+Previous:<a rel=previous href="#Examining_And_Reverting_Changes">Examining And Reverting Changes</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>The Slow Method Of Reverting</h3>
+
+<p>This method involves passing the -p flag to update, in conjunction with
+-r. The -p option sends the contents of the named revision to standard
+output. By itself, this isn't terribly helpful; the contents of the
+file fly by on the display, leaving the working copy unchanged.
+However, by redirecting the standard output into the file, the file will
+now hold the contents of the older revision. It's just as though the
+file had been hand-edited into that state.
+
+<p>First, though, qsmith needs to get up to date with respect to the
+repository:
+
+<pre>paste$ cvs update
+cvs update: Updating .
+U hello.c
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+paste$ cat hello.c
+#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+ printf ("BETWEEN HELLO AND GOODBYE.\n");
+ printf ("Goodbye, world!\n");
+}
+paste$
+</pre>
+
+<p>Next, he runs update -p to make sure that the revision 1.3 is the one he
+wants:
+
+<pre>paste$ cvs update -p -r 1.3 hello.c
+===================================================================
+Checking out hello.c
+RCS: /usr/local/cvs/myproj/hello.c,v
+VERS: 1.3
+***************
+#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+ printf ("between hello and goodbye\n");
+ printf ("Goodbye, world!\n");
+}
+</pre>
+
+<p>Oops, there are a few lines of cruft at the beginning. They aren't
+actually being sent to standard output, but rather to standard error, so
+they're harmless. Nevertheless, they make reading the output more
+difficult and can be suppressed with -Q:
+
+<pre>paste$ cvs -Q update -p -r 1.3 hello.c
+#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+ printf ("between hello and goodbye\n");
+ printf ("Goodbye, world!\n");
+}
+paste$
+</pre>
+
+<p>There - that's exactly what qsmith was hoping to retrieve. The next
+step is to put that content into the working copy's file, using a Unix
+redirect (that's what the "&gt;" does):
+
+<pre>paste$ cvs -Q update -p -r 1.3 hello.c &gt; hello.c
+paste$ cvs update
+cvs update: Updating .
+M hello.c
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+paste$
+</pre>
+
+<p>Now when update is run, the file is listed as modified, which makes
+sense because its contents have changed. Specifically, it has the same
+content as the old revision 1.3 (not that CVS is aware of its being
+identical to a previous revision - it just knows the file has been
+modified). If qsmith wants to make extra sure, he can do a diff to
+check:
+
+<pre>paste$ cvs -Q diff -c
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.4
+diff -c -r1.4 hello.c
+*** hello.c 1999/04/20 04:14:37 1.4
+--- hello.c 1999/04/20 06:02:25
+***************
+*** 4,9 ****
+ main ()
+ {
+ printf ("Hello, world!\n");
+! printf ("BETWEEN HELLO AND GOODBYE.\n");
+ printf ("Goodbye, world!\n");
+ }
+--- 4,9 --
+ main ()
+ {
+ printf ("Hello, world!\n");
+! printf ("between hello and goodbye\n");
+ printf ("Goodbye, world!\n");
+ }
+paste$
+</pre>
+
+<p>Yes, that's exactly what he wanted: a pure reversion - in fact, it is
+the reverse of the diff he previously obtained. Satisfied, he commits:
+
+<pre>paste$ cvs ci -m "reverted to 1.3 code"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;- hello.c
+new revision: 1.5; previous revision: 1.4
+done
+paste$
+</pre>
+
+<p><hr>
+Node:<a name="The_Fast_Method_Of_Reverting">The Fast Method Of Reverting</a>,
+Previous:<a rel=previous href="#The_Slow_Method_Of_Reverting">The Slow Method Of Reverting</a>,
+Up:<a rel=up href="#A_Day_With_CVS">A Day With CVS</a>
+<br>
+
+<h3>The Fast Method Of Reverting</h3>
+
+<p>The fast, fancy way of reverting is to use the -j (for "join") flag to
+the update command. This flag is like -r in that it takes a revision
+number, and you can use up to two -j's at once. CVS calculates the
+difference between the two named revisions and applies that difference
+as a patch to the file in question (so the order in which you give the
+revisions is important).
+
+<p>Thus, assuming qsmith's copy is up to date, he can just do this:
+
+<pre>paste$ cvs update -j 1.4 -j 1.3 hello.c
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.4
+retrieving revision 1.3
+Merging differences between 1.4 and 1.3 into hello.c
+paste$ cvs update
+cvs update: Updating .
+M hello.c
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+paste$ cvs ci -m "reverted to 1.3 code" hello.c
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;-- hello.c
+new revision: 1.5; previous revision: 1.4
+done
+paste$
+</pre>
+
+<p>When you only need to revert one file, there's not really much
+difference between the plodding and fast methods. Later in the book,
+you'll see how the fast method is much better for reverting multiple
+files at once. In the meantime, use whichever way you're more
+comfortable with.
+
+<h2>Reverting Is Not A Substitute For Communication</h2>
+
+<p>In all likelihood, what qsmith did in our example was quite rude. When
+you're working on a real project with other people and you think that
+someone has committed a bad change, the first thing you should do is
+talk to him or her about it. Maybe there's a good reason for the change,
+or maybe he or she just didn't think things through. Either way, there's
+no reason to rush and revert. A full record of everything that happens
+is stored permanently in CVS, so you can always revert to a previous
+revision after consulting with whoever made the changes.
+
+<p>If you're a project maintainer facing a deadline or you feel you have
+the right and the need to revert the change unconditionally, then do so
+- but follow it immediately with an email to the author whose change
+was reverted, explaining why you did it and what needs to be fixed to
+recommit the change.
+
+<p><hr>
+Node:<a name="Other_Useful_CVS_Commands">Other Useful CVS Commands</a>,
+Next:<a rel=next href="#Branches">Branches</a>,
+Previous:<a rel=previous href="#A_Day_With_CVS">A Day With CVS</a>,
+Up:<a rel=up href="#An_Overview_of_CVS">An Overview of CVS</a>
+<br>
+
+<h2>Other Useful CVS Commands</h2>
+
+<p>At this point, you should be pretty comfortable with basic CVS usage.
+I'll abandon the tour narrative and introduce a few more useful commands
+in summarized form.
+
+<ul>
+<li><a href="#Adding_Files">Adding Files</a>:
+<li><a href="#Adding_Directories">Adding Directories</a>:
+<li><a href="#CVS_And_Binary_Files">CVS And Binary Files</a>:
+<li><a href="#Removing_Files">Removing Files</a>:
+<li><a href="#Removing_Directories">Removing Directories</a>:
+<li><a href="#Renaming_Files_And_Directories">Renaming Files And Directories</a>:
+<li><a href="#Avoiding_Option_Fatigue">Avoiding Option Fatigue</a>:
+<li><a href="#Getting_Snapshots__Dates_And_Tagging_">Getting Snapshots (Dates And Tagging)</a>:
+<li><a href="#Acceptable_Date_Formats">Acceptable Date Formats</a>:
+<li><a href="#Marking_A_Moment_In_Time__Tags_">Marking A Moment In Time (Tags)</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Adding_Files">Adding Files</a>,
+Next:<a rel=next href="#Adding_Directories">Adding Directories</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Adding Files</h3>
+
+<p>Adding a file is a two-step process: First you run the add command on
+it, then commit. The file won't actually appear in the repository until
+commit is run:
+
+<pre>floss$ cvs add newfile.c
+cvs add: scheduling file 'newfile.c' for addition
+cvs add: use 'cvs commit' to add this file permanently
+floss$ cvs ci -m "added newfile.c" newfile.c
+RCS file: /usr/local/cvs/myproj/newfile.c,v
+done
+Checking in newfile.c;
+/usr/local/cvs/myproj/newfile.c,v &lt;- newfile.c
+initial revision: 1.1
+done
+floss$
+</pre>
+
+<p><hr>
+Node:<a name="Adding_Directories">Adding Directories</a>,
+Next:<a rel=next href="#CVS_And_Binary_Files">CVS And Binary Files</a>,
+Previous:<a rel=previous href="#Adding_Files">Adding Files</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Adding Directories</h3>
+
+<p>Unlike adding a file, adding a new directory is done in one step;
+there's no need to do a commit afterwards:
+
+<pre>floss$ mkdir c-subdir
+floss$ cvs add c-subdir
+Directory /usr/local/cvs/myproj/c-subdir added to the repository
+floss$
+</pre>
+
+<p>If you look inside the new directory in the working copy, you'll see
+that a CVS subdirectory was created automatically by add:
+
+<pre>floss$ ls c-subdir
+CVS/
+floss$ ls c-subdir/CVS
+Entries Repository Root
+floss$
+</pre>
+
+<p>Now you can add files (or new directories) inside it, as with any other
+working copy directory.
+
+<p><hr>
+Node:<a name="CVS_And_Binary_Files">CVS And Binary Files</a>,
+Next:<a rel=next href="#Removing_Files">Removing Files</a>,
+Previous:<a rel=previous href="#Adding_Directories">Adding Directories</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>CVS And Binary Files</h3>
+
+<p>Until now, I've left unsaid the dirty little secret of CVS, which is
+that it doesn't handle binary files very well (well, there are other
+dirty little secrets, but this definitely counts as one of the
+dirtiest). It's not that CVS doesn't handle binaries at all; it does,
+just not with any great panache.
+
+<p>All the files we've been working with until now have been plain text
+files. CVS has some special tricks for text files. For example, when
+it's working between a Unix repository and a Windows or Macintosh
+working copy, it converts file line endings appropriately for each
+platform. For example, Unix convention is to use a linefeed (LF) only,
+whereas Windows expects a carriage return/linefeed (CRLF) sequence at
+the end of each line. Thus, the files in a working copy on a Windows
+machine will have CRLF endings, but a working copy of the same project
+on a Unix machine will have LF endings (the repository itself is always
+stored in LF format).
+
+<p>Another trick is that CVS detects special strings, known as RCS keyword
+strings, in text files and replaces them with revision information and
+other useful things. For example, if your file contains this string
+
+<pre>$Revision$
+</pre>
+
+<p>CVS will expand on each commit to include the revision number. For
+example, it may get expanded to
+
+<pre>$Revision$
+</pre>
+
+<p>CVS will keep that string up to date as the file is developed. (The
+various keyword strings are documented in <a href="#Advanced_CVS">Advanced CVS</a> and
+<a href="#Third-Party_Tools">Third-Party Tools</a>.)
+
+<p>This string expansion is a very useful feature in text files, as it
+allows you to see the revision number or other information about a file
+while you're editing it. But what if the file is a JPG image? Or a
+compiled executable program? In those kinds of files, CVS could do some
+serious damage if it blundered around expanding any keyword string that
+it encountered. In a binary, such strings may even appear by
+coincidence.
+
+<p>Therefore, when you add a binary file, you have to tell CVS to turn off
+both keyword expansion and line-ending conversion. To do so, use -kb:
+
+<pre>floss$ cvs add -kb filename
+floss$ cvs ci -m "added blah" filename
+ (etc)
+</pre>
+
+<p>Also, in some cases (such as text files that are likely to contain
+spurious keyword strings), you may wish to disable just the keyword
+expansion. That's done with -ko:
+
+<pre>floss$ cvs add -ko filename
+floss$ cvs ci -m "added blah" filename
+ (etc)
+</pre>
+
+<p>(In fact, this chapter is one such document, because of the
+<code>$Revision$</code> example shown here.)
+
+<p>Note that you can't meaningfully run <code>cvs&nbsp;diff</code> on two
+revisions of a binary file. Diff uses a text-based algorithm that can
+only report whether two binary files differ, but not how they differ.
+Future versions of CVS may provide a way to diff binary files.
+
+<p><hr>
+Node:<a name="Removing_Files">Removing Files</a>,
+Next:<a rel=next href="#Removing_Directories">Removing Directories</a>,
+Previous:<a rel=previous href="#CVS_And_Binary_Files">CVS And Binary Files</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Removing Files</h3>
+
+<p>Removing a file is similar to adding one, except there's an extra step:
+You have to remove the file from the working copy first:
+
+<pre>floss$ rm newfile.c
+floss$ cvs remove newfile.c
+cvs remove: scheduling 'newfile.c' for removal
+cvs remove: use 'cvs commit' to remove this file permanently
+floss$ cvs ci -m "removed newfile.c" newfile.c
+Removing newfile.c;
+/usr/local/cvs/myproj/newfile.c,v &lt;- newfile.c
+new revision: delete; previous revision: 1.1
+done
+floss$
+</pre>
+
+<p>Notice how, in the second and third commands, we name newfile.c
+explicitly even though it doesn't exist in the working copy anymore. Of
+course, in the commit, you don't absolutely need to name the file, as
+long as you don't mind the commit encompassing any other modifications
+that may have taken place in the working copy.
+
+<p><hr>
+Node:<a name="Removing_Directories">Removing Directories</a>,
+Next:<a rel=next href="#Renaming_Files_And_Directories">Renaming Files And Directories</a>,
+Previous:<a rel=previous href="#Removing_Files">Removing Files</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Removing Directories</h3>
+
+<p>As I said before, CVS doesn't really keep directories under version
+control. Instead, as a kind of cheap substitute, it offers certain odd
+behaviors that in most cases do the "right thing". One of these odd
+behaviors is that empty directories can be treated specially. If you
+want to remove a directory from a project, you first remove all the
+files in it
+
+<pre>floss$ cd dir
+floss$ rm file1 file2 file3
+floss$ cvs remove file1 file2 file3
+ (output omitted)
+floss$ cvs ci -m "removed all files" file1 file2 file3
+ (output omitted)
+</pre>
+
+<p>and then run update in the directory above it with the -P flag:
+
+<pre>floss$ cd ..
+floss$ cvs update -P
+ (output omitted)
+</pre>
+
+<p>The -P option tells update to "prune" any empty directories - that is,
+to remove them from the working copy. Once that's done, the directory
+can be said to have been removed; all of its files are gone, and the
+directory itself is gone (from the working copy, at least, although
+there is actually still an empty directory in the repository).
+
+<p>An interesting counterpart to this behavior is that when you run a plain
+update, CVS does not automatically bring new directories from the
+repository into your working copy. There are a couple of different
+justifications for this, none really worth going into here. The short
+answer is that from time to time you should run update with the -d flag,
+telling it to bring down any new directories from the repository.
+
+<p><hr>
+Node:<a name="Renaming_Files_And_Directories">Renaming Files And Directories</a>,
+Next:<a rel=next href="#Avoiding_Option_Fatigue">Avoiding Option Fatigue</a>,
+Previous:<a rel=previous href="#Removing_Directories">Removing Directories</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Renaming Files And Directories</h3>
+
+<p>Renaming a file is equivalent to creating it under the new name and
+removing it under the old. In Unix, the commands are:
+
+<pre>floss$ cp oldname newname
+floss$ rm oldname
+</pre>
+
+<p>Here's the equivalent in CVS:
+
+<pre>floss$ mv oldname newname
+floss$ cvs remove oldname
+ (output omitted)
+floss$ cvs add newname
+ (output omitted)
+floss$ cvs ci -m "renamed oldname to newname" oldname newname
+ (output omitted)
+floss$
+</pre>
+
+<p>For files, that's all there is to it. Renaming directories is not done
+very differently: create the new directory, cvs add it, move all the
+files from the old directory to the new one, cvs remove them from the
+old directory, cvs add them in the new one, cvs commit so everything
+takes effect, and then do cvs update -P to make the now-empty directory
+disappear from the working copy. That is to say:
+
+<pre>floss$ mkdir newdir
+floss$ cvs add newdir
+floss$ mv olddir/* newdir
+mv: newdir/CVS: cannot overwrite directory
+floss$ cd olddir
+floss$ cvs rm foo.c bar.txt
+floss$ cd ../newdir
+floss$ cvs add foo.c bar.txt
+floss$ cd ..
+floss$ cvs commit -m "moved foo.c and bar.txt from olddir to newdir"
+floss$ cvs update -P
+</pre>
+
+<p>Note: the warning message after the third command. It's telling you
+that it can't copy olddir's CVS/ subdirectory into newdir because newdir
+already has a directory of that name. This is fine, because you want
+olddir to keep its CVS/ subdirectory anyway.
+
+<p>Obviously, moving directories around can get a bit cumbersome. The best
+policy is to try to come up with a good layout when you initially import
+your project so you won't have to move directories around very often.
+Later, you'll learn about a more drastic method of moving directories
+that involves making the change directly in the repository. However,
+that method is best saved for emergencies; whenever possible, it's best
+to handle everything with CVS operations inside working copies.
+
+<p><hr>
+Node:<a name="Avoiding_Option_Fatigue">Avoiding Option Fatigue</a>,
+Next:<a rel=next href="#Getting_Snapshots__Dates_And_Tagging_">Getting Snapshots (Dates And Tagging)</a>,
+Previous:<a rel=previous href="#Renaming_Files_And_Directories">Renaming Files And Directories</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Avoiding Option Fatigue</h3>
+
+<p>Most people tire pretty quickly of typing the same option flags with
+every command. If you know that you always want to pass the -Q global
+option or you always want to use -c with diff, why should you have to
+type it out each time?
+
+<p>There is help, fortunately. CVS looks for a .cvsrc file in your home
+directory. In that file, you can specify default options to apply to
+every invocation of CVS. Here's an example .cvsrc:
+
+<pre>diff -c
+update -P
+cvs -q
+</pre>
+
+<p>If the leftmost word on a line matches a CVS command (in its
+unabbreviated form), the corresponding options are used for that command
+every time. For global options, you just use cvs. So, for example,
+every time that user runs cvs diff, the -c flag is automatically
+included.
+
+<p><hr>
+Node:<a name="Getting_Snapshots__Dates_And_Tagging_">Getting Snapshots (Dates And Tagging)</a>,
+Next:<a rel=next href="#Acceptable_Date_Formats">Acceptable Date Formats</a>,
+Previous:<a rel=previous href="#Avoiding_Option_Fatigue">Avoiding Option Fatigue</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Getting Snapshots (Dates And Tagging)</h3>
+
+<p>Let's return to the example of the program that's in a broken state when
+a bug report comes in. The developer suddenly needs access to the
+entire project as it was at the time of the last release, even though
+many files may have been changed since then, and each file's revision
+number differs from the others. It would be far too time-consuming to
+look over the log messages, figure out what each file's individual
+revision number was at the time of release, and then run update
+(specifying a revision number with -r) on each one of them. In medium-
+to large-sized projects (tens to hundreds of files), such a process
+would be too unwieldy to attempt.
+
+<p>CVS, therefore, provides a way to retrieve previous revisions of the
+files in a project en masse. In fact, it provides two ways: by date,
+which selects the revisions based on the time that they were committed,
+and by tag, which retrieves a previously marked "snapshot" of the
+project.
+
+<p>Which method you use depends on the situation. The date-based
+retrievals are done by passing update the -D flag, which is similar to
+-r but takes dates instead of revision numbers:
+
+<pre>floss$ cvs -q update -D "1999-04-19"
+U hello.c
+U a-subdir/subsubdir/fish.c
+U b-subdir/random.c
+floss$
+</pre>
+
+<p>With the -D option, update retrieves the highest revision of each file
+as of the given date, and it will revert the files in the working copy
+to prior revisions if necessary.
+
+<p>When you give the date, you can, and often should, include the time.
+For example, the previous command ended up retrieving revision 1.1 of
+everything (only three files showed changes, because all of the others
+are still at revision 1.1 anyway). Here's the status of hello.c to
+prove it:
+
+<pre>floss$ cvs -Q status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+ Working revision: 1.1.1.1 Sat Apr 24 22:45:03 1999
+ Repository revision: 1.1.1.1 /usr/local/cvs/myproj/hello.c,v
+ Sticky Date: 99.04.19.05.00.00
+floss$
+</pre>
+
+<p>But a glance back at the log messages from earlier in this chapter shows
+that revision 1.2 of hello.c was definitely committed on April 19,
+1999. So why did we now get revision 1.1 instead of 1.2?
+
+<p>The problem is that the date "1999-04-19" was interpreted as meaning
+"the midnight that begins 1999-04-19" - that is, the very first instant
+on that date. This is probably not what you want. The 1.2 commit took
+place later in the day. By qualifying the date more precisely, we can
+retrieve revision 1.2:
+
+<pre>floss$ cvs -q update -D "1999-04-19 23:59:59"
+U hello.c
+U a-subdir/subsubdir/fish.c
+U b-subdir/random.c
+floss$ cvs status hello.c
+===================================================================
+File: hello.c Status: Locally Modified
+ Working revision: 1.2 Sat Apr 24 22:45:22 1999
+ Repository revision: 1.2 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: 99.04.20.04.59.59
+ Sticky Options: (none)
+floss$
+</pre>
+
+<p>We're almost there. If you look closely at the date/time on the Sticky
+Date line, it seems to indicate 4:59:59 A.M., not 11:59 as the command
+requested (later we'll get to what the "sticky" means). As you may have
+guessed, the discrepancy is due to the difference between local time and
+Universal Coordinated Time (also known as "Greenwich mean time"). The
+repository always stores dates in Universal Time, but CVS on the client
+side usually assumes the local system time zone. In the case of -D,
+this is rather unfortunate because you're probably most interested in
+comparing against the repository time and don't care about the local
+system's idea of time. You can get around this by specifying the GMT
+zone in the command:
+
+<pre>floss$ cvs -q update -D "1999-04-19 23:59:59 GMT"
+U hello.c
+floss$ cvs -q status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+ Working revision: 1.2 Sun Apr 25 22:38:53 1999
+ Repository revision: 1.2 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: 99.04.19.23.59.59
+ Sticky Options: (none)
+floss$
+</pre>
+
+<p>There - that brought the working copy back to the final commits from
+April 19 (unless there were any commits during the last second of the
+day, which there weren't).
+
+<p>What happens now if you run update?
+
+<pre>floss$ cvs update
+cvs update: Updating .
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+floss$
+</pre>
+
+<p>Nothing happens at all. But you know that there are more recent
+versions of at least three files. Why aren't these included in your
+working copy?
+
+<p>That's where the "sticky" comes in. Updating ("downdating"?) with the
+-D flag causes the working copy to be restricted permanently to that
+date or before. In CVS terminology, the working copy has a "sticky
+date" set. Once a working copy has acquired a sticky property, it stays
+sticky until told otherwise. Therefore, subsequent updates will not
+automatically retrieve the most recent revision. Instead, they'll stay
+restricted to the sticky date. Stickiness can be revealed by running
+cvs status or by directly examining the CVS/Entries file:
+
+<pre>floss$ cvs -q update -D "1999-04-19 23:59:59 GMT"
+U hello.c
+floss$ cat CVS/Entries
+D/a-subdir////
+D/b-subdir////
+D/c-subdir////
+/README.txt/1.1.1.1/Sun Apr 18 18:18:22 1999//D99.04.19.23.59.59
+/hello.c/1.2/Sun Apr 25 23:07:29 1999//D99.04.19.23.59.59
+floss$
+</pre>
+
+<p>If you were to modify hello.c and then try to commit
+
+<pre>floss$ cvs update
+M hello.c
+floss$ cvs ci -m "trying to change the past"
+cvs commit: cannot commit with sticky date for file 'hello.c'
+cvs [commit aborted]: correct above errors first!
+floss$
+</pre>
+
+<p>CVS would not permit the commit to happen because that would be like
+allowing you to go back and change the past. CVS is all about record
+keeping and, therefore, will not allow you to do that.
+
+<p>This does not mean CVS is unaware of all the revisions that have been
+committed since that date, however. You can still compare the
+sticky-dated working copy against other revisions, including future
+ones:
+
+<pre>floss$ cvs -q diff -c -r 1.5 hello.c
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.5
+diff -c -r1.5 hello.c
+*** hello.c 1999/04/24 22:09:27 1.5
+--- hello.c 1999/04/25 00:08:44
+***************
+*** 3,9 ****
+ void
+ main ()
+ {
+ printf ("Hello, world!\n");
+- printf ("between hello and goodbye\n");
+ printf ("Goodbye, world!\n");
+ }
+--- 3,9 --
+ void
+ main ()
+ {
++ /* this line was added to a downdated working copy */
+ printf ("Hello, world!\n");
+ printf ("Goodbye, world!\n");
+ }
+</pre>
+
+<p>This diff reveals that, as of April 19, 1999, the between hello and
+goodbye line had not yet been added. It also shows the modification
+that we made to the working copy (adding the comment shown in the
+preceding code snippet).
+
+<p>You can remove a sticky date (or any sticky property) by updating with
+the -A flag (-A stands for "reset", don't ask me why), which brings the
+working copy back to the most recent revisions:
+
+<pre>floss$ cvs -q update -A
+U hello.c
+floss$ cvs status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+ Working revision: 1.5 Sun Apr 25 22:50:27 1999
+ Repository revision: 1.5 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+floss$
+</pre>
+
+<p><hr>
+Node:<a name="Acceptable_Date_Formats">Acceptable Date Formats</a>,
+Next:<a rel=next href="#Marking_A_Moment_In_Time__Tags_">Marking A Moment In Time (Tags)</a>,
+Previous:<a rel=previous href="#Getting_Snapshots__Dates_And_Tagging_">Getting Snapshots (Dates And Tagging)</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Acceptable Date Formats</h3>
+
+<p>CVS accepts a wide range of syntaxes to specify dates. You'll never go
+wrong if you use ISO 8601 format (that is, the International Standards
+Organization standard #8601, see also
+www.saqqara.demon.co.uk/datefmt.htm), which is the format used in the
+preceding examples. You can also use Internet email dates as described
+in RFC 822 and RFC 1123 (see www.rfc-editor.org/rfc/). Finally, you can
+use certain unambiguous English constructs to specify dates relative to
+the current date.
+
+<p>You will probably never need all of the formats available, but here are
+some more examples to give you an idea of what CVS accepts:
+
+<pre>floss$ cvs update -D "19 Apr 1999"
+floss$ cvs update -D "19 Apr 1999 20:05"
+floss$ cvs update -D "19/04/1999"
+floss$ cvs update -D "3 days ago"
+floss$ cvs update -D "5 years ago"
+floss$ cvs update -D "19 Apr 1999 23:59:59 GMT"
+floss$ cvs update -D "19 Apr"
+</pre>
+
+<p>The double quotes around the dates are there to ensure that the Unix
+shell treats the date as one argument even if it contains spaces. The
+quotes will do no harm if the date doesn't contain spaces, so it's
+probably best to always use them.
+
+<p><hr>
+Node:<a name="Marking_A_Moment_In_Time__Tags_">Marking A Moment In Time (Tags)</a>,
+Previous:<a rel=previous href="#Acceptable_Date_Formats">Acceptable Date Formats</a>,
+Up:<a rel=up href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>
+<br>
+
+<h3>Marking A Moment In Time (Tags)</h3>
+
+<p>Retrieving by date is useful when the mere passage of time is your main
+concern. But more often what you really want to do is retrieve the
+project as it was at the time of a specific event - perhaps a public
+release, a known stable point in the software's development, or the
+addition or removal of some major feature.
+
+<p>Trying to remember the date when that event took place or deducing the
+date from log messages would be a tedious process. Presumably, the
+event, because it was important, was marked as such in the formal
+revision history. The method CVS offers for making such marks is known
+as <dfn>tagging</dfn>.
+
+<p>Tags differ from commits in that they don't record any particular
+textual change to files, but rather a change in the developers' attitude
+about the files. A tag gives a label to the collection of revisions
+represented by one developer's working copy (usually, that working copy
+is completely up to date so the tag name is attached to the "latest and
+greatest" revisions in the repository).
+
+<p>Setting a tag is as simple as this:
+
+<pre>floss$ cvs -q tag Release-1999_05_01
+T README.txt
+T hello.c
+T a-subdir/whatever.c
+T a-subdir/subsubdir/fish.c
+T b-subdir/random.c
+floss$
+</pre>
+
+<p>That command associates the symbolic name "Release-1999_05_01" with the
+snapshot represented by this working copy. Defined formally, snapshot
+means a set of files and associated revision numbers from the project.
+Those revision numbers do not have to be the same from file to file and,
+in fact, usually aren't. For example, assuming that tag was done on the
+same myproj directory that we've been using throughout this chapter and
+that the working copy was completely up to date, the symbolic name
+"Release-1999_05_01" will be attached to hello.c at revision 1.5, to
+fish.c at revision 1.2, to random.c at revision 1.2, and to everything
+else at revision 1.1.
+
+<p>It may help to visualize a tag as a path or string linking various
+revisions of files in the project. In Figure 2.1, an imaginary string
+passes through the tagged revision number of each file in a project.
+
+<pre>
+ File A File B File C File D File E
+ ------ ------ ------ ------ ------
+ 1.1 1.1 1.1 1.1 1.1
+ ----1.2-. 1.2 1.2 1.2 1.2
+ 1.3 | 1.3 1.3 1.3 1.3
+ \ 1.4 .-1.4-. 1.4 1.4
+ \ 1.5 / 1.5 \ 1.5 1.5
+ \ 1.6 / 1.6 | 1.6 1.6
+ \ 1.7 / | 1.7 1.7
+ \ 1.8 / | 1.8 .-1.8-------&gt;
+ \ 1.9 / | 1.9 / 1.9
+ `1.10' | 1.10 / 1.10
+ 1.11 | 1.11 |
+ | 1.12 |
+ | 1.13 |
+ \ 1.14 |
+ \ 1.15 /
+ \ 1.16 /
+ `-1.17-'
+
+[Figure 2.1: How a tag might stand in relation to files's revisions.]
+
+</pre>
+
+<p>But if you pull the string taut and sight directly along it, you'll see
+a particular moment in the project's history - namely, the moment that
+the tag was set (Figure 2.2).
+
+<pre>
+ File A File B File C File D File E
+ ------ ------ ------ ------ ------
+ 1.1
+ 1.2
+ 1.3
+ 1.4
+ 1.5
+ 1.6
+ 1.7
+ 1.1 1.8
+ 1.2 1.9
+ 1.3 1.10 1.1
+ 1.4 1.11 1.2
+ 1.5 1.12 1.3
+ 1.6 1.13 1.4
+ 1.7 1.1 1.14 1.5
+ 1.8 1.2 1.15 1.6
+ 1.1 1.9 1.3 1.16 1.7
+ ----1.2---------1.10--------1.4---------1.17--------1.8-------&gt;
+ 1.3 1.11 1.5 1.17 1.9
+ 1.6 1.17 1.10
+
+[Figure 2.2: The same tag as a "straight sight" through the revision history.]
+
+</pre>
+
+<p>As you continue to edit files and commit changes, the tag will not move
+along with the increasing revision numbers. It stays fixed, "stickily",
+at the revision number of each file at the time the tag was made.
+
+<p>Given their importance as descriptors, it's a bit unfortunate that log
+messages can't be included with tags or that the tags themselves can't
+be full paragraphs of prose. In the preceding example, the tag is
+fairly obviously stating that the project was in a releasable state as
+of a certain date. However, sometimes you may want to make snapshots of
+a more complex state, which can result in ungainly tag names such as:
+
+<pre>floss$ cvs tag testing-release-3_pre-19990525-public-release
+</pre>
+
+<p>As a general rule, you should try to keep tags as terse as possible
+while still including all necessary information about the event that
+you're trying to record. When in doubt, err on the side of being overly
+descriptive - you'll be glad later when you're able to tell from some
+verbose tag name exactly what circumstance was recorded.
+
+<p>You've probably noticed that no periods or spaces were used in the tag
+names. CVS is rather strict about what constitutes a valid tag name.
+The rules are that it must start with a letter and contain letters,
+digits, hyphens ("-"), and underscores ("_"). No spaces, periods,
+colons, commas, or any other symbols may be used.
+
+<p>To retrieve a snapshot by tag name, the tag name is used just like a
+revision number. There are two ways to retrieve snapshots: You can
+check out a new working copy with a certain tag, or you can switch an
+existing working copy over to a tag. Both result in a working copy
+whose files are at the revisions specified by the tag.
+
+<p>Most of the time, what you're trying to do is take a look at the project
+as it was at the time of the snapshot. You may not necessarily want to
+do this in your main working copy, where you presumably have uncommitted
+changes and other useful states built up, so let's assume you just want
+to check out a separate working copy with the tag. Here's how (but make
+sure to invoke this somewhere other than in your existing working copy
+or its parent directory!):
+
+<pre>floss$ cvs checkout -r Release-1999_05_01 myproj
+cvs checkout: Updating myproj
+U myproj/README.txt
+U myproj/hello.c
+cvs checkout: Updating myproj/a-subdir
+U myproj/a-subdir/whatever.c
+cvs checkout: Updating myproj/a-subdir/subsubdir
+U myproj/a-subdir/subsubdir/fish.c
+cvs checkout: Updating myproj/b-subdir
+U myproj/b-subdir/random.c
+cvs checkout: Updating myproj/c-subdir
+</pre>
+
+<p>We've seen the -r option before in the update command, where it preceded
+a revision number. In many ways a tag is just like a revision number
+because, for any file, a given tag corresponds to exactly one revision
+number (it's illegal, and generally impossible, to have two tags of the
+same name in the same project). In fact, anywhere you can use a
+revision number as part of a CVS command, you can use a tag name instead
+(as long as the tag has been set previously). If you want to diff a
+file's current state against its state at the time of the last release,
+you can do this:
+
+<pre>floss$ cvs diff -c -r Release-1999_05_01 hello.c
+</pre>
+
+<p>And if you want to revert it temporarily to that revision, you can do
+this:
+
+<pre>floss$ cvs update -r Release-1999_05_01 hello.c
+</pre>
+
+<p>The interchangeability of tags and revision numbers explains some of the
+strict rules about valid tag names. Imagine if periods were legal in
+tag names; you could have a tag named "1.3" attached to an actual
+revision number of "1.47". If you then issued the command
+
+<pre>floss$ cvs update -r 1.3 hello.c
+</pre>
+
+<p>how would CVS know whether you were referring to the tag named "1.3", or
+the much earlier revision 1.3 of hello.c? Thus, restrictions are placed
+on tag names so that they can always be easily distinguished from
+revision numbers. A revision number has a period; a tag name
+doesn't. (There are reasons for the other restrictions, too, mostly
+having to do with making tag names easy for CVS to parse.)
+
+<p>As you've probably guessed by this point, the second method of
+retrieving a snapshot - that is, switching an existing working
+directory over to the tagged revisions-is also done by updating:
+
+<pre>floss$ cvs update -r Release-1999_05_01
+cvs update: Updating .
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+cvs update: Updating c-subdir
+floss$
+</pre>
+
+<p>The preceding command is just like the one we used to revert hello.c to
+<code>Release-1999_05_01</code>, except that the filename is omitted because
+we want to revert the entire project over. (You can, if you want,
+revert just one subtree of the project to the tag by invoking the
+preceding command in that subtree instead of from the top level,
+although you hardly ever would want to do that.)
+
+<p>Note that no files appear to have changed when we updated. The working
+copy was completely up to date when we tagged, and no changes had been
+committed since the tagging.
+
+<p>However, this does not mean that nothing changed at all. The working
+copy now knows that it's at a tagged revision. When you make a change
+and try to commit it (let's assume we modified hello.c):
+
+<pre>floss$ cvs -q update
+M hello.c
+floss$ cvs -q ci -m "trying to commit from a working copy on a tag"
+cvs commit: sticky tag 'Release-1999_05_01' for file 'hello.c' is not a branch
+cvs [commit aborted]: correct above errors first!
+floss$
+</pre>
+
+<p>CVS does not permit the commit to happen. (Don't worry about the exact
+meaning of that error message yet - we'll cover branches next in this
+chapter.) It doesn't matter whether the working copy got to be on a tag
+via a checkout or an update. Once it is on a tag, CVS views the working
+copy as a static snapshot of a moment in history, and CVS won't let you
+change history, at least not easily. If you run cvs status or look at
+the CVS/Entries files, you'll see that there is a sticky tag set on each
+file. Here's the top level Entries file, for example:
+
+<pre>floss$ cat CVS/Entries
+D/a-subdir////
+D/b-subdir////
+D/c-subdir////
+/README.txt/1.1.1.1/Sun Apr 18 18:18:22 1999//TRelease-1999_05_01
+/hello.c/1.5/Tue Apr 20 07:24:10 1999//TRelease-1999_05_01
+floss$
+</pre>
+
+<p>Tags, like other sticky properties, are removed with the -A flag to
+update:
+
+<pre>floss$ cvs -q update -A
+M hello.c
+floss$
+</pre>
+
+<p>The modification to hello.c did not go away, however; CVS is still aware
+that the file changed with respect to the repository:
+
+<pre>floss$ cvs -q diff -c hello.c
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.5
+diff -c -r1.5 hello.c
+*** hello.c 1999/04/20 06:12:56 1.5
+--- hello.c 1999/05/04 20:09:17
+***************
+*** 6,9 ****
+--- 6,10 --
+ printf ("Hello, world!\n");
+ printf ("between hello and goodbye\n");
+ printf ("Goodbye, world!\n");
++ /* a comment on the last line */
+ }
+floss$
+</pre>
+
+<p>Now that you've reset with update, CVS will accept a commit:
+
+<pre>floss$ cvs ci -m "added comment to end of main function"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+cvs commit: Examining c-subdir
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;- hello.c
+new revision: 1.6; previous revision: 1.5
+done
+floss$
+</pre>
+
+<p>The tag <code>Release-1999_05_01</code> is still attached to revision 1.5, of
+course. Compare the file's status before and after a reversion to the
+tag:
+
+<pre>floss$ cvs -q status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+ Working revision: 1.6 Tue May 4 20:09:17 1999
+ Repository revision: 1.6 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: (none)
+ Sticky Date: (none)
+ Sticky Options: (none)
+floss$ cvs -q update -r Release-1999_05_01
+U hello.c
+floss$ cvs -q status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+ Working revision: 1.5 Tue May 4 20:21:12 1999
+ Repository revision: 1.5 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: Release-1999_05_01 (revision: 1.5)
+ Sticky Date: (none)
+ Sticky Options: (none)
+floss$
+</pre>
+
+<p>Now, having just told you that CVS doesn't let you change history, I'll
+show you how to change history.
+
+<p><hr>
+Node:<a name="Branches">Branches</a>,
+Previous:<a rel=previous href="#Other_Useful_CVS_Commands">Other Useful CVS Commands</a>,
+Up:<a rel=up href="#An_Overview_of_CVS">An Overview of CVS</a>
+<br>
+
+<h2>Branches</h2>
+
+<p>We've been viewing CVS as a kind of intelligent, coordinating library.
+However, it can also be thought of as a time machine (thanks to Jim
+Blandy for the analogy). So far, we've only seen how you can examine
+the past with CVS, without affecting anything. Like all good time
+machines, CVS also allows you to go back in time to change the past.
+What do you get then? Science fiction fans know the answer to that
+question: an alternate universe, running parallel to ours, but diverging
+from ours at exactly the point where the past was changed. A CVS branch
+splits a project's development into separate, parallel histories.
+Changes made on one branch do not affect the other.
+
+<ul>
+<li><a href="#Branching_Basics">Branching Basics</a>:
+<li><a href="#Merging_Changes_From_Branch_To_Trunk">Merging Changes From Branch To Trunk</a>:
+<li><a href="#Multiple_Merges">Multiple Merges</a>:
+<li><a href="#Creating_A_Tag_Or_Branch_Without_A_Working_Copy">Creating A Tag Or Branch Without A Working Copy</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Branching_Basics">Branching Basics</a>,
+Next:<a rel=next href="#Merging_Changes_From_Branch_To_Trunk">Merging Changes From Branch To Trunk</a>,
+Up:<a rel=up href="#Branches">Branches</a>
+<br>
+
+<h3>Branching Basics</h3>
+
+<p>Why are branches useful?
+
+<p>Let's return for a moment to the scenario of the developer who, in the
+midst of working on a new version of the program, receives a bug report
+about an older released version. Assuming the developer fixes the
+problem, she still needs a way to deliver the fix to the customer. It
+won't help to just find an old copy of the program somewhere, patch it
+up without CVS's knowledge, and ship it off. There would be no record
+of what was done; CVS would be unaware of the fix; and later if
+something was discovered to be wrong with the patch, no one would have a
+starting point for reproducing the problem.
+
+<p>It's even more ill-advised to fix the bug in the current, unstable
+version of the sources and ship that to the customer. Sure, the
+reported bug may be solved, but the rest of the code is in a
+half-implemented, untested state. It may run, but it's certainly not
+ready for prime time.
+
+<p>Because the last released version is thought to be stable, aside from
+this one bug, the ideal solution is to go back and correct the bug in
+the old release - that is, to create an alternate universe in which the
+last public release includes this bug fix.
+
+<p>That's where branches come in. The developer splits off a branch,
+rooted in the main line of development (the trunk) not at its most
+recent revisions, but back at the point of the last release. Then she
+checks out a working copy of this branch, makes whatever changes are
+necessary to fix the bug, and commits them on that branch, so there's a
+record of the bug fix. Now she can package up an interim release based
+on the branch and ship it to the customer.
+
+<p>Her change won't have affected the code on the trunk, nor would she want
+it to without first finding out whether the trunk needs the same bug fix
+or not. If it does, she can merge the branch changes into the trunk.
+In a merge, CVS calculates the changes made on the branch between the
+point where it diverged from the trunk and the branch's tip (its most
+recent state), then applies those differences to the project at the tip
+of the trunk. The difference between the branch's root and its tip
+works out, of course, to be precisely the bug fix.
+
+<p>Another good way to think of a merge is as a special case of updating.
+The difference is that in a merge, the changes to be incorporated are
+derived by comparing the branch's root and tip, instead of by comparing
+the working copy against the repository.
+
+<p>The act of updating is itself similar to receiving patches directly from
+their authors and applying them by hand. In fact, to do an update, CVS
+calculates the difference (that's "difference" as in the diff program)
+between the working copy and the repository and then applies that diff
+to the working copy just as the patch program would. This mirrors the
+way in which a developer takes changes from the outside world, by
+manually applying patch files sent in by contributors.
+
+<p>Thus, merging the bug fix branch into the trunk is just like accepting
+some outside contributor's patch to fix the bug. The contributor would
+have made the patch against the last released version, just as the
+branch's changes are against that version. If that area of code in the
+current sources hasn't changed much since the last release, the merge
+will succeed with no problems. If the code is now substantially
+different, however, the merge will fail with conflict (that is, the
+patch will be rejected), and some manual fiddling will be necessary.
+Usually this is accomplished by reading the conflicting area, making the
+necessary changes by hand, and committing. Figure 2.3 shows a picture
+of what happens in a branch and merge.
+
+<pre>
+ (branch on which bug was fixed)
+ .----------------&gt;---------------.
+ / |
+ / |
+ / |
+ / |
+ / V (&lt;------ point of merge)
+ ====*===================================================================&gt;
+ (main line of development)
+
+
+[Figure 2.3: A branch and then a merge. Time flows left to right.]
+
+</pre>
+
+<p>We'll now walk through the steps necessary to make this picture happen.
+Remember that it's not really time that's flowing from left to right in
+the diagram, but rather the revision history. The branch will not have
+been made at the time of the release, but is created later, rooted back
+at the release's revisions.
+
+<p>In our case, let's assume the files in the project have gone through
+many revisions since they were tagged as <code>Release-1999_05_01</code>, and
+perhaps files have been added as well. When the bug report regarding
+the old release comes in, the first thing we'll want to do is create a
+branch rooted at the old release, which we conveniently tagged
+<code>Release-1999_05_01</code>.
+
+<p>One way to do this is to first check out a working copy based on that
+tag, then create the branch by re-tagging with the -b (branch) option:
+
+<pre>floss$ cd ..
+floss$ ls
+myproj/
+floss$ cvs -q checkout -d myproj_old_release -r Release-1999_05_01 myproj
+U myproj_old_release/README.txt
+U myproj_old_release/hello.c
+U myproj_old_release/a-subdir/whatever.c
+U myproj_old_release/a-subdir/subsubdir/fish.c
+U myproj_old_release/b-subdir/random.c
+floss$ ls
+myproj/ myproj_old_release/
+floss$ cd myproj_old_release
+floss$ ls
+CVS/ README.txt a-subdir/ b-subdir/ hello.c
+floss$ cvs -q tag -b Release-1999_05_01-bugfixes
+T README.txt
+T hello.c
+T a-subdir/whatever.c
+T a-subdir/subsubdir/fish.c
+T b-subdir/random.c
+floss$
+</pre>
+
+<p>Take a good look at that last command. It may seem somewhat arbitrary
+that tag is used to create branches, but there's actually a reason for
+it: The tag name will serve as a label by which the branch can be
+retrieved later. Branch tags do not look any different from non-branch
+tags, and are subject to the same naming restrictions. Some people like
+to always include the word branch in the tag name itself (for example,
+<code>Release-1999_05_01-bugfix-branch</code>), so they can distinguish branch
+tags from other kinds of tags. You may want to do this if you find
+yourself often retrieving the wrong tag.
+
+<p>(And while we're at it, note the -d myproj_old_release option to
+checkout in the first CVS command. This tells checkout to put the
+working copy in a directory called myproj_old_release, so we won't
+confuse it with the current version in myproj. Be careful not to
+confuse this use of -d with the global option of the same name, or with
+the -d option to update.)
+
+<p>Of course, merely running the tag command does not switch this working
+copy over to the branch. Tagging never affects the working copy; it
+just records some extra information in the repository to allow you to
+retrieve that working copy's revisions later on (as a static piece of
+history or as a branch, as the case may be).
+
+<p>Retrieval can be done one of two ways (you're probably getting used to
+this motif by now!). You can check out a new working copy on the branch
+
+<pre>floss$ pwd
+/home/whatever
+floss$ cvs co -d myproj_branch -r Release-1999_05_01-bugfixes myproj
+</pre>
+
+<p>or switch an existing working copy over to it:
+
+<pre>floss$ pwd
+/home/whatever/myproj
+floss$ cvs update -r Release-1999_05_01-bugfixes
+</pre>
+
+<p>The end result is the same (well, the name of the new working copy's
+top-level directory may be different, but that's not important for CVS's
+purposes). If your current working copy has uncommitted changes, you'll
+probably want to use checkout instead of update to access the branch.
+Otherwise, CVS attempts to merge your changes into the working copy as
+it switches it over to the branch. In that case, you might get
+conflicts, and even if you didn't, you'd still have an impure branch.
+It won't truly reflect the state of the program as of the designated
+tag, because some files in the working copy will contain modifications
+made by you.
+
+<p>Anyway, let's assume that by one method or another you get a working
+copy on the desired branch:
+
+<pre>floss$ cvs -q status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+ Working revision: 1.5 Tue Apr 20 06:12:56 1999
+ Repository revision: 1.5 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: Release-1999_05_01-bugfixes
+(branch: 1.5.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+floss$ cvs -q status b-subdir/random.c
+===================================================================
+File: random.c Status: Up-to-date
+ Working revision: 1.2 Mon Apr 19 06:35:27 1999
+ Repository revision: 1.2 /usr/local/cvs/myproj/b-subdir/random.c,v
+ Sticky Tag: Release-1999_05_01-bugfixes (branch: 1.2.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+floss$
+</pre>
+
+<p>(The contents of those <code>Sticky&nbsp;Tag</code> lines will be explained
+shortly.) If you modify hello.c and random.c, and commit
+
+<pre>floss$ cvs -q update
+M hello.c
+M b-subdir/random.c
+floss$ cvs ci -m "fixed old punctuation bugs"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;- hello.c
+new revision: 1.5.2.1; previous revision: 1.5
+done
+Checking in b-subdir/random.c;
+/usr/local/cvs/myproj/b-subdir/random.c,v &lt;- random.c
+new revision: 1.2.2.1; previous revision: 1.2
+done
+floss$
+</pre>
+
+<p>you'll notice that there's something funny going on with the revision
+numbers:
+
+<pre>floss$ cvs -q status hello.c b-subdir/random.c
+===================================================================
+File: hello.c Status: Up-to-date
+ Working revision: 1.5.2.1 Wed May 5 00:13:58 1999
+ Repository revision: 1.5.2.1 /usr/local/cvs/myproj/hello.c,v
+ Sticky Tag: Release-1999_05_01-bugfixes (branch: 1.5.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+===================================================================
+File: random.c Status: Up-to-date
+ Working revision: 1.2.2.1 Wed May 5 00:14:25 1999
+ Repository revision: 1.2.2.1 /usr/local/cvs/myproj/b-subdir/random.c,v
+ Sticky Tag: Release-1999_05_01-bugfixes (branch: 1.2.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+floss$
+</pre>
+
+<p>They now have four digits instead of two!
+
+<p>A closer look reveals that each file's revision number is just the
+branch number (as shown on the <code>Sticky&nbsp;Tag</code> line) plus an extra
+digit on the end.
+
+<p>What you're seeing is a little bit of CVS's inner workings. Although
+you almost always use a branch to mark a project-wide divergence, CVS
+actually records the branch on a per-file basis. This project had five
+files in it at the point of the branch, so five individual branches were
+made, all with the same tag name: <code>Release-1999_05_01-bugfixes</code>.
+
+<p>Most people consider this per-file scheme a rather inelegant
+implementation on CVS's part. It's a bit of the old RCS legacy showing
+through-RCS didn't know how to group files into projects, and even
+though CVS does, it still uses code inherited from RCS to handle
+branches.
+
+<p>Ordinarily, you don't need to be too concerned with how CVS is keeping
+track of things internally, but in this case, it helps to understand the
+relationship between branch numbers and revision numbers. Let's look at
+the hello.c file; everything I'm about to say about hello.c applies to
+the other files in the branch (with revision/branch numbers adjusted
+accordingly).
+
+<p>The hello.c file was on revision 1.5 at the point where the branch was
+rooted. When we created the branch, a new number was tacked onto the
+end to make a branch number (CVS chooses the first unused even, nonzero
+integer). Thus, the branch number in this case became <code>1.5.2</code>.
+The branch number by itself is not a revision number, but it is the root
+(that is, the prefix) of all the revision numbers for hello.c along this
+branch.
+
+<p>However, when we ran that first CVS status in a branched working copy,
+hello.c's revision number showed up as only <code>1.5</code>, not
+<code>1.5.2.0</code> or something similar. This is because the initial
+revision on a branch is always the same as the trunk revision of the
+file, where the branch sprouts off. Therefore, CVS shows the trunk
+revision number in status output, for as long as the file is the same on
+both branch and trunk.
+
+<p>Once we had committed a new revision, hello.c was no longer the same on
+both trunk and branch - the branch incarnation of the file had changed,
+while the trunk remained the same. Accordingly, hello.c was assigned
+its first branch revision number. We saw this in the status output
+after the commit, where its revision number is clearly <code>1.5.2.1</code>.
+
+<p>The same story applies to the random.c file. Its revision number at the
+time of branching was <code>1.2</code>, so its first branch is <code>1.2.2</code>,
+and the first new commit of random.c on that branch received the
+revision number <code>1.2.2.1</code>.
+
+<p>There is no numeric relationship between <code>1.5.2.1</code> and
+<code>1.2.2.1</code> - no reason to think that they are part of the same
+branch event, except that both files are tagged with
+<code>Release-1999_05_01-bugfixes</code>, and the tag is attached to branch
+numbers <code>1.5.2</code> and <code>1.2.2</code> in the respective files.
+Therefore, the tag name is your only handle on the branch as a
+project-wide entity. Although it is perfectly possible to move a file
+to a branch by using the revision number directly
+
+<pre>floss$ cvs update -r 1.5.2.1 hello.c
+U hello.c
+floss$
+</pre>
+
+<p>it is almost always ill-advised. You would be mixing the branch
+revision of one file with non-branch revisions of the others. Who knows
+what losses may result? It is better to use the branch tag to refer to
+the branch and do all files at once by not specifying any particular
+file. That way you don't have to know or care what the actual branch
+revision number is for any particular file.
+
+<p>It is also possible to have branches that sprout off other branches, to
+any level of absurdity. For example, if a file has a revision number of
+<code>1.5.4.37.2.3</code>, its revision history can be diagrammed like this:
+
+<pre> 1.1
+ |
+ 1.2
+ |
+ 1.3
+ |
+ 1.4
+ |
+ 1.5
+ / \
+ / \
+ / \
+ (1.5.2) (1.5.4) &lt;--- (these are branch numbers)
+ / \
+ 1.5.2.1 1.5.4.1
+ | |
+ 1.5.2.2 1.5.4.2
+ | |
+ (etc) (...) &lt;--- (collapsed 34 revisions for brevity)
+ |
+ 1.5.4.37
+ /
+ /
+ (1.5.4.37.2) &lt;--- (this is also a branch number)
+ /
+ /
+ 1.5.4.37.2.1
+ |
+ 1.5.4.37.2.2
+ |
+ 1.5.4.37.2.3
+
+[Figure 2.4: An unusually high degree of branching. Time flows downward.]
+
+</pre>
+
+<p>Admittedly, only the rarest circumstances make such a branching depth
+necessary, but isn't it nice to know that CVS will go as far as you're
+willing to take it? Nested branches are created the same way as any
+other branch: Check out a working copy on branch <code>N</code>, run cvs tag
+-b branchname in it, and you'll create branch <code>N.M</code> in the
+repository (where <code>N</code> represents the appropriate branch revision
+number in each file, such as <code>1.5.2.1</code>, and <code>M</code> represents the
+next available branch at the end of that number, such as <code>2</code>).
+
+<p><hr>
+Node:<a name="Merging_Changes_From_Branch_To_Trunk">Merging Changes From Branch To Trunk</a>,
+Next:<a rel=next href="#Multiple_Merges">Multiple Merges</a>,
+Previous:<a rel=previous href="#Branching_Basics">Branching Basics</a>,
+Up:<a rel=up href="#Branches">Branches</a>
+<br>
+
+<h3>Merging Changes From Branch To Trunk</h3>
+
+<p>Now that the bug fix has been committed on the branch, let's switch the
+working copy over to the highest trunk revisions and see if the bug fix
+needs to be done there, too. We'll move the working copy off the branch
+by using update -A (branch tags are like other sticky properties in this
+respect) and then diffing against the branch we just left:
+
+<pre>floss$ cvs -q update -d -A
+U hello.c
+U b-subdir/random.c
+floss$ cvs -q diff -c -r Release-1999_05_01-bugfixes
+Index: hello.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.5.2.1
+retrieving revision 1.6
+diff -c -r1.5.2.1 -r1.6
+*** hello.c 1999/05/05 00:15:07 1.5.2.1
+--- hello.c 1999/05/04 20:19:16 1.6
+***************
+*** 4,9 ****
+ main ()
+ {
+ printf ("Hello, world!\n");
+! printf ("between hello and good-bye\n");
+ printf ("Goodbye, world!\n");
+ }
+--- 4,10 --
+ main ()
+ {
+ printf ("Hello, world!\n");
+! printf ("between hello and goodbye\n");
+ printf ("Goodbye, world!\n");
++ /* a comment on the last line */
+ }
+Index: b-subdir/random.c
+===================================================================
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2
+diff -c -r1.2.2.1 -r1.2
+*** b-subdir/random.c 1999/05/05 00:15:07 1.2.2.1
+--- b-subdir/random.c 1999/04/19 06:35:27 1.2
+***************
+*** 4,8 ****
+ void main ()
+ {
+! printf ("A random number.\n");
+ }
+--- 4,8 --
+ void main ()
+ {
+! printf ("a random number\n");
+ }
+floss$
+</pre>
+
+<p>The diff shows that good-bye is spelled with a hyphen in the branch
+revision of hello.c, and that the trunk revision of that file has a
+comment near the end that the branch revision doesn't have. Meanwhile,
+in random.c, the branch revision has a capital "A" and a period, whereas
+the trunk doesn't.
+
+<p>To actually merge the branch changes into the current working copy, run
+update with the -j flag (the same j for "join" that we used to revert a
+file to an old revision before):
+
+<pre>floss$ cvs -q update -d -j Release-1999_05_01-bugfixes
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.5
+retrieving revision 1.5.2.1
+Merging differences between 1.5 and 1.5.2.1 into hello.c
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+retrieving revision 1.2
+retrieving revision 1.2.2.1
+Merging differences between 1.2 and 1.2.2.1 into random.c
+floss$ cvs -q update
+M hello.c
+M b-subdir/random.c
+floss$ cvs -q ci -m "merged from branch Release-1999_05_01-bugfixes"
+Checking in hello.c;
+/usr/local/cvs/myproj/hello.c,v &lt;- hello.c
+new revision: 1.7; previous revision: 1.6
+done
+Checking in b-subdir/random.c;
+/usr/local/cvs/myproj/b-subdir/random.c,v &lt;- random.c
+new revision: 1.3; previous revision: 1.2
+done
+floss$
+</pre>
+
+<p>This takes the changes from the branch's root to its tip and merges them
+into the current working copy (which subsequently shows those
+modifications just as though the files had been hand-edited into that
+state). The changes are then committed onto the trunk, since nothing in
+the repository changed when a working copy underwent a merge.
+
+<p>Although no conflicts were encountered in this example, it's quite
+possible (even probable) that there would be some in a normal merge. If
+that happens, they need to be resolved like any other conflict, and then
+committed.
+
+<p><hr>
+Node:<a name="Multiple_Merges">Multiple Merges</a>,
+Next:<a rel=next href="#Creating_A_Tag_Or_Branch_Without_A_Working_Copy">Creating A Tag Or Branch Without A Working Copy</a>,
+Previous:<a rel=previous href="#Merging_Changes_From_Branch_To_Trunk">Merging Changes From Branch To Trunk</a>,
+Up:<a rel=up href="#Branches">Branches</a>
+<br>
+
+<h3>Multiple Merges</h3>
+
+<p>Sometimes a branch will continue to be actively developed even after the
+trunk has undergone a merge from it. For example, this can happen if a
+second bug in the previous public release is discovered and has to be
+fixed on the branch. Maybe someone didn't get the joke in random.c, so
+on the branch, you have to add a line explaining it
+
+<pre>floss$ pwd
+/home/whatever/myproj_branch
+floss$ cat b-subdir/random.c
+/* Print out a random number. */
+#include &lt;stdio.h&gt;
+void main ()
+{
+ printf ("A random number.\n");
+ printf ("Get the joke?\n");
+}
+floss$
+</pre>
+
+<p>and commit. If that bug fix also needs to be merged into the trunk, you
+might be tempted to try the same update command as before in the trunk
+working copy to "re-merge":
+
+<pre>floss$ cvs -q update -d -j Release-1999_05_01-bugfixes
+RCS file: /usr/local/cvs/myproj/hello.c,v
+retrieving revision 1.5
+retrieving revision 1.5.2.1
+Merging differences between 1.5 and 1.5.2.1 into hello.c
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+retrieving revision 1.2
+retrieving revision 1.2.2.2
+Merging differences between 1.2 and 1.2.2.2 into random.c
+rcsmerge: warning: conflicts during merge
+floss$
+</pre>
+
+<p>As you can see, that didn't have quite the desired effect-we got a
+conflict, even though the trunk copy hadn't been modified there and,
+therefore, no conflict was expected.
+
+<p>The trouble was that the update command behaved exactly as described: It
+tried to take all the changes between the branch's root and tip and
+merge them into the current working copy. The only problem is, some of
+those changes had already been merged into this working copy. That's
+why we got the conflict:
+
+<pre>floss$ pwd
+/home/whatever/myproj
+floss$ cat b-subdir/random.c
+/* Print out a random number. */
+#include &lt;stdio.h
+void main ()
+{
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; random.c
+ printf ("A random number.\n");
+=======
+ printf ("A random number.\n");
+ printf ("Get the joke?\n");
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; 1.2.2.2
+}
+floss$
+</pre>
+
+<p>You could go through resolving all such conflicts by hand-it's usually
+not hard to tell what you need to do in each file. Nevertheless, it is
+even better to avoid a conflict in the first place. By passing two -j
+flags instead of one, you'll get only those changes from where you last
+merged to the tip instead of all of the changes on the branch, from root
+to tip. The first -j gives the starting point on the branch, and the
+second is just the plain branch name (which implies the tip of the
+branch).
+
+<p>The question then is, how can you specify the point on the branch from
+which you last merged? One way is to qualify by using a date along with
+the branch tag name. CVS provides a special syntax for this:
+
+<pre>floss$ cvs -q update -d -j "Release-1999_05_01-bugfixes:2 days ago" \
+ -j Release-1999_05_01-bugfixes
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.2
+Merging differences between 1.2.2.1 and 1.2.2.2 into random.c
+floss$
+</pre>
+
+<p>If the branch tag name is followed by a colon and then a date (in any of
+the usual CVS date syntaxes), CVS will include only changes later than
+that date. So if you knew that the original bug fix was committed on
+the branch three days ago, the preceding command would merge the second
+bug fix only.
+
+<p>A better way, if you plan ahead, is to tag the branch after each bug fix
+(just a regular tag - we're not starting a new branch here or anything
+like that). Suppose after fixing the bug in the branch and committing,
+you do this in the branch's working copy:
+
+<pre>floss$ cvs -q tag Release-1999_05_01-bugfixes-fix-number-1
+T README.txt
+T hello.c
+T a-subdir/whatever.c
+T a-subdir/subsubdir/fish.c
+T b-subdir/random.c
+floss$
+</pre>
+
+<p>Then, when it's time to merge the second change into the trunk, you can
+use that conveniently placed tag to delimit the earlier revision:
+
+<pre>floss$ cvs -q update -d -j Release-1999_05_01-bugfixes-fix-number-1 \
+ -j Release-1999_05_01-bugfixes
+RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
+retrieving revision 1.2.2.1
+retrieving revision 1.2.2.2
+Merging differences between 1.2.2.1 and 1.2.2.2 into random.c
+floss$
+</pre>
+
+<p>This way, of course, is much better than trying to recall how long ago
+you made one change versus another, but it only works if you remember to
+tag the branch every time it is merged to the trunk. The lesson,
+therefore, is to tag early and tag often! It's better to err on the side
+of too many tags (as long as they all have descriptive names) than to
+have too few. In these last examples, for instance, there was no
+requirement that the new tag on the branch have a name similar to the
+branch tag itself. Although I named it
+<code>Release-1999_05_01-bugfixes-fix-number-1</code>, it could just as easily
+have been <code>fix1</code>. However, the former is preferable, because it
+contains the name of the branch and thus won't ever be confused with a
+tag on some other branch. (Remember that tag names are unique within
+files, not within branches. You can't have two tags named <code>fix1</code>
+in the same file, even if they refer to revisions on different
+branches.)
+
+<p><hr>
+Node:<a name="Creating_A_Tag_Or_Branch_Without_A_Working_Copy">Creating A Tag Or Branch Without A Working Copy</a>,
+Previous:<a rel=previous href="#Multiple_Merges">Multiple Merges</a>,
+Up:<a rel=up href="#Branches">Branches</a>
+<br>
+
+<h3>Creating A Tag Or Branch Without A Working Copy</h3>
+
+<p>As stated earlier, tagging affects the repository, not the working copy.
+That begs the question: Why require a working copy at all when tagging?
+The only purpose that it serves is to designate which project and which
+revisions of the various files in the project are being tagged. If you
+could specify the project and revisions independently of the working
+copy, no working copy would be necessary.
+
+<p>There is such a way: the rtag command (for "repository tag"). It's very
+similar to tag; a couple of examples will explain its usage. Let's go
+back to the moment when the first bug report came in and we needed to
+create a branch rooted at the last public release. We checked out a
+working copy at the release tag and then ran <code>tag&nbsp;-b</code> on it:
+
+<pre>floss$ cvs tag -b Release-1999_05_01-bugfixes
+</pre>
+
+<p>This created a branch rooted at <code>Release-1999_05_01</code>. However,
+because we know the release tag, we could have used it in an rtag
+command to specify where to root the branch, not even bothering with a
+working copy:
+
+<pre>floss$ cvs rtag -b -r Release-1999_05_01 Release-1999_05_01-bugfixes myproj
+</pre>
+
+<p>That's all there is to it. That command can be issued from anywhere,
+inside or outside a working copy. However, your CVSROOT environment
+variable would have to point to the repository, of course, or you can
+specify it with the global -d option. It works for non-branch tagging,
+too, but it's less useful that way because you have to specify each
+file's revision number, one by one. (Or you can refer to it by tag, but
+then you'd obviously already have a tag there, so why would you want to
+set a second one on the exact same revisions?)
+
+<p>You now know enough to get around in CVS and probably enough to start
+working with other people on a project. There are still a few minor
+features that haven't been introduced, as well as some unmentioned but
+useful options to features already seen. These will all be presented as
+appropriate in chapters to come, in scenarios that will demonstrate both
+how and why to use them. When in doubt, don't hesitate to consult the
+Cederqvist manual; it is an indispensable resource for serious CVS
+users.
+
+<p><hr>
+Node:<a name="Repository_Administration">Repository Administration</a>,
+Next:<a rel=next href="#Advanced_CVS">Advanced CVS</a>,
+Previous:<a rel=previous href="#An_Overview_of_CVS">An Overview of CVS</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>Repository Administration</h1>
+
+<p>In <a href="#An_Overview_of_CVS">An Overview of CVS</a>, you learned enough CVS to use it
+effectively as a project participant. If you're going to be a project
+maintainer, however, you'll need to know how to install CVS and
+administer repositories. In this chapter, we'll throw back the curtain
+and look in detail at how the repository is structured, and how CVS uses
+it. You'll learn all the major steps CVS goes through during updates
+and commits, and how you can modify its behavior. By understanding how
+CVS works, you'll also be able to trace problems to their causes, and
+fix them in maintainable ways.
+
+<p>This may sound very involved, but remember that CVS has already proven
+quite long-lived, and will probably be around for many years to come.
+Whatever you learn now will be useful for a long time. CVS also tends
+to become more indispensable the more you use it. If you're going to be
+that dependent on something (and trust me, you are), it's worth really
+getting to know it.
+
+<p>With that in mind, let's begin at the beginning: putting CVS on your
+system.
+
+<ul>
+<li><a href="#Getting_And_Installing_CVS">Getting And Installing CVS</a>: Putting CVS on your system.
+<li><a href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>: What's in the CVS distribution.
+<li><a href="#Starting_A_Repository">Starting A Repository</a>: Setting up a repository.
+<li><a href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a>: One method of remote access.
+<li><a href="#Anonymous_Access">Anonymous Access</a>: Granting access to the public.
+<li><a href="#Repository_Structure">Repository Structure</a>: How the repository is arranged.
+<li><a href="#RCS_Format">RCS Format</a>: How repository storage works.
+<li><a href="#What_Happens_When_You_Remove_A_File">What Happens When You Remove A File</a>: CVS keeps an Attic for old files.
+<li><a href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>: Run-time server configuration files.
+<li><a href="#Commit_Emails">Commit Emails</a>: Arranging automatic commit notices.
+<li><a href="#Finding_Out_More">Finding Out More</a>: Other sources of information.
+</ul>
+
+<p><hr>
+Node:<a name="Getting_And_Installing_CVS">Getting And Installing CVS</a>,
+Next:<a rel=next href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>Getting And Installing CVS</h2>
+
+<p>In many cases, you won't have to go out and get CVS, because it will
+already be on your system. If you run one of the major Linux or FreeBSD
+distributions, it's probably already installed in /usr/bin or some other
+likely location. If not, Red Hat Linux users can usually find an RPM
+(Red Hat Package) for the latest, or nearly latest, version of CVS in
+their distributions. And Debian users can install the latest Debian
+package with these commands:
+
+<pre>floss$ apt-get update
+floss$ apt-get install cvs
+</pre>
+
+<p>If CVS isn't already on your machine, you'll probably have to build it
+from source. If you're a non-Unix user, you'll probably find it easier
+to get a prebuilt binary for your operating system (more on that later).
+Fortunately, CVS is fully <dfn>autoconfiscated</dfn> - that is, it uses the
+GNU autoconfiguration mechanism, making compilation from source
+surprisingly easy.
+
+<ul>
+<li><a href="#Getting_And_Building_CVS_Under_Unix">Getting And Building CVS Under Unix</a>:
+<li><a href="#Getting_And_Installing_CVS_Under_Windows">Getting And Installing CVS Under Windows</a>:
+<li><a href="#Getting_And_Installing_CVS_On_A_Macintosh">Getting And Installing CVS On A Macintosh</a>:
+<li><a href="#Limitations_Of_The_Windows_And_Macintosh_Versions">Limitations Of The Windows And Macintosh Versions</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Getting_And_Building_CVS_Under_Unix">Getting And Building CVS Under Unix</a>,
+Next:<a rel=next href="#Getting_And_Installing_CVS_Under_Windows">Getting And Installing CVS Under Windows</a>,
+Up:<a rel=up href="#Getting_And_Installing_CVS">Getting And Installing CVS</a>
+<br>
+
+<h3>Getting And Building CVS Under Unix</h3>
+
+<p>As of this writing, there are two canonical sites from which you can
+download CVS. One is the Free Software Foundation's FTP site,
+<a href="ftp://ftp.gnu.org/gnu/cvs/">ftp://ftp.gnu.org/gnu/cvs/</a>, which offers CVS as an official GNU
+tool. The other is Cyclic Software's download site. Cyclic Software
+is, if not the maintainer of CVS, then the "maintainer of the
+maintainers", by providing a repository server and download access for
+users and developers. They distribute releases from
+<a href="http://download.cyclic.com/pub/">http://download.cyclic.com/pub/</a>.
+
+<p>Either location is fine. In the following example, I use Cyclic
+Software's site. If you point your FTP client (probably your Web
+browser) there, you'll see a list of directories, something like this:
+
+<pre>Index of /pub
+ cvs-1.10.5/ 18-Feb-99 21:36 -
+ cvs-1.10.6/ 17-May-99 10:34 -
+ cvs-1.10/ 09-Dec-98 17:26 -
+ macintosh/ 23-Feb-99 00:53 -
+ os2/ 09-Dec-98 17:26 -
+ packages/ 09-Dec-98 17:26 -
+ rcs/ 09-Dec-98 17:26 -
+ tkcvs/ 09-Dec-98 17:26 -
+ training/ 09-Dec-98 17:26 -
+ unix/ 09-Dec-98 17:26 -
+ vms/ 09-Dec-98 17:26 -
+</pre>
+
+<p>Pay attention to the directories beginning with "cvs-" (you can ignore
+most of the others). There are three such directories, which means that
+you're already faced with a choice: Get the designated "stable" release,
+or go with a newer (but less-tested) interim release. The stable
+releases have only one decimal point, as in "cvs-1.10", whereas the
+interim releases have minor version increments tacked on the end, as in
+"1.10.5".
+
+<p>The GNU site usually only offers the major releases, not the interim
+ones, so you won't see all of this if you get CVS from there. In
+general, the interim releases have been pretty safe, and sometimes
+contain fixes to bugs that were found in the major release. Your best
+policy is to go with the highest interim release, but if you encounter
+any problems with it, be prepared to drop back to the previous release,
+as many times as necessary. The highest release listed in the earlier
+example is cvs-1.10.6. Entering that directory, we see this:
+
+<pre>Index of /pub/cvs-1.10.6
+ cvs-1.10.6.tar.gz 17-May-99 08:44 2.2M
+</pre>
+
+<p>That's it - the full source code to CVS. Just download it to your
+machine, and you're ready to build. At this point, if you're already
+familiar with the standard build process for GNU tools, you know what to
+do and probably don't need to read anything between here and the section
+<a href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>. On the other hand, if you're not
+sure how to proceed, then read on....
+
+<p>The following compilation instructions and examples assume that you have
+a fairly standard distribution of Unix. Any of the free versions of
+Unix (for example, FreeBSD or Linux) should work with no problem, as
+should the major commercial Unix versions (such as SunOS/Solaris, AIX,
+HP-UX, or Ultrix). Even if these instructions don't work for you
+exactly as written, don't give up hope. Although covering the details
+of compiling on every operating system is beyond the scope of this book,
+I'll give some pointers to other help resources later in this chapter.
+
+<p>Anyway, to proceed with the compilation, first unpack the tar file using
+GNU gunzip and tar (if you don't have these installed on your system,
+you can get gunzip from <a href="ftp://ftp.gnu.org/gnu/gzip/">ftp://ftp.gnu.org/gnu/gzip/</a> and GNU's
+version of tar from <a href="ftp://ftp.gnu.org/gnu/tar/">ftp://ftp.gnu.org/gnu/tar/</a>):
+
+<pre>floss$ gunzip cvs-1.10.6.tar.gz
+floss$ tar xvf cvs-1.10.6.tar
+</pre>
+
+<p>You'll see a lot of file names fly by on your screen.
+
+<p>Now you have a new directory on your machine - cvs-1.10.6 - and it is
+populated with the CVS source code. Go into that directory and
+configure CVS for your system, by using the provided configure script:
+
+<pre>floss$ cd cvs-1.10.6
+floss$ ./configure
+creating cache ./config.cache
+checking for gcc... gcc
+checking whether we are using GNU C... yes
+checking whether gcc accepts -g... yes
+checking how to run the C preprocessor... gcc -E
+ (etc)
+</pre>
+
+<p>When the configure command finishes, the source tree will know
+everything it needs to know about compiling on your machine. The next
+step is to type:
+
+<pre>floss$ make
+</pre>
+
+<p>You'll see lots of output fly by, then type:
+
+<pre>floss$ make install
+</pre>
+
+<p>You'll see yet more output fly by; when it's all over, CVS will be
+installed on your system. (You will probably need to do that last step
+as the superuser.)
+
+<p>By default, the CVS executable will end up as <code>/usr/local/bin/cvs</code>.
+This assumes you have a decent make program installed on your system
+(again, if you don't have one, get the GNU project's make from
+<a href="ftp://ftp.gnu.org/gnu/make/">ftp://ftp.gnu.org/gnu/make/</a>).
+
+<p>If you want CVS to install to a location other than /usr/local/bin, you
+should change how you run the initial configuration step. For example,
+
+<pre>floss$ ./configure --prefix=/usr
+</pre>
+
+<p>results in CVS being installed as /usr/bin/cvs (it always ends up as
+PREFIX/bin/cvs). The default prefix is /usr/local, which is fine for
+most installations.
+
+<p>Note To Experienced Users: Although older versions of CVS consisted of
+more than just an executable in that they depended on having RCS
+installed as well, this has not been the case since Version 1.10.
+Therefore, you don't need to worry about any libraries or executables
+other than cvs itself.
+
+<p>If you just intend to use CVS to access remote repositories, the
+preceding is all you need to do. If you also plan to serve a repository
+from this system, a few additional steps are necessary, which are
+covered later in this chapter.
+
+<p><hr>
+Node:<a name="Getting_And_Installing_CVS_Under_Windows">Getting And Installing CVS Under Windows</a>,
+Next:<a rel=next href="#Getting_And_Installing_CVS_On_A_Macintosh">Getting And Installing CVS On A Macintosh</a>,
+Previous:<a rel=previous href="#Getting_And_Building_CVS_Under_Unix">Getting And Building CVS Under Unix</a>,
+Up:<a rel=up href="#Getting_And_Installing_CVS">Getting And Installing CVS</a>
+<br>
+
+<h3>Getting And Installing CVS Under Windows</h3>
+
+<p>Unless you're truly religious about having the source code to your
+executable, you don't need to compile CVS from source on your Windows
+box. Unlike Unix, the necessary compilation tools probably do not
+already exist on your system, so a source build would involve first
+going out and getting those tools. Because such a project is beyond the
+scope of this book, I'll just give instructions for getting a
+precompiled CVS binary.
+
+<p>First, note that Windows binary distributions of CVS are usually made
+only for major releases of CVS - not for the interim releases - and
+are not found on the GNU FTP site. So you'll need to go to Cyclic
+Software's download site, where in the major version directory,
+<a href="http://download.cyclic.com/pub/cvs-1.10/">http://download.cyclic.com/pub/cvs-1.10/</a>, you'll see an extra
+subdirectory
+
+<pre>Index of /pub/cvs-1.10
+ cvs-1.10.tar.gz 14-Aug-98 09:35 2.4M
+ windows/
+</pre>
+
+<p>inside of which is a ZIP file:
+
+<pre>Index of /pub/cvs-1.10/windows
+ cvs-1.10-win.zip 14-Aug-98 10:10 589k
+</pre>
+
+<p>This ZIP file contains a binary distribution of CVS. Download and
+extract that ZIP file:
+
+<pre>floss$ unzip cvs-1.10-win.zip
+
+Archive: cvs-1.10-win.zip
+ inflating: cvs.html
+ inflating: cvs.exe
+ inflating: README
+ inflating: FAQ
+ inflating: NEWS
+ inflating: patch.exe
+ inflating: win32gnu.dll
+</pre>
+
+<p>The README there contains detailed instructions. For most
+installations, they can be summarized as follows: Put all of the EXE and
+DLL files in a directory in your PATH. Additionally, if you're going to
+be using the pserver method to access a remote repository, you may need
+to put the following in your <code>C:\AUTOEXEC.BAT</code> file and reboot:
+
+<pre>set HOME=C:
+</pre>
+
+<p>This tells CVS where to store the .cvspass file.
+
+<p>CVS running under Windows cannot currently serve repositories to remote
+machines; it can be a client (connecting to remote repositories), and
+operate in local mode (using a repository on the same machine). For the
+most part, this book assumes that CVS under Windows is operating as a
+client. However, it shouldn't be too hard to set up a local repository
+under Windows after reading the Unix-oriented instructions in the rest
+of this chapter.
+
+<p>If you are only accessing remote repositories, you may not even need to
+run CVS. There is a tool called WinCvs that implements only the
+client-side portion of CVS. It is distributed separately from CVS
+itself but, like CVS, is freely available under the GNU General Public
+License. More information is available from <a href="http://www.wincvs.org">http://www.wincvs.org</a>.
+
+<p><hr>
+Node:<a name="Getting_And_Installing_CVS_On_A_Macintosh">Getting And Installing CVS On A Macintosh</a>,
+Next:<a rel=next href="#Limitations_Of_The_Windows_And_Macintosh_Versions">Limitations Of The Windows And Macintosh Versions</a>,
+Previous:<a rel=previous href="#Getting_And_Installing_CVS_Under_Windows">Getting And Installing CVS Under Windows</a>,
+Up:<a rel=up href="#Getting_And_Installing_CVS">Getting And Installing CVS</a>
+<br>
+
+<h3>Getting And Installing CVS On A Macintosh</h3>
+
+<p>CVS is available for the Macintosh, but not as part of the main
+distribution. At the moment, there are actually three separate
+Macintosh CVS clients available:
+
+<ul>
+<li>MacCvs - <a href="http://www.wincvs.org">http://www.wincvs.org</a>
+<li>MacCVSClient - <a href="http://www.glink.net.hk/~jb/MacCVSClient">http://www.glink.net.hk/~jb/MacCVSClient</a>
+ or <a href="http://www.cyclic.com/maccvsclient/">http://www.cyclic.com/maccvsclient/</a>
+<li>MacCVS Pro - <a href="http://www.maccvs.org">http://www.maccvs.org</a>
+</ul>
+
+<p>Frankly, I have no idea which one is best. Try them all, not
+necessarily in the order given, and see which one you like. MacCVS Pro
+seems to be under active development. MacCvs is apparently a companion
+project of WinCVS and shares a home page with it. (As of this writing, a
+notice on the WinCVS page states, "Development of MacCvs will be resumed
+soon.", whatever that means.)
+
+<p><hr>
+Node:<a name="Limitations_Of_The_Windows_And_Macintosh_Versions">Limitations Of The Windows And Macintosh Versions</a>,
+Previous:<a rel=previous href="#Getting_And_Installing_CVS_On_A_Macintosh">Getting And Installing CVS On A Macintosh</a>,
+Up:<a rel=up href="#Getting_And_Installing_CVS">Getting And Installing CVS</a>
+<br>
+
+<h3>Limitations Of The Windows And Macintosh Versions</h3>
+
+<p>The Windows and Macintosh distributions of CVS are generally limited in
+functionality. They can all act as clients, meaning that they can
+contact a repository server to obtain a working copy, commit, update,
+and so on. But they can't serve repositories themselves. If you set it
+up right, the Windows port can use a local-disk repository, but it still
+can't serve projects from that repository to other machines. In
+general, if you want to have a network-accessible CVS repository, you
+must run the CVS server on a Unix box.
+
+<p><hr>
+Node:<a name="Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>,
+Next:<a rel=next href="#Starting_A_Repository">Starting A Repository</a>,
+Previous:<a rel=previous href="#Getting_And_Installing_CVS">Getting And Installing CVS</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>Anatomy Of A CVS Distribution</h2>
+
+<p>The preceding instructions are designed to get you up and running
+quickly, but there's a lot more inside a CVS source distribution than
+just the code. Here's a quick road map to the source tree, so you'll
+know which parts are useful resources and which can be ignored.
+
+<ul>
+<li><a href="#Informational_Files">Informational Files</a>: NEWS, BUGS, FAQ, etc.
+<li><a href="#Subdirectories">Subdirectories</a>: How the distribution is laid out.
+<li><a href="#The_Cederqvist_Manual">The Cederqvist Manual</a>: The CVS Online Manual.
+<li><a href="#Other_Sources_Of_Information">Other Sources Of Information</a>: Where else to find help.
+</ul>
+
+<p><hr>
+Node:<a name="Informational_Files">Informational Files</a>,
+Next:<a rel=next href="#Subdirectories">Subdirectories</a>,
+Up:<a rel=up href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>
+<br>
+
+<h3>Informational Files</h3>
+
+<p>In the top level of the distribution tree, you'll find several files
+containing useful information (and pointers to further information).
+They are, in approximate order of importance:
+
+<ul>
+
+<li><code>NEWS</code> - This file lists the changes from one release to the next,
+in reverse chronological order (that is, most recent first). If you've
+already been using CVS for a while and have just upgraded to a new
+version, you should look at the NEWS file to see what new features are
+available. Also, although most changes to CVS preserve backward
+compatibility, noncompatible changes do occur from time to time. It's
+better to read about them here than be surprised when CVS doesn't behave
+the way you expect it to.
+
+<li><code>BUGS</code> - This file contains exactly what you think it does: a list
+of known bugs in CVS. They usually aren't show-stoppers, but you should
+read over them whenever you install a new release.
+
+<li><code>DEVEL-CVS</code> - This file is the CVS "constitution". It describes
+the process by which changes are accepted into the main CVS distribution
+and the procedures through which a person becomes a CVS developer. You
+don't really need to read it if you just want to use CVS; however, it's
+highly interesting if you want to understand how the mostly
+uncoordinated efforts of people scattered across the globe coalesce into
+a working, usable piece of software. And of course, it's required
+reading if you plan to submit a patch (be it a bug fix or new feature)
+to CVS.
+
+<li><code>HACKING</code> - Despite its name, the HACKING file doesn't say much
+about the design or implementation of CVS. It's mainly a guide to
+coding standards and other technical administrivia for people thinking
+of writing a patch to CVS. It can be thought of as an addendum to the
+DEVEL-CVS file. After you understand the basic philosophy of CVS
+development, you must read the HACKING file to translate that into
+concrete coding practices.
+
+<li><code>FAQ</code> - This is the CVS "Frequently Asked Questions" document.
+Unfortunately it has a rather spotty maintenance history. David Grubbs
+took care of it until 1995, then he (presumably) got too busy and it
+languished for a while. Eventually, in 1997, Pascal Molli took over
+maintenance. Molli also didn't have time to maintain it by hand, but at
+least he found time to put it into his automated FAQ-O-Matic system,
+which allows the public to maintain the FAQ in a decentralized manner
+(basically, anyone can edit or add entries via a Web form). This was
+probably a good thing, in that at least the FAQ was once again being
+maintained; however, its overall organization and quality control are
+not on the same level as if a person were maintaining it.
+
+<p>The master version of the FAQ is always available from Molli's Web site
+(<a href="http://www.loria.fr/~molli/cvs-index.html">http://www.loria.fr/~molli/cvs-index.html</a>, under the link
+"Documentation"). The FAQ file shipped with CVS distributions is
+generated automatically from that FAQ-O-Matic database, so by the time
+it reaches the public it's already a little bit out of date.
+Nevertheless, it can be quite helpful when you're looking for hints and
+examples about how to do something specific (say, merging a large branch
+back into the trunk or resurrecting a removed file). The best way to
+use it is as a reference document; you can bring it up in your favorite
+editor and do text searches on terms that interest you. Trying to use
+it as a tutorial would be a mistake - it's missing too many important
+facts about CVS to serve as a complete guide.
+
+</ul>
+
+<p><hr>
+Node:<a name="Subdirectories">Subdirectories</a>,
+Next:<a rel=next href="#The_Cederqvist_Manual">The Cederqvist Manual</a>,
+Previous:<a rel=previous href="#Informational_Files">Informational Files</a>,
+Up:<a rel=up href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>
+<br>
+
+<h3>Subdirectories</h3>
+
+<p>The CVS distribution contains a number of subdirectories. In the course
+of a normal installation, you won't have to navigate among them, but if
+you want to go poking around in the sources, it's nice to know what each
+one does. Here they are:
+
+<pre>contrib/
+diff/
+doc/
+emx/
+lib/
+man/
+os2/
+src/
+tools/
+vms/
+windows-NT/
+zlib/
+</pre>
+
+<p>The majority of these can be ignored. The emx/, os2/, vms/, and
+windows-NT/ subdirectories all contain operating-system-specific source
+code, which you would only need if you're actually trying to debug a
+code-level problem in CVS (an unlikely situation, though not unheard
+of). The diff/ and zlib/ subdirectories contain CVS's internal
+implementations of the diff program and the GNU gzip compression
+library, respectively. (CVS uses the latter to reduce the number of bits
+it has to send over the network when accessing remote repositories.)
+
+<p>The contrib/ and tools/ subdirectories contain free third-party software
+meant to be used with CVS. In contrib/, you will find an assortment of
+small, specialized shell scripts (read contrib/README to find out what
+they do). The tools/ subdirectory used to contain contributed software,
+but now contains a README file, which says in part:
+
+<pre>This subdirectory formerly contained tools that can be used with CVS.
+In particular, it used to contain a copy of pcl-cvs version 1.x.
+Pcl-cvs is an Emacs interface to CVS.
+
+If you are looking for pcl-cvs, we'd suggest pcl-cvs version 2.x, at:
+ ftp://ftp.weird.com/pub/local/
+</pre>
+
+<p>The PCL-CVS package it's referring to is very handy, and I'll have more
+to say about it in <a href="#Third-Party_Tools">Third-Party Tools</a>.
+
+<p>The src/ and lib/ subdirectories contain the bulk of the CVS source
+code, which involves the CVS internals. The main data structures and
+commands are implemented in src/, whereas lib/ contains small code
+modules of general utility that CVS uses.
+
+<p>The man/ subdirectory contains the CVS man pages (intended for the Unix
+online manual system). When you ran make install, they were
+incorporated into your Unix system's regular man pages, so you can type
+
+<pre>floss$ man cvs
+</pre>
+
+<p>and get a rather terse introduction and subcommand reference to CVS.
+Although useful as a quick reference, the man pages may not be as up to
+date or complete as the Cederqvist manual (see the next section);
+however, the man pages are more likely to be incomplete than actually
+wrong, if it's any comfort.
+
+<p><hr>
+Node:<a name="The_Cederqvist_Manual">The Cederqvist Manual</a>,
+Next:<a rel=next href="#Other_Sources_Of_Information">Other Sources Of Information</a>,
+Previous:<a rel=previous href="#Subdirectories">Subdirectories</a>,
+Up:<a rel=up href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>
+<br>
+
+<h3>The Cederqvist Manual</h3>
+
+<p>That leaves the doc/ subdirectory, whose most important inhabitant is
+the famed <dfn>Cederqvist</dfn>. These days, it's probably a stretch to call
+it "the Cederqvist". Although Per Cederqvist (of Signum Support,
+Linkoping Sweden, www.signum.se) wrote the first version around 1992, it
+has been updated since then by many other people. For example, when
+contributors add a new feature to CVS, they usually also document it in
+the Cederqvist.
+
+<p>The Cederqvist manual is written in Texinfo format, which is used by the
+GNU project because it's relatively easy to produce both online and
+printed output from it (in Info and PostScript formats, respectively).
+The Texinfo master file is doc/cvs.texinfo, but CVS distributions come
+with the Info and PostScript pregenerated, so you don't have to worry
+about running any Texinfo tools yourself.
+
+<p>Although the Cederqvist can be used as an introduction and tutorial, it
+is probably most useful as a reference document. For that reason, most
+people browse it online instead of printing it out (although the
+PostScript file is <code>doc/cvs.ps</code>, for those with paper to spare).
+If this is the first time you've installed CVS on your system, you'll
+have to take an extra step to make sure the manual is accessible online.
+
+<p>The Info files (doc/cvs.info, doc/cvs.info-1, doc/cvs.info-2, and so on)
+were installed for you when you ran make install. Although the files
+were copied into the system's Info tree, you may still have to add a
+line for CVS to the Info table of contents, the "Top" node. (This will
+only be necessary if this is the first time CVS has been installed on
+your system; otherwise, the entry from previous installations should
+already be in the table of contents.)
+
+<p>If you've added new Info documentation before, you may be familiar with
+the process. First figure out where the Info pages were installed. If
+you used the default installation (in /usr/local/), then the Info files
+are /usr/local/info/cvs.info*. If you installed using
+
+<pre>floss$ ./configure --prefix=/usr
+</pre>
+
+<p>the files ended up as /usr/info/cvs.*. After you locate the files,
+you'll need to add a line for CVS to the Info table of contents, which
+is in a file named dir in that directory (so in the latter case, it
+would be /usr/info/dir). If you don't have root access, ask your system
+administrator to do it. Here is an excerpt from dir before the
+reference to CVS documentation was added:
+
+<pre>* Bison: (bison). The Bison parser generator.
+* Cpp: (cpp). The GNU C preprocessor.
+* Flex: (flex). A fast scanner generator
+</pre>
+
+<p>And here is the same region of dir afterwards:
+
+<pre>* Bison: (bison). The Bison parser generator.
+* Cpp: (cpp). The GNU C preprocessor.
+* Cvs: (cvs). Concurrent Versions System
+* Flex: (flex). A fast scanner generator
+</pre>
+
+<p>The format of the line is very important. You must include the
+asterisk, spaces, and colon in <code>*&nbsp;Cvs:</code> and the parentheses and
+period in <code>(cvs).</code> after it. If any of these elements are missing,
+the Info dir format will be corrupt, and you'll be unable to read the
+Cederqvist.
+
+<p>Once the manual is installed and referred to from the table of contents,
+you can read it with any Info-compatible browser. The ones most likely
+to be installed on a typical Unix system are either the command-line
+Info reader, which can be invoked this way if you want to go straight to
+the CVS pages
+
+<pre>floss$ info cvs
+</pre>
+
+<p>and the one within Emacs, which is invoked by typing
+
+<pre>M-x info
+</pre>
+
+<p>or
+
+<pre>C-h i
+</pre>
+
+<p>Take whatever time is necessary to get the Cederqvist set up properly on
+your system when you install CVS; it will pay off many times down the
+road when you need to look something up.
+
+<p><hr>
+Node:<a name="Other_Sources_Of_Information">Other Sources Of Information</a>,
+Previous:<a rel=previous href="#The_Cederqvist_Manual">The Cederqvist Manual</a>,
+Up:<a rel=up href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>
+<br>
+
+<h3>Other Sources Of Information</h3>
+
+<p>In addition to the Cederqvist, the FAQ, and the other files in the
+distribution itself, there are Internet resources devoted to CVS. If
+you're going to administrate a CVS server, you'll probably want to join
+the info-cvs mailing list. To subscribe, send email to
+<a href="mailto:info-cvs-request@gnu.org">info-cvs-request@gnu.org</a> (the list itself is
+<a href="mailto:info-cvs@gnu.org">info-cvs@gnu.org</a>). Traffic can be medium to heavy, around 10
+to 20 emails a day, most of them questions seeking answers. The
+majority of these can be deleted without reading (unless you want to
+help people by answering their questions, which is always nice), but
+every now and then someone will announce the discovery of a bug or
+announce a patch that implements some feature you've been wanting.
+
+<p>You can also join the formal bug report mailing list, which includes
+every bug report sent in. This probably isn't necessary, unless you
+intend to help fix the bugs, which would be great, or you're
+terrifically paranoid and want to know about every problem other people
+find with CVS. If you do want to join, send email to
+<a href="mailto:bug-cvs-request@gnu.org">bug-cvs-request@gnu.org</a>.
+
+<p>There's also a Usenet newsgroup, <code>comp.software.config-mgmt</code>, which
+is about version control and configuration management systems in
+general, in which there is a fair amount of discussion about CVS.
+
+<p>Finally, there are at least three Web sites devoted to CVS. Cyclic
+Software's <a href="http://www.cyclic.com">http://www.cyclic.com</a> has been CVS's informal home
+site for a few years, and probably will continue to be for the
+foreseeable future. Cyclic Software also provides server space and Net
+access for the repository where the CVS sources are kept. The Cyclic
+Web pages contain comprehensive links to experimental patches for CVS,
+third-party tools that work with CVS, documentation, mailing list
+archives, and just about everything else. If you can't find what you
+need in the distribution, <a href="http://www.cyclic.com">http://www.cyclic.com</a> is the place to
+start looking.
+
+<p>Two other good sites are Pascal Molli's
+<a href="http://www.loria.fr/~molli/cvs-index.html">http://www.loria.fr/~molli/cvs-index.html</a> and Sean Dreilinger's
+<a href="http://durak.org/cvswebsites/">http://durak.org/cvswebsites/</a>. The biggest attraction at Molli's
+site is, of course, the FAQ, but it also has links to CVS-related tools
+and mailing list archives. Dreilinger's site specializes in information
+about using CVS to manage Web documents and also has a CVS-specific
+search engine.
+
+<p><hr>
+Node:<a name="Starting_A_Repository">Starting A Repository</a>,
+Next:<a rel=next href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a>,
+Previous:<a rel=previous href="#Anatomy_Of_A_CVS_Distribution">Anatomy Of A CVS Distribution</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>Starting A Repository</h2>
+
+<p>Once the CVS executable is installed on your system, you can start using
+it right away as a client to access remote repositories, following the
+procedures described in <a href="#An_Overview_of_CVS">An Overview of CVS</a>. However, if you want
+to serve revisions from your machine, you have to create a repository
+there. The command to do that is
+
+<pre>floss$ cvs -d /usr/local/newrepos init
+</pre>
+
+<p>where <code>/usr/local/newrepos</code> is a path to wherever you want the
+repository to be (of course, you must have write permission to that
+location, which may imply running the command as the root user). It may
+seem somewhat counterintuitive that the location of the new repository
+is specified before the init subcommand instead of after it, but by
+using the -d option, it stays consistent with other CVS commands.
+
+<p>The command will return silently after it is run. Let's examine the new
+directory:
+
+<pre>floss$ ls -ld /usr/local/newrepos
+drwxrwxr-x 3 root root 1024 Jun 19 17:59 /usr/local/newrepos/
+floss$ cd /usr/local/newrepos
+floss$ ls
+CVSROOT
+floss$ cd CVSROOT
+floss$ ls
+checkoutlist config,v history notify taginfo,v
+checkoutlist,v cvswrappers loginfo notify,v verifymsg
+commitinfo cvswrappers,v loginfo,v rcsinfo verifymsg,v
+commitinfo,v editinfo modules rcsinfo,v
+config editinfo,v modules,v taginfo
+
+floss$
+</pre>
+
+<p>The single subdirectory in the new repository - CVSROOT/ - contains
+various administrative files that control CVS's behavior. Later on,
+we'll examine those files one by one; for now, the goal is just to get
+the repository working. In this case, "working" means users can import,
+check out, update, and commit projects.
+
+<p>Don't confuse the CVSROOT environment variable introduced in <a href="#An_Overview_of_CVS">An Overview of CVS</a> with this CVSROOT subdirectory in the repository. They
+are unrelated - it is an unfortunate coincidence that they share the
+same name. The former is a way for users to avoid having to type
+<code>-d&nbsp;&lt;repository-location&gt;</code> every time they use CVS; the latter
+is the administrative subdirectory of a repository.
+
+<p>Once the repository is created, you must take care of its permissions.
+CVS does not require any particular, standardized permission or file
+ownership scheme; it merely needs write access to the repository.
+However - partly for security reasons, but mainly for your own sanity
+as an administrator - I highly recommend that you take the following
+steps:
+
+<ol type=1 start=1>
+
+</p><li>Add a Unix group <code>cvs</code> to your system. Any users who need to
+access the repository should be in this group. For example, here's the
+relevant line from my machine's <code>/etc/group</code> file:
+
+<pre>cvs:*:105:kfogel,sussman,jimb,noel,lefty,fitz,craig,anonymous,jrandom
+</pre>
+
+<li>Make the repository's group ownership and permissions reflect this new
+group:
+
+<pre>floss$ cd /usr/local/newrepos
+floss$ chgrp -R cvs .
+floss$ chmod ug+rwx . CVSROOT
+</pre>
+
+</ol>
+
+<p>Now any of the users listed in that group can start a project by running
+<code>cvs&nbsp;import</code>, as described in <a href="#An_Overview_of_CVS">An Overview of CVS</a>.
+Checkout, update, and commit should work as well. They can also reach
+the repository from remote locations by using the <code>:ext:</code> method,
+assuming that they have rsh or ssh access to the repository
+machine. (You may have noticed that the chgrp and chmod commands in that
+example gave write access to a user named <code>anonymous</code>, which is not
+what one would expect. The reason is that even anonymous, read-only
+repository users need system-level write access, so that their CVS
+processes can create temporary lockfiles inside the repository. CVS
+enforces the "read-only" restriction of anonymous access not through
+Unix file permissions, but by other means, which will be covered in
+<a href="#Anonymous_Access">Anonymous Access</a>.)
+
+<p>If your repository is intended to serve projects to the general public,
+where contributors won't necessarily have accounts on the repository
+machine, you should set up the password-authenticating server now
+(see <a href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a>). It's necessary for
+anonymous read-only access, and it's also probably the easiest way to
+grant commit access to certain people without giving them full accounts
+on the machine.
+
+<p><hr>
+Node:<a name="The_Password-Authenticating_Server">The Password-Authenticating Server</a>,
+Next:<a rel=next href="#Anonymous_Access">Anonymous Access</a>,
+Previous:<a rel=previous href="#Starting_A_Repository">Starting A Repository</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>The Password-Authenticating Server</h2>
+
+<p>Before running through the steps needed to set up the password server,
+let's examine how such connections work in the abstract. When a remote
+CVS client uses the <code>:pserver:</code> method to connect to a repository,
+the client is actually contacting a specific port number on the server
+machine - specifically, port number 2401 (which is 49 squared, if you
+like that sort of thing). Port 2401 is the designated default port for
+the CVS pserver, although one could arrange for a different port to be
+used as long as both client and server agree on it.
+
+<p>The CVS server is not actually waiting for connections at that port -
+the server won't get started up until a connection actually arrives.
+Instead, the Unix inetd (InterNET Daemon) program is listening on that
+port, and needs to know that when it receives a connection request
+there, it should start up the CVS server and connect it to the incoming
+client.
+
+<p>This is accomplished by modifying inetd's configuration files:
+<code>/etc/services</code> and <code>/etc/inetd.conf</code>. The services file maps
+raw port numbers to service names and then inetd.conf tells inetd what
+to do for a given service name.
+
+<p>First, put a line like this into /etc/services (after checking to make
+sure it isn't already there):
+
+<pre>cvspserver 2401/tcp
+</pre>
+
+<p>Then in /etc/inetd.conf, put this:
+
+<pre>cvspserver stream tcp nowait root /usr/local/bin/cvs cvs \
+ --allow-root=/usr/local/newrepos pserver
+</pre>
+
+<p>(In the actual file, this should be all one long line, with no
+backslash.) If your system uses tcpwrappers, you may want to use
+something like this instead:
+
+<pre>cvspserver stream tcp nowait root /usr/sbin/tcpd /usr/local/bin/cvs \
+ --allow-root=/usr/local/newrepos pserver
+</pre>
+
+<p>Now, restart inetd so it notices the changes to its configuration files
+(if you don't know how to restart the daemon, just reboot the machine -
+that will work too).
+
+<p>That's enough to permit connections, but you'll also want to set up
+special CVS passwords - separate from the users' regular login
+passwords - so people can access the repository without compromising
+overall system security.
+
+<p>The CVS password file is CVSROOT/passwd in the repository. It was not
+created by default when you ran cvs init, because CVS doesn't know for
+sure that you'll be using pserver. Even if the password file had been
+created, CVS would have no way of knowing what usernames and passwords
+to create. So, you'll have to create one yourself; here's a sample
+CVSRoot/passwd file:
+
+<pre>kfogel:rKa5jzULzmhOo
+anonymous:XR4EZcEs0szik
+melissa:tGX1fS8sun6rY:pubcvs
+</pre>
+
+<p>The format is as simple as it looks. Each line is:
+
+<pre>&lt;USERNAME&gt;:&lt;ENCRYPTED_PASSWORD&gt;:&lt;OPTIONAL_SYSTEM_USERNAME&gt;
+</pre>
+
+<p>The extra colon followed by an optional system username tells CVS that
+connections authenticated with USERNAME should run as the system account
+SYSTEM_USERNAME - in other words, that CVS session would only be able
+to do things in the repository that someone logged in as SYSTEM_USERNAME
+could do.
+
+<p>If no system username is given, USERNAME must match an actual login
+account name on the system, and the session will run with that user's
+permissions. In either case, the encrypted password should not be the
+same as the user's actual login password. It should be an independent
+password used only for CVS pserver connections.
+
+<p>The password is encrypted using the same algorithm as the standard Unix
+system passwords stored in /etc/passwd. You may be wondering at this
+point, how does one acquire an encrypted version of a password? For
+Unix system passwords, the passwd command takes care of the encryption
+in /etc/passwd for you. Unfortunately, there is no corresponding cvs
+passwd command (it has been proposed several times, but no one's gotten
+around to writing it - perhaps you'll do it?).
+
+<p>This is an inconvenience, but only a slight one. If nothing else, you
+can always temporarily change a regular user's system password using
+passwd, cut and paste the encrypted text from /etc/passwd into
+CVSROOT/passwd, and then restore the old password (note that on some
+systems, the encrypted passwords are found in /etc/shadow and are
+readable only by root.)
+
+<p>That scheme is workable but rather cumbersome. It would be much easier
+to have a command-line utility that takes a plain text password as its
+argument and outputs the encrypted version. Here is such a tool,
+written in Perl:
+
+<pre>#!/usr/bin/perl
+
+srand (time());
+my $randletter = "(int (rand (26)) + (int (rand (1) + .5) % 2 ? 65 : 97))";
+my $salt = sprintf ("%c%c", eval $randletter, eval $randletter);
+my $plaintext = shift;
+my $crypttext = crypt ($plaintext, $salt);
+
+print "${crypttext}\n";
+</pre>
+
+<p>I keep the preceding script in <code>/usr/local/bin/cryptout.pl</code>:
+
+<pre>floss$ ls -l /usr/local/bin/cryptout.pl
+
+-rwxr-xr-x 1 root root 265 Jun 14 20:41 /usr/local/bin/cryptout.pl
+floss$ cryptout.pl "some text"
+sB3A79YDX5L4s
+
+floss$
+</pre>
+
+<p>If I took the output of this example and used it to create the following
+entry in CVSROOT/passwd
+
+<pre>jrandom:sB3A79YDX5L4s:craig
+</pre>
+
+<p>then someone could connect to the repository with the following command:
+
+<pre>remote$ cvs -d :pserver:jrandom@floss.red-bean.com:/usr/local/newrepos login
+</pre>
+
+<p>They could then type <code>some text</code> as their password and thereafter
+be able to execute CVS commands with the same access privileges as the
+system user <code>craig</code>.
+
+<p>If someone attempts to authenticate with a username and password that
+don't appear in CVSROOT/passwd, CVS will check to see if that username
+and password are present in /etc/passwd. If they are (and if the
+password matches, of course), CVS will grant access. It behaves this
+way for the administrator's convenience, so that separate CVSROOT/passwd
+entries don't have to be set up for regular system users. However, this
+behavior is also a security hole, because it means that if one of those
+users does connect to the CVS server, her regular login password will
+have crossed over the network in cleartext, potentially vulnerable to
+the eyes of password sniffers. A bit further on, you'll learn how to
+turn off this "fallback" behavior, so that CVS consults only its own
+passwd file. Whether you leave it on or off, you should probably force
+any CVS users who also have login accounts to maintain different
+passwords for the two functions.
+
+<p>Although the passwd file authenticates for the whole repository, with a
+little extra work you can still use it to grant project-specific access.
+Here's one method:
+
+<p>Suppose you want to grant some remote developers access to project
+<code>foo</code>, and others access to project <code>bar</code>, and you don't want
+developers from one project to have commit access to the other. You can
+accomplish this by creating project-specific user accounts and groups on
+the system and then mapping to those accounts in the CVSROOT/passwd
+file.
+
+<p>Here's the relevant excerpt from /etc/passwd
+
+<pre>cvs-foo:*:600:600:Public CVS Account for Project Foo:/usr/local/cvs:/bin/false
+cvs-bar:*:601:601:Public CVS Account for Project Bar:/usr/local/cvs:/bin/false
+</pre>
+
+<p>and from /etc/group
+
+<pre>cvs-foo:*:600:cvs-foo
+cvs-bar:*:601:cvs-bar
+</pre>
+
+<p>and, finally, CVSROOT/passwd:
+
+<pre>kcunderh:rKa5jzULzmhOo:cvs-foo
+jmankoff:tGX1fS8sun6rY:cvs-foo
+brebard:cAXVPNZN6uFH2:cvs-foo
+xwang:qp5lsf7nzRzfs:cvs-foo
+dstone:JDNNF6HeX/yLw:cvs-bar
+twp:glUHEM8KhcbO6:cvs-bar
+ffranklin:cG6/6yXbS9BHI:cvs-bar
+yyang:YoEqcCeCUq1vQ:cvs-bar
+</pre>
+
+<p>Some of the CVS usernames map onto the system user account
+<code>cvs-foo</code> and some onto <code>cvs-bar</code>. Because CVS runs under the
+user ID of the system account, you just have to make sure that the
+relevant parts of the repository are writeable only by the appropriate
+users and groups. If you just make sure that the user accounts are
+locked down pretty tight (no valid login password, <code>/bin/false</code> as
+the shell), then this system is reasonably secure (but see later in this
+chapter about CVSROOT permissions!). Also, CVS does record changes and
+log messages under the CVS username, not the system username, so you can
+still tell who is responsible for a given change.
+
+<p><hr>
+Node:<a name="Anonymous_Access">Anonymous Access</a>,
+Next:<a rel=next href="#Repository_Structure">Repository Structure</a>,
+Previous:<a rel=previous href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>Anonymous Access</h2>
+
+<p>So far we've only seen how to use the password-authenticating server to
+grant normal full access to the repository (although admittedly one can
+restrict that access through carefully arranged Unix file permissions).
+Turning this into anonymous, read-only access is a simple step: You just
+have to add a new file, or possibly two, in CVSROOT/. The files' names
+are <code>readers</code> and <code>writers</code> - the former containing a list of
+usernames who can only read the repository, the latter users who can
+read and write.
+
+<p>If you list a username in CVSROOT/readers, that user will have only read
+access to all projects in the repository. If you list a username in
+CVSROOT/writers, that user will have write access, and every pserver
+user not listed in writers will have read-only access (that is, if the
+writers file exists at all, it implies read-only access for all those
+not listed in it). If the same username is listed in both files, CVS
+resolves the conflict in the more conservative way: the user will have
+read-only access.
+
+<p>The format of the files is very simple: one user per line (don't forget
+to put a newline after the last user). Here is a sample readers file:
+
+<pre>anonymous
+splotnik
+guest
+jbrowse
+</pre>
+
+<p>Note that the files apply to CVS usernames, not system usernames. If
+you use user aliasing in the CVSROOT/passwd file (putting a system
+username after a second colon), the leftmost username is the one to list
+in a readers or writers file.
+
+<p>Just to be painfully accurate about it, here is a formal description of
+the server's behavior in deciding whether to grant read-only or
+read-write access:
+
+<p>If a readers file exists and this user is listed in it, then she gets
+read-only access. If a writers file exists and this user is not listed
+in it, then she also gets read-only access (this is true even if a
+readers file exists but that person is not listed there). If that
+person is listed in both, she gets read-only access. In all other
+cases, that person gets full read-write access.
+
+<p>Thus, a typical repository with anonymous CVS access has this (or
+something like it) in CVSROOT/passwd
+
+<pre>anonymous:XR4EZcEs0szik
+</pre>
+
+<p>this (or something like it) in /etc/passwd
+
+<pre>anonymous:!:1729:105:Anonymous CVS User:/usr/local/newrepos:/bin/false
+</pre>
+
+<p>and this in CVSROOT/readers:
+
+<pre>anonymous
+</pre>
+
+<p>And, of course, the aforementioned setup in /etc/services and
+/etc/inetd.conf. That's all there is to it!
+
+<p>Note that some older Unix systems don't support usernames longer than
+eight characters. One way to get around this would be to call the user
+<code>anon</code> instead of <code>anonymous</code> in CVSROOT/passwd and in the
+system files, because people often assume that anon is short for
+anonymous anyway. But it might be better to put something like this
+into the CVSROOT/passwd file
+
+<pre>anonymous:XR4EZcEs0szik:cvsanon
+</pre>
+
+<p>(and then of course use <code>cvsanon</code> in the system files). That way,
+you'd be able to publish a repository address that uses
+<code>anonymous</code>, which is more or less standard now. People accessing
+the repository with
+
+<pre>cvs -d :pserver:anonymous@cvs.foobar.com:/usr/local/newrepos (etc...)
+</pre>
+
+<p>would actually run on the server as cvsanon (or whatever). But they
+wouldn't need to know or care about how things are set up on the server
+side - they'd only see the published address.
+
+<p><hr>
+Node:<a name="Repository_Structure">Repository Structure</a>,
+Next:<a rel=next href="#RCS_Format">RCS Format</a>,
+Previous:<a rel=previous href="#Anonymous_Access">Anonymous Access</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>Repository Structure</h2>
+
+<p>The new repository still has no projects in it. Let's re-run the
+initial import from <a href="#An_Overview_of_CVS">An Overview of CVS</a>, watching what happens to
+the repository. (For simplicity's sake, all commands will assume that
+the CVSROOT environment variable has been set to /usr/local/newrepos, so
+there's no need to specify the repository with -d on imports and
+checkouts.)
+
+<pre>floss$ ls /usr/local/newrepos
+CVSROOT/
+floss$ pwd
+/home/jrandom/src/
+floss$ ls
+myproj/
+floss$ cd myproj
+floss$ cvs import -m "initial import into CVS" myproj jrandom start
+N myproj/README.txt
+N myproj/hello.c
+cvs import: Importing /usr/local/newrepos/myproj/a-subdir
+N myproj/a-subdir/whatever.c
+cvs import: Importing /usr/local/newrepos/myproj/a-subdir/subsubdir
+N myproj/a-subdir/subsubdir/fish.c
+cvs import: Importing /usr/local/newrepos/myproj/b-subdir
+N myproj/b-subdir/random.c
+
+No conflicts created by this import
+
+floss$ ls /usr/local/newrepos
+CVSROOT/ myproj/
+floss$ cd /usr/local/newrepos/myproj
+floss$ ls
+README.txt,v a-subdir/ b-subdir/ hello.c,v
+floss$ cd a-subdir
+floss$ ls
+subsubdir/ whatever.c,v
+floss$ cd ..
+
+floss$
+</pre>
+
+<p>Before the import, the repository contained only its administrative
+area, CVSROOT. After the import, a new directory - <code>myproj</code> -
+appeared. The files and subdirectories inside that new directory look
+suspiciously like the project we imported, except that the files have
+the suffix <code>,v</code>. These are RCS-format version control files (the
+<code>,v</code> stands for "version"), and they are the backbone of the
+repository. Each RCS file stores the revision history of its
+corresponding file in the project, including all branches and tags.
+
+<p><hr>
+Node:<a name="RCS_Format">RCS Format</a>,
+Next:<a rel=next href="#What_Happens_When_You_Remove_A_File">What Happens When You Remove A File</a>,
+Previous:<a rel=previous href="#Repository_Structure">Repository Structure</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>RCS Format</h2>
+
+<p>You do not need to know any of the RCS format to use CVS (although there
+is an excellent writeup included with the source distribution, see
+doc/RCSFILES). However, a basic understanding of the format can be of
+immense help in troubleshooting CVS problems, so we'll take a brief peek
+into one of the files, <code>hello.c,v</code>. Here are its contents:
+
+<pre>head 1.1;
+branch 1.1.1;
+access ;
+symbols start:1.1.1.1 jrandom:1.1.1;
+locks ; strict;
+comment @ * @;
+
+1.1
+date 99.06.20.17.47.26; author jrandom; state Exp;
+branches 1.1.1.1;
+next;
+
+1.1.1.1
+date 99.06.20.17.47.26; author jrandom; state Exp;
+branches ;
+next;
+
+desc
+@@
+
+1.1
+log
+@Initial revision
+@
+text
+@#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+}
+@
+
+1.1.1.1
+log
+@initial import into CVS
+@
+text
+@@
+</pre>
+
+<p>Whew! Most of that you can ignore; don't worry about the relationship
+between 1.1 and 1.1.1.1, for example, or the implied 1.1.1 branch -
+they aren't really significant from a user's or even an administrator's
+point of view. What you should try to grok is the overall format. At
+the top is a collection of header fields:
+
+<pre>head 1.1;
+branch 1.1.1;
+access ;
+symbols start:1.1.1.1 jrandom:1.1.1;
+locks ; strict;
+comment @ * @;
+</pre>
+
+<p>Farther down in the file are groups of meta-information about each
+revision (but still not showing the contents of that revision), such as:
+
+<pre>1.1
+date 99.06.20.17.47.26; author jrandom; state Exp;
+branches 1.1.1.1;
+next ;
+</pre>
+
+<p>And finally, the log message and text of an actual revision:
+
+<pre>1.1
+log
+@Initial revision
+@
+text
+@#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+}
+@
+
+1.1.1.1
+log
+@initial import into CVS
+@
+text
+@@
+</pre>
+
+<p>If you look closely, you'll see that the first revision's contents are
+stored under the heading 1.1, but that the log message there is "Initial
+revision", whereas the log message we actually used at import time was
+"initial import into CVS", which appears farther down, under
+<code>Revision 1.1.1.1</code>. You don't need to worry about this discrepancy
+right now. It happens because imports are a special circumstance: In
+order to make repeated imports into the same project have a useful
+effect, import actually places the initial revision on both the main
+trunk and on a special branch (the reasons for this will become clearer
+when we look at vendor branches in <a href="#Advanced_CVS">Advanced CVS</a>). For now, you
+can treat <code>1.1</code> and <code>1.1.1.1</code> as the same thing.
+
+<p>The file becomes even more revealing after we commit the first
+modification to hello.c:
+
+<pre>floss$ cvs -Q co myproj
+floss$ cd myproj
+floss$ emacs hello.c
+ (make some changes to the file)
+
+floss$ cvs ci -m "print goodbye too"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in hello.c;
+/usr/local/newrepos/myproj/hello.c,v &lt;-- hello.c
+new revision: 1.2; previous revision: 1.1
+done
+</pre>
+
+<p>If you look at hello.c,v in the repository now, you can see the effect
+of the commit:
+
+<pre>head 1.2;
+access;
+symbols
+ start:1.1.1.1 jrandom:1.1.1;
+locks; strict;
+comment @ * @;
+
+1.2
+date 99.06.21.01.49.40; author jrandom; state Exp;
+branches;
+next 1.1;
+
+1.1
+date 99.06.20.17.47.26; author jrandom; state Exp;
+branches
+ 1.1.1.1;
+next ;
+
+1.1.1.1
+date 99.06.20.17.47.26; author jrandom; state Exp;
+branches;
+next ;
+
+desc
+@@
+
+1.2
+log
+@print goodbye too
+@
+text
+@#include &lt;stdio.h&gt;
+
+void
+main ()
+{
+ printf ("Hello, world!\n");
+ printf ("Goodbye, world!\n");
+}
+@
+
+1.1
+log
+@Initial revision
+@
+text
+@d7 1
+@
+
+1.1.1.1
+log
+@initial import into CVS
+@
+text
+@@
+</pre>
+
+<p>Now the full contents of Revision 1.2 are stored in the file, and the
+text for Revision 1.1 has been replaced with the cryptic formula:
+
+<pre>d7 1
+</pre>
+
+<p>The <code>d7&nbsp;1</code> is a diff code that means "starting at line 7,
+delete 1 line". In other words, to derive Revision 1.1, delete line 7
+from Revision 1.2! Try working through it yourself. You'll see that it
+does indeed produce Revision 1.1 - it simply does away with the line we
+added to the file.
+
+<p>This demonstrates the basic principle of RCS format: It stores only the
+differences between revisions, thereby saving a lot of space compared
+with storing each revision in full. To go backwards from the most
+recent revision to the previous one, it patches the later revision using
+the stored diff. Of course, this means that the further back you travel
+in the revision history, the more patch operations must be performed
+(for example, if the file is on Revision 1.7 and CVS is asked to
+retrieve Revision 1.4, it has to produce 1.6 by patching backwards from
+1.7, then 1.5 by patching 1.6, then 1.4 by patching 1.5). Fortunately,
+old revisions are also the ones least often retrieved, so the RCS system
+works out pretty well in practice: The more recent the revision, the
+cheaper it is to obtain.
+
+<p>As for the header information at the top of the file, you don't need to
+know what all of it means. However, the effects of certain operations
+show up very clearly in the headers, and a passing familiarity with them
+may prove useful.
+
+<p>When you commit a new revision on the trunk, the <code>head</code> label is
+updated (note how it became 1.2 in the preceding example, when the
+second revision to hello.c was committed). When you add a file as
+binary or tag it, those operations are recorded in the headers as well.
+As an example, we'll add foo.jpg as a binary file and then tag it a
+couple of times:
+
+<pre>floss$ cvs add -kb foo.jpg
+cvs add: scheduling file 'foo.jpg' for addition
+cvs add: use 'cvs commit' to add this file permanently
+floss$ cvs -q commit -m "added a random image; ask jrandom@red-bean.com why"
+RCS file: /usr/local/newrepos/myproj/foo.jpg,v
+done
+Checking in foo.jpg;
+/usr/local/newrepos/myproj/foo.jpg,v &lt;-- foo.jpg
+initial revision: 1.1
+done
+floss$ cvs tag some_random_tag foo.jpg
+T foo.jpg
+floss$ cvs tag ANOTHER-TAG foo.jpg
+T foo.jpg
+floss$
+</pre>
+
+<p>Now examine the header section of foo.jpg,v in the repository:
+
+<pre>head 1.1;
+access;
+symbols
+ ANOTHER-TAG:1.1
+ some_random_tag:1.1;
+locks; strict;
+comment @# @;
+expand @b@;
+</pre>
+
+<p>Notice the b in the expand line at the end - it's due to our having
+used the -kb flag when adding the file, and means the file won't undergo
+any keyword or newline expansions, which would normally occur during
+checkouts and updates if it were a regular text file. The tags appear
+in the symbols section, one tag per line - both of them are attached to
+the first revision, since that's what was tagged both times. (This also
+helps explain why tag names can only contain letters, numbers, hyphens,
+and underscores. If the tag itself contained colons or dots, the RCS
+file's record of it might be ambiguous, because there would be no way to
+find the textual boundary between the tag and the revision to which it
+is attached.)
+
+<h2>RCS Format Always Quotes @ Signs</h2>
+
+<p>The <code>@</code> symbol is used as a field delimiter in RCS files, which
+means that if one appears in the text of a file or in a log message, it
+must be quoted (otherwise, CVS would incorrectly interpret it as marking
+the end of that field). It is quoted by doubling - that is, CVS always
+interprets <code>@@</code> as "literal @ sign", never as "end of current
+field". When we committed foo.jpg, the log message was
+
+<pre>"added a random image; ask jrandom@red-bean.com why"
+</pre>
+
+<p>which is stored in foo.jpg,v like this:
+
+<pre>1.1
+log
+@added a random image; ask jrandom@@red-bean.com why
+@
+</pre>
+
+<p>The @ sign in jrandom@@red-bean.com will be automatically unquoted
+whenever CVS retrieves the log message:
+
+<pre>floss$ cvs log foo.jpg
+RCS file: /usr/local/newrepos/myproj/foo.jpg,v
+Working file: foo.jpg
+head: 1.1
+branch:
+locks: strict
+access list:
+symbolic names:
+ ANOTHER-TAG: 1.1
+ some_random_tag: 1.1
+keyword substitution: b
+total revisions: 1; selected revisions: 1
+description:
+----------------------------
+revision 1.1
+date: 1999/06/21 02:56:18; author: jrandom; state: Exp;
+added a random image; ask jrandom@red-bean.com why
+============================================================================
+
+floss$
+</pre>
+
+<p>The only reason you should care is that if you ever find yourself
+hand-editing RCS files (a rare circumstance, but not unheard of), you
+must remember to use double @ signs in revision contents and log
+messages. If you don't, the RCS file will be corrupt and will probably
+exhibit strange and undesirable behaviors.
+
+<p>Speaking of hand-editing RCS files, don't be fooled by the permissions
+in the repository:
+
+<pre>floss$ ls -l
+total 6
+-r--r--r-- 1 jrandom users 410 Jun 20 12:47 README.txt,v
+drwxrwxr-x 3 jrandom users 1024 Jun 20 21:56 a-subdir/
+drwxrwxr-x 2 jrandom users 1024 Jun 20 21:56 b-subdir/
+-r--r--r-- 1 jrandom users 937 Jun 20 21:56 foo.jpg,v
+-r--r--r-- 1 jrandom users 564 Jun 20 21:11 hello.c,v
+
+floss$
+</pre>
+
+<p>(For those not fluent in Unix ls output, the <code>-r--r--r--</code> lines on
+the left essentially mean that the files can be read but not changed.)
+Although the files appear to be read-only for everyone, the directory
+permissions must also be taken into account:
+
+<pre>floss$ ls -ld .
+drwxrwxr-x 4 jrandom users 1024 Jun 20 22:16 ./
+floss$
+</pre>
+
+<p>The myproj/ directory itself - and its subdirectories - are all
+writeable by the owner (jrandom) and the group (users). This means that
+CVS (running as jrandom, or as anyone in the users group) can create and
+delete files in those directories, even if it can't directly edit files
+already present. CVS edits an RCS file by making a separate copy of it,
+so you should also make all of your changes in a temporary copy, and
+then replace the existing RCS file with the new one. (But please don't
+ask why the files themselves are read-only - there are historical
+reasons for that, having to do with the way RCS works when run as a
+standalone program.)
+
+<p>Incidentally, having the files' group be <code>users</code> is probably not
+what you want, considering that the top-level directory of the
+repository was explicitly assigned group <code>cvs</code>. You can correct
+the problem by running this command inside the repository:
+
+<pre>floss$ cd /usr/local/newrepos
+floss$ chgrp -R cvs myproj
+</pre>
+
+<p>The usual Unix file-creation rules govern which group is assigned to new
+files that appear in the repository, so once in a while you may need to
+run chgrp or chmod on certain files or directories in the repository
+(setting the SGID bit with <code>chmod&nbsp;g+s</code> is often a good
+strategy: it makes children of a directory inherit the directory's group
+ownership, which is usually what you want in the repository). There are
+no hard and fast rules about how you should structure repository
+permissions; it just depends on who is working on what projects.
+
+<p><hr>
+Node:<a name="What_Happens_When_You_Remove_A_File">What Happens When You Remove A File</a>,
+Next:<a rel=next href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>,
+Previous:<a rel=previous href="#RCS_Format">RCS Format</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>What Happens When You Remove A File</h2>
+
+<p>When you remove a file from a project, it doesn't just disappear. CVS
+must be able to retrieve such files when you request an old snapshot of
+the project. Instead, the file gets put in the <code>Attic</code>, literally:
+
+<pre>floss$ pwd
+/home/jrandom/src/myproj
+floss$ ls /usr/local/newrepos/myproj/
+README.txt,v a-subdir/ b-subdir/ foo.jpg,v hello.c,v
+floss$ rm foo.jpg
+floss$ cvs rm foo.jpg
+cvs remove: scheduling 'foo.jpg' for removal
+cvs remove: use 'cvs commit' to remove this file permanently
+floss$ cvs ci -m "Removed foo.jpg" foo.jpg
+Removing foo.jpg;
+/usr/local/newrepos/myproj/foo.jpg,v &lt;-- foo.jpg
+new revision: delete; previous revision: 1.1
+done
+floss$ cd /usr/local/newrepos/myproj/
+floss$ ls
+Attic/ README.txt,v a-subdir/ b-subdir/ hello.c,v
+floss$ cd Attic
+floss$ ls
+foo.jpg,v
+floss$
+</pre>
+
+<p>In each repository directory of a project, the presence of an
+<code>Attic/</code> subdirectory means that at least one file has been removed
+from that directory (this means that you shouldn't use directories named
+Attic in your projects). CVS doesn't merely move the RCS file into
+Attic/, however; it also commits a new revision into the file, with a
+special revision state of <code>dead</code>. Here's the relevant section from
+Attic/foo.jpg,v:
+
+<pre>1.2
+date 99.06.21.03.38.07; author jrandom; state dead;
+branches;
+next 1.1;
+</pre>
+
+<p>If the file is later brought back to life, CVS has a way of recording
+that it was dead at some point in the past and is now alive again.
+
+<p>This means that if you want to restore a removed file, you can't just
+take it out of the Attic/ and put it back into the project. Instead,
+you have to do something like this in a working copy:
+
+<pre>floss$ pwd
+/home/jrandom/src/myproj
+floss$ cvs -Q update -p -r 1.1 foo.jpg &gt; foo.jpg
+floss$ ls
+CVS/ README.txt a-subdir/ b-subdir/ foo.jpg hello.c
+floss$ cvs add -kb foo.jpg
+cvs add: re-adding file foo.jpg (in place of dead revision 1.2)
+cvs add: use 'cvs commit' to add this file permanently
+floss$ cvs ci -m "revived jpg image" foo.jpg
+Checking in foo.jpg;
+/usr/local/newrepos/myproj/foo.jpg,v &lt;-- foo.jpg
+new revision: 1.3; previous revision: 1.2
+done
+floss$ cd /usr/local/newrepos/myproj/
+floss$ ls
+Attic/ a-subdir/ foo.jpg,v
+README.txt,v b-subdir/ hello.c,v
+floss$ ls Attic/
+floss$
+</pre>
+
+<p>There's a lot more to know about RCS format, but this is sufficient for
+a CVS adminstrator to maintain a repository. It's quite rare to
+actually edit an RCS file; you'll usually just have to tweak file
+permissions in the repository, at least if my own experience is any
+guide. Nevertheless, when CVS starts behaving truly weirdly (rare, but
+not completely outside the realm of possibility), you may want to
+actually look inside the RCS files to figure out what's going on.
+
+<p><hr>
+Node:<a name="The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>,
+Next:<a rel=next href="#Commit_Emails">Commit Emails</a>,
+Previous:<a rel=previous href="#What_Happens_When_You_Remove_A_File">What Happens When You Remove A File</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>The CVSROOT/ Administrative Directory</h2>
+
+<p>The files in newrepos/CVSROOT/ are not part of any project, but are used
+to control CVS's behavior in the repository. The best way to edit those
+files is to check out a working copy of CVSROOT, just like a regular
+project:
+
+<pre>floss$ cvs co CVSROOT
+cvs checkout: Updating CVSROOT
+U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/editinfo
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg
+floss$
+</pre>
+
+<p>We'll take the files in their approximate order of importance. Note
+that each of the files comes with an explanatory comment at the
+beginning (the comment convention is the same across all of them: A
+<code>#</code> sign at the beginning of the line signifies a comment, and CVS
+ignores such lines when parsing the files). Remember that any change
+you make to the administrative files in your checked out working copy
+won't affect CVS's behavior until you commit the changes.
+
+<p>If you're extremely security conscious, you may want to arrange the
+Unix-level permissions on CVSROOT to be different from permissions
+elsewhere in the repository, in order to have fine-grained control over
+who can commit changes to CVSROOT. As you'll see a little later, being
+able to modify the files in CVSROOT essentially gives any CVS user -
+even remote ones - the ability to run arbitrary commands on the
+repository machine.
+
+<ul>
+<li><a href="#The_config_File">The config File</a>:
+<li><a href="#The_modules_File">The modules File</a>:
+<li><a href="#The_commitinfo_And_loginfo_And_rcsinfo_Files">The commitinfo And loginfo And rcsinfo Files</a>:
+<li><a href="#The_verifymsg_And_rcsinfo_Files">The verifymsg And rcsinfo Files</a>:
+<li><a href="#The_taginfo_File">The taginfo File</a>:
+<li><a href="#The_cvswrappers_File">The cvswrappers File</a>:
+<li><a href="#The_editinfo_File">The editinfo File</a>:
+<li><a href="#The_notify_File">The notify File</a>:
+<li><a href="#The_checkoutlist_File">The checkoutlist File</a>:
+</ul>
+
+<p><hr>
+Node:<a name="The_config_File">The config File</a>,
+Next:<a rel=next href="#The_modules_File">The modules File</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The config File</h3>
+
+<p>The <dfn>config</dfn> file allows you to configure certain global behavioral
+parameters. It follows a very strict format
+
+<pre>PARAMETER=VALUE
+(etc)
+</pre>
+
+<p>with no extra spaces allowed. For example, here is a possible config
+file:
+
+<pre>SystemAuth=yes
+TopLevelAdmin=no
+PreservePermissions=no
+</pre>
+
+<p>(An absent entry would be equivalent to <code>no</code>.)
+
+<p>The <code>SystemAuth</code> parameter governs whether CVS should look in the
+system passwd file if it fails to find a given username in the
+CVSROOT/passwd file. CVS distributions are shipped with this set to
+<code>no</code> to be conservative about your system's security.
+
+<p><code>TopLevelAdmin</code> tells CVS whether to make a sibling CVS/ directory
+when it checks out a working copy. This CVS/ directory would not be
+inside the working copy, but rather next to it. It might be convenient
+to turn this on if you tend (and your repository's users tend) to check
+out many different projects from the same repository. Otherwise, you
+should leave it off, as it can be disconcerting to see an extra CVS/
+directory appear where you don't expect it.
+
+<p><code>PreservePermissions</code> governs whether to preserve file permissions
+and similar metadata in the revision history. This is a somewhat
+obscure feature that probably isn't worth describing in detail. See the
+node <cite>Special Files</cite> in the Cederqvist if you're interested
+(<dfn>node</dfn> is Texinfo-speak for a particular location within an Info
+document. To go to a node while reading Info, just type <kbd>g</kbd>
+followed by the name of the node, from anywhere inside the document).
+
+<p><code>LockDir</code> is also a rarely used feature. In special circumstances,
+you may want to tell CVS to create its lockfiles somewhere other than
+directly in the project subdirectories, in order to avoid permission
+problems. These lockfiles keep CVS from tripping over itself when
+multiple operations are performed on the same repository directory
+simultaneously. Generally, you never need to worry about them, but
+sometimes users may have trouble updating or checking out from a
+repository directory because they're unable to create a lockfile (even
+on read-only operations, CVS needs to create a lockfile to avoid
+situations where it could end up reading while another invocation of CVS
+is writing). The usual fix for this is to change repository
+permissions, but when that's not feasible, the LockDir parameter can
+come in handy.
+
+<p>There are no other parameters at this time, but future versions of CVS
+may add new ones; you should always check the Cederqvist or the
+distribution config file itself for updates.
+
+<p><hr>
+Node:<a name="The_modules_File">The modules File</a>,
+Next:<a rel=next href="#The_commitinfo_And_loginfo_And_rcsinfo_Files">The commitinfo And loginfo And rcsinfo Files</a>,
+Previous:<a rel=previous href="#The_config_File">The config File</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The modules File</h3>
+
+<p>In modules, you can define aliases and alternate groupings for projects
+in the repository. The most basic module line is of the form:
+
+<pre>MODULE_NAME DIRECTORY_IN_REPOSITORY
+</pre>
+
+<p>for example,
+
+<pre>mp myproj
+asub myproj/a-subdir
+</pre>
+
+<p>(The paths given on the right are relative to the top of the
+repository.) This gives developers an alternate name by which to check
+out a project or a portion of a project:
+
+<pre>floss$ cvs co mp
+cvs checkout: Updating mp
+U mp/README.txt
+U mp/foo.jpg
+U mp/hello.c
+cvs checkout: Updating mp/a-subdir
+U mp/a-subdir/whatever.c
+cvs checkout: Updating mp/a-subdir/subsubdir
+U mp/a-subdir/subsubdir/fish.c
+cvs checkout: Updating mp/b-subdir
+U mp/b-subdir/random.c
+</pre>
+
+<p>or
+
+<pre>floss$ cvs -d /usr/local/newrepos/ co asub
+cvs checkout: Updating asub
+U asub/whatever.c
+cvs checkout: Updating asub/subsubdir
+U asub/subsubdir/fish.c
+</pre>
+
+<p>Notice how in both cases the module's name became the name of the
+directory created for the working copy. In the case of asub, it didn't
+even bother with the intermediate myproj/ directory, but created a
+top-level asub/ instead, even though it came from myproj/a-subdir in the
+repository. Updates, commits, and all other CVS commands will behave
+normally in those working copies - the only thing unusual about them
+are their names.
+
+<p>By putting file names after the directory name, you can define a module
+consisting of just some of the files in a given repository directory.
+For example
+
+<pre>readme myproj README.txt
+</pre>
+
+<p>and
+
+<pre>no-readme myproj hello.c foo.jpg
+</pre>
+
+<p>would permit the following checkouts, respectively:
+
+<pre>floss$ cvs -q co readme
+U readme/README.txt
+floss$ cvs -q co no-readme
+U no-readme/hello.c
+U no-readme/foo.jpg
+floss$
+</pre>
+
+<p>You can define a module that will include multiple repository
+directories by using the -a (for <code>alias</code>) flag, but note that the
+directories will get them checked out under their original names. For
+example, this line
+
+<pre>twoproj -a myproj yourproj
+</pre>
+
+<p>would allow you to do this (assuming that both myproj/ and yourproj/ are
+in the repository):
+
+<pre>floss$ cvs co twoproj
+U myproj/README.txt
+U myproj/foo.jpg
+U myproj/hello.c
+U myproj/a-subdir/whatever.c
+U myproj/a-subdir/subsubdir/fish.c
+U myproj/b-subdir/random.c
+U yourproj/README
+U yourproj/foo.c
+U yourproj/some-subdir/file1.c
+U yourproj/some-subdir/file2.c
+U yourproj/some-subdir/another-subdir/blah.c
+</pre>
+
+<p>The name <code>twoproj</code> was a convenient handle to pull in both
+projects, but it didn't affect the names of the working copies. (There
+is no requirement that alias modules refer to multiple directories, by
+the way; we could have omitted twoproj, in which case myproj would still
+have been checked out under the name <code>myproj</code>.)
+
+<p>Modules can even refer to other modules, by prefixing them with an
+ampersand:
+
+<pre>mp myproj
+asub myproj/a-subdir
+twoproj -a myproj yourproj
+tp &amp;twoproj
+</pre>
+
+<p>Doing a checkout of <code>tp</code> would have exactly the same result as the
+checkout of <code>twoproj</code> did.
+
+<p>There are a few other tricks you can do with modules, most of them less
+frequently used than the ones just presented. See the node modules in
+the Cederqvist for information about them.
+
+<p><hr>
+Node:<a name="The_commitinfo_And_loginfo_And_rcsinfo_Files">The commitinfo And loginfo And rcsinfo Files</a>,
+Next:<a rel=next href="#The_verifymsg_And_rcsinfo_Files">The verifymsg And rcsinfo Files</a>,
+Previous:<a rel=previous href="#The_modules_File">The modules File</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The commitinfo And loginfo And rcsinfo Files</h3>
+
+<p>Most of the other administrative files provide programmatic <dfn>hooks</dfn>
+into various parts of the commit process (for example, the ability to
+validate log messages or file states before permitting the commit, or
+the ability to notify a group of developers whenever a commit happens in
+a certain directory of the repository).
+
+<p>The files generally share a common syntax. Each line is of the form:
+
+<pre>REGULAR_EXPRESSION PROGRAM_TO_RUN
+</pre>
+
+<p>The regular expression will be tested against the directory into which
+the commit is taking place (with the directory name relative to the top
+of the repository). If it matches, the designated program will be run.
+The program will be passed the names of each of the files in the commit;
+it can do whatever it likes with those names, including opening up the
+files and examining their contents. If the program returns with a
+nonzero exit status, the commit is prevented from taking place.
+
+<p>(<dfn>Regular expressions</dfn> are a system for concisely describing classes
+of strings. If you aren't familiar with regular expressions, you can
+get by with the following short summary: <code>foo</code> would match any file
+whose name contains the string <code>foo</code>; and <code>foo.*bar</code> would
+match any file whose name contains <code>foo</code>, followed by any number of
+characters, followed by the string <code>bar</code>. That's because normal
+substrings match themselves, but <code>.</code> and <code>*</code> are special.
+<code>.</code> matches any character, and <code>*</code> means match any number of
+the preceding character, including zero. The <code>^</code> and <code>$</code>
+signs mean match at the beginning and end of the string, respectively;
+thus, <code>^foo.*bar.*baz$</code> would match any string beginning with
+<code>foo</code>, containing <code>bar</code> somewhere in the middle, and ending
+with <code>baz</code>. That's all we'll go into here; this summary is a very
+abbreviated subset of full regular expression syntax.)
+
+<p>The <dfn>commitinfo</dfn> file is for generic hooks you want run on every
+commit. Here are some example commitinfo lines:
+
+<pre>^a-subdir* /usr/local/bin/check-asubdir.sh
+ou /usr/local/bin/validate-project.pl
+</pre>
+
+<p>So any commit into myproj/a-subdir/ would match the first line, which
+would then run the check-asubdir.sh script. A commit in any project
+whose name (actual repository directory name, not necessarily module
+name) contained the string <code>ou</code> would run the validate-project.pl
+script, unless the commit had already matched the previous a-subdir
+line.
+
+<p>In place of a regular expression, the word <code>DEFAULT</code> or <code>ALL</code>
+may be used. The DEFAULT line (or the first DEFAULT line, if there are
+more than one) will be run if no regular expression matches, and each of
+the ALL lines will be run in addition to any other lines that may match.
+
+<p>The file names passed to the program do not refer to RCS files - they
+point to normal files, whose contents are exactly the same as the
+working-copy files being committed. The only unusual aspect is that CVS
+has them temporarily placed inside the repository, so they'll be
+available to programs running on the machine where the repository is
+located.
+
+<p>The <dfn>loginfo</dfn> file is similar to commitinfo, except that instead of
+acting on the files' contents, it acts on the log message. The left
+side of the loginfo file contains regular expressions, including
+possibly DEFAULT and ALL lines. The program invoked on the right side
+receives the log message on its standard input; it can do whatever it
+wants with that input.
+
+<p>The program on the right side can also take an arbitrary number of
+command-line arguments. One of those arguments can be a special
+<code>%</code> code, to be expanded by CVS at runtime, as follows:
+
+<pre>%s ------&gt; name(s) of the file(s) being committed
+%V ------&gt; revision number(s) before the commit
+%v ------&gt; revision number(s) after the commit
+</pre>
+
+<p>The expansion always begins with the repository subdirectory (relative
+to the top of the repository), followed by the per-file information.
+For example, if the files committed were foo, bar, and baz, all in
+<code>myproj/a-subdir</code>, then <code>%s</code> would expand into
+
+<pre>myproj/a-subdir foo bar baz
+</pre>
+
+<p>whereas <code>%V</code> would expand to show their old revision numbers
+
+<pre>myproj/a-subdir 1.7 1.134 1.12
+</pre>
+
+<p>and <code>%v</code> their new revision numbers:
+
+<pre>myproj/a-subdir 1.8 1.135 1.13
+</pre>
+
+<p>You can combine <code>%</code> expressions by enclosing them in curly braces
+following <code>%</code> sign - this will expand them into a series of
+comma-separated sublists, each containing the corresponding information
+for one file in the commit. For instance, <code>%{sv}</code> would expand
+to
+
+<pre>myproj/a-subdir foo,1.8 bar,1.135 baz,1.13
+</pre>
+
+<p>and <code>%{sVv}</code> would expand to
+
+<pre>myproj/a-subdir foo,1.7,1.8 bar,1.134,1.135 baz,1.12,1.13
+</pre>
+
+<p>(You may have to look carefully to distinguish the commas from the
+periods in those examples.)
+
+<p>Here is a sample loginfo file:
+
+<pre>^myproj$ /usr/local/newrepos/CVSROOT/log.pl -m myproj-devel@foobar.com %s
+ou /usr/local/bin/ou-notify.pl %{sv}
+DEFAULT /usr/local/bin/default-notify.pl %{sVv}
+</pre>
+
+<p>In the first line, any commit in the myproj subdirectory of the
+repository invokes <code>log.pl</code>, passing it an email address (to which
+<code>log.pl</code> will send a mail containing the log message), followed by
+the repository, followed by all the files in the commit.
+
+<p>In the second line, any commit in a repository subdirectory containing
+the string <code>ou</code> will invoke the (imaginary) <code>ou-notify.pl</code>
+script, passing it the repository followed by the file names and new
+revision numbers of the files in the commit.
+
+<p>The third line invokes the (equally imaginary) <code>default-notify.pl</code>
+script for any commit that didn't match either of the two previous
+lines, passing it all possible information (path to repository, file
+names, old revisions, and new revisions).
+
+<p><hr>
+Node:<a name="The_verifymsg_And_rcsinfo_Files">The verifymsg And rcsinfo Files</a>,
+Next:<a rel=next href="#The_taginfo_File">The taginfo File</a>,
+Previous:<a rel=previous href="#The_commitinfo_And_loginfo_And_rcsinfo_Files">The commitinfo And loginfo And rcsinfo Files</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The verifymsg And rcsinfo Files</h3>
+
+<p>Sometimes you may just want a program to automatically verify that the
+log message conforms to a certain standard and to stop the commit if
+that standard is not met. This can be accomplished by using
+<code>verifymsg</code>, possibly with some help from <code>rcsinfo</code>.
+
+<p>The <dfn>verifymsg</dfn> file is the usual combination of regular expressions
+and programs. The program receives the log message on standard input;
+presumably it runs some checks to verify that the log message meets
+certain criteria, then it exits with status zero or nonzero. If the
+latter, the commit will fail.
+
+<p>Meanwhile, the left side of rcsinfo has the usual regular expressions,
+but the right side points to template files instead of programs. A
+template file might be something like this
+
+<pre>Condition:
+Fix:
+Comments:
+</pre>
+
+<p>or some other collection of fields that a developer is supposed to fill
+out to form a valid log message. The template is not very useful if
+everyone commits using the -m option explicitly, but many developers
+prefer not to do that. Instead, they run
+
+<pre>floss$ cvs commit
+</pre>
+
+<p>and wait for CVS to automatically fire up a text editor (as specified in
+the EDITOR environment variable). There they write a log message, then
+save the file and exit the editor, after which CVS continues with the
+commit.
+
+<p>In that scenario, an rcsinfo template would insert itself into the
+editor before the user starts typing, so the fields would be displayed
+along with a reminder to fill them in. Then when the user commits, the
+appropriate program in <code>verifymsg</code> is invoked. Presumably, it will
+check that the message does follow that format, and its exit status will
+reflect the results of its inquiry (with zero meaning success).
+
+<p>As an aid to the verification programs, the path to the template from
+the rcsinfo file is appended as the last argument to the program command
+line in <code>verifymsg</code>; that way, the program can base its
+verification process on the template itself, if desired.
+
+<p>Note that when someone checks out a working copy to a remote machine,
+the appropriate rcsinfo template file is sent to the client as well
+(it's stored in the CVS/ subdirectory of the working copy). However,
+this means that if the rcsinfo file on the server is changed after that,
+the client won't see the changes without re-checking out the project
+(merely doing an update won't work).
+
+<p>Note also that in the verifymsg file, the ALL keyword is not supported
+(although DEFAULT still is). This is to make it easier to override
+default verification scripts with subdirectory-specific ones.
+
+<p><hr>
+Node:<a name="The_taginfo_File">The taginfo File</a>,
+Next:<a rel=next href="#The_cvswrappers_File">The cvswrappers File</a>,
+Previous:<a rel=previous href="#The_verifymsg_And_rcsinfo_Files">The verifymsg And rcsinfo Files</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The taginfo File</h3>
+
+<p>What loginfo does for log messages, taginfo does for tags. The left
+side of taginfo is regular expressions, as usual, and the right side is
+programs. Each program is automatically handed arguments when CVS tag
+is invoked, in this order:
+
+<pre>arg 1: tag name
+arg 2: operation ("add" =&gt; tag, "mov" =&gt; tag -F, "del" =&gt; tag -d)
+arg 3: repository
+arg 4, 5, etc: file revision [file revision ...]
+</pre>
+
+<p>If the program returns nonzero, the tag is aborted.
+
+<p>We haven't covered the -F option to tag before now, but it's exactly
+what the above implies: a way to move a tag from one revision to
+another. For example, if the tag <code>Known_Working</code> is attached to
+Revision 1.7 of a file and you want it attached to Revision 1.11
+instead, you'd do this
+
+<pre>cvs tag -r 1.11 -F Known_Working foo.c
+</pre>
+
+<p>which removes the tag from 1.7, or wherever it was previously in that
+file, and puts it at 1.11.
+
+<p><hr>
+Node:<a name="The_cvswrappers_File">The cvswrappers File</a>,
+Next:<a rel=next href="#The_editinfo_File">The editinfo File</a>,
+Previous:<a rel=previous href="#The_taginfo_File">The taginfo File</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The cvswrappers File</h3>
+
+<p>The redundantly-named cvswrappers file gives you a way to specify that
+certain files should be treated as binary, based on their file name.
+CVS does not assume that all .jpg files are JPG image data, for example,
+so it doesn't automatically use -kb when adding JPG files. Nonetheless,
+certain projects would find it very useful to simply designate all JPG
+files as binary. Here is a line in cvswrappers to do that:
+
+<pre>*.jpg -k 'b'
+</pre>
+
+<p>The <code>b</code> is separate and in quotes because it's not the only
+possible RCS keyword expansion mode; one could also specify <code>o</code>,
+which means not to expand <code>$</code> sign keywords but to do newline
+conversion. However, <code>b</code> is the most common parameter.
+
+<p>There are a few other modes that can be specified from the wrappers
+file, but they're for such rare situations that they're probably not
+worth documenting here (translation: your author has never had to use
+them). See the node <cite>Wrappers</cite> in the Cederqvist if you're
+curious.
+
+<p><hr>
+Node:<a name="The_editinfo_File">The editinfo File</a>,
+Next:<a rel=next href="#The_notify_File">The notify File</a>,
+Previous:<a rel=previous href="#The_cvswrappers_File">The cvswrappers File</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The editinfo File</h3>
+
+<p>This file is obsolete, even though it's still included in distributions.
+Just ignore it.
+
+<p><hr>
+Node:<a name="The_notify_File">The notify File</a>,
+Next:<a rel=next href="#The_checkoutlist_File">The checkoutlist File</a>,
+Previous:<a rel=previous href="#The_editinfo_File">The editinfo File</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The notify File</h3>
+
+<p>This file is used in conjunction with CVS's <code>watch</code> features, which
+are described in <a href="#Advanced_CVS">Advanced CVS</a>. Nothing about it will make sense
+until you understand what watches are (they're a useful but
+non-essential feature), so see <a href="#Advanced_CVS">Advanced CVS</a> for details about this
+file and about watches.
+
+<p><hr>
+Node:<a name="The_checkoutlist_File">The checkoutlist File</a>,
+Previous:<a rel=previous href="#The_notify_File">The notify File</a>,
+Up:<a rel=up href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>
+<br>
+
+<h3>The checkoutlist File</h3>
+
+<p>If you look inside CVSROOT/, you'll see that working copies of the files
+exist side by side with their RCS revision files:
+
+<pre>floss$ ls /usr/local/newrepos/CVSROOT
+checkoutlist config,v history notify taginfo
+checkoutlist,v cvswrappers loginfo notify,v taginfo,v
+commitinfo cvswrappers,v loginfo,v passwd verifymsg
+commitinfo,v editinfo modules rcsinfo verifymsg,v
+config editinfo,v modules,v rcsinfo,v
+
+floss$
+</pre>
+
+<p>CVS only pays attention to the working versions, not the RCS files, when
+it's looking for guidance on how to behave. Therefore, whenever you
+commit your working copy of CVSROOT/ (which might, after all, even be
+checked out to a different machine), CVS automatically updates any
+changed files in the repository itself. You will know that this has
+happened because CVS will print a message at the end of such commits:
+
+<pre>floss$ cvs ci -m "added mp and asub modules" modules
+Checking in modules;
+/usr/local/newrepos/CVSROOT/modules,v &lt;-- modules
+new revision: 1.2; previous revision: 1.1
+done
+cvs commit: Rebuilding administrative file database
+</pre>
+
+<p>CVS automatically knows about the standard administrative files, and
+will rebuild them in CVSROOT/ as necessary. If you decide to put custom
+files in CVSROOT/ (such as programs or rcsinfo template files), you'll
+have to tell CVS explicitly to treat them the same way.
+
+<p>That's the purpose of the checkoutlist file. It has a different format
+from most of the files we've looked at so far
+
+<pre>FILENAME ERROR_MESSAGE_IF_FILE_CANNOT_BE_CHECKED_OUT
+</pre>
+
+<p>for example,
+
+<pre>log.pl unable to check out / update log.pl in CVSROOT
+
+bugfix.tmpl unable to check out / update bugfix.tmpl in CVSROOT
+</pre>
+
+<p>Certain files in CVSROOT are traditionally not kept under revision
+control. One such is the <dfn>history</dfn> file, which keeps a running
+record of all actions in the repository, for use by the <code>cvs&nbsp;history</code> command (which lists checkout, update, and tag activity for a
+given file or project directory). Incidentally, if you just remove the
+<code>history</code> file, CVS will obligingly stop keeping that log.
+
+<p>Note: sometimes the history file is the cause of permission problems,
+and the easiest way to solve them is to either make it world-writeable
+or just remove it.
+
+<p>Another <code>unrevisioned</code> administrative file is passwd, the
+assumption being that having it checked out over the network might
+compromise the passwords (even though they're encrypted). You'll have
+to decide based on your own security situation whether you want to add
+passwd to checkoutlist or not; by default, it is not in checkoutlist.
+
+<p>Two final notes about the CVSROOT/ directory: It is possible, if you
+make a big enough mistake, to commit an administrative file that is
+broken in such a way as to prevent any commits from happening at all.
+If you do that, naturally you won't be able to commit a fixed version of
+the administrative file! The solution is to go in and hand-edit the
+repository's working copy of the administrative file to correct the
+problem; the whole repository may stay inaccessible until you do that.
+
+<p>Also, for security's sake, make sure your CVSROOT/ directory is only
+writeable by users you trust (by <code>trust</code>, I mean you trust both
+their intentions and their ability not to compromise their password).
+The <code>*info</code> files give people the ability to invoke arbitrary
+programs, so anyone who can commit or edit files in the CVSROOT/
+directory can essentially run any command on the system. That's
+something you should always keep in mind.
+
+<p><hr>
+Node:<a name="Commit_Emails">Commit Emails</a>,
+Next:<a rel=next href="#Finding_Out_More">Finding Out More</a>,
+Previous:<a rel=previous href="#The_CVSROOT__Administrative_Directory">The CVSROOT/ Administrative Directory</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>Commit Emails</h2>
+
+<p>The loginfo file is how one sets up commit emails - automated emails
+that go out to everyone working on a project whenever a commit takes
+place. (It may seem counterintuitive that this is done in loginfo
+instead of commitinfo, but the point is that one wants to include the
+log message in the email). The program to do the mailing -
+<code>contrib/log.pl</code> in the CVS source distribution - can be installed
+anywhere on your system. I customarily put it in the repository's
+CVSROOT/ subdirectory, but that's just a matter of taste.
+
+<p>You may need to edit <code>log.pl</code> a bit to get it to work on your
+system, possibly changing the first line to point to your Perl
+interpreter, and maybe changing this line
+
+<pre>$mailcmd = "| Mail -s 'CVS update: $modulepath'";
+</pre>
+
+<p>to invoke your preferred mailer, which may or may not be named
+<code>Mail</code>. Once you've got it set the way you like it, you can put
+lines similar to these into your loginfo:
+
+<pre>listerizer CVSROOT/log.pl %s -f CVSROOT/commitlog -m listerizer@red-bean.com
+RoadMail CVSROOT/log.pl %s -f CVSROOT/commitlog -m roadmail@red-bean.com
+bk/*score CVSROOT/log.pl %s -f CVSROOT/commitlog -m \
+ bkscore-devel@red-bean.com
+</pre>
+
+<p>The <code>%s</code> expands to the names of the files being committed; the -f
+option to <code>log.pl</code> takes a file name, to which the log message will
+be appended (so CVSROOT/commitlog is an ever-growing file of log
+messages); and the -m flag takes an email address, to which
+<code>log.pl</code> will send a message about the commit. The address is
+usually a mailing list, but you can specify the -m option as many times
+as necessary in one log.pl command line.
+
+<p><hr>
+Node:<a name="Finding_Out_More">Finding Out More</a>,
+Previous:<a rel=previous href="#Commit_Emails">Commit Emails</a>,
+Up:<a rel=up href="#Repository_Administration">Repository Administration</a>
+<br>
+
+<h2>Finding Out More</h2>
+
+<p>Although this chapter tries to give a complete introduction to
+installing and administering CVS, I've left out things that are either
+too rarely used to be worth mentioning or already well documented in the
+Cederqvist manual. The latter category includes setting up the other
+remote access methods: RSH/SSH, kserver (Kerberos 4), and GSSAPI (which
+includes Kerberos 5, among other things). It should be noted that
+nothing special needs to be done for RSH/SSH connections, other than
+making sure that the user in question can log into the repository
+machine using RSH or SSH. If they can and CVS is installed on both
+client and server, and they have the right permissions to use the
+repository directly from the server machine, then they should be able to
+access the repository remotely via the :ext: method.
+
+<p>Descriptions of certain specialized features of CVS have been deferred
+to later chapters, so they can be introduced in contexts where their
+usefulness is obvious. General CVS troubleshooting tips are found in
+<a href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>. Although it's not necessary to read the
+entire Cederqvist manual, you should familiarize yourself with it; it
+will be an invaluable reference tool. If for some reason you don't have
+Info working on your machine and don't want to print the manual, you can
+browse it online at <a href="http://durak.org/cvswebsites/doc/">http://durak.org/cvswebsites/doc/</a> or
+<a href="http://www.loria.fr/~molli/cvs/doc/cvs_toc.html">http://www.loria.fr/~molli/cvs/doc/cvs_toc.html</a>.
+
+<p><hr>
+Node:<a name="Advanced_CVS">Advanced CVS</a>,
+Next:<a rel=next href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>,
+Previous:<a rel=previous href="#Repository_Administration">Repository Administration</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>Advanced CVS</h1>
+
+<p>Now that we've covered the basic concepts of CVS usage and repository
+administration, we'll look at how CVS can be incorporated into the
+entire process of development. The fundamental CVS working cycle -
+checkout, update, commit, update, commit, and so on - was demonstrated
+by the examples in <a href="#An_Overview_of_CVS">An Overview of CVS</a>. This chapter elaborates on
+the cycle and discusses how CVS can be used to help developers
+communicate, give overviews of project activity and history, isolate and
+reunite different branches of development, and automate frequently
+performed tasks. Some of the techniques covered introduce new CVS
+commands, but many merely explain better ways to use commands that you
+already know.
+
+<ul>
+<li><a href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>:
+<li><a href="#Log_Messages_And_Commit_Emails">Log Messages And Commit Emails</a>:
+<li><a href="#Changing_A_Log_Message_After_Commit">Changing A Log Message After Commit</a>:
+<li><a href="#Getting_Rid_Of_A_Working_Copy">Getting Rid Of A Working Copy</a>:
+<li><a href="#History_--_A_Summary_Of_Repository_Activity">History -- A Summary Of Repository Activity</a>:
+<li><a href="#Annotations_--_A_Detailed_View_Of_Project_Activity">Annotations -- A Detailed View Of Project Activity</a>:
+<li><a href="#Annotations_And_Branches">Annotations And Branches</a>:
+<li><a href="#Using_Keyword_Expansion">Using Keyword Expansion</a>:
+<li><a href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>:
+<li><a href="#Tracking_Third-Party_Sources__Vendor_Branches_">Tracking Third-Party Sources (Vendor Branches)</a>:
+<li><a href="#Exporting_For_Public_Distribution">Exporting For Public Distribution</a>:
+<li><a href="#The_Humble_Guru">The Humble Guru</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>,
+Next:<a rel=next href="#Log_Messages_And_Commit_Emails">Log Messages And Commit Emails</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Watches (CVS As Telephone)</h2>
+
+<p>A major benefit of using CVS on a project is that it can function as a
+communications device as well as a record-keeper. This section
+concentrates on how CVS can be used to keep participants informed about
+what's going on in a project. As is true with other aspects of CVS,
+these features reward cooperation. The participants must want to be
+informed; if people choose not to use the communications features,
+there's nothing CVS can do about it.
+
+<ul>
+<li><a href="#How_Watches_Work">How Watches Work</a>:
+<li><a href="#Enabling_Watches_In_The_Repository">Enabling Watches In The Repository</a>:
+<li><a href="#Using_Watches_In_Development">Using Watches In Development</a>:
+<li><a href="#Ending_An_Editing_Session">Ending An Editing Session</a>:
+<li><a href="#Controlling_What_Actions_Are_Watched">Controlling What Actions Are Watched</a>:
+<li><a href="#Finding_Out_Who_Is_Watching_What">Finding Out Who Is Watching What</a>:
+<li><a href="#Reminding_People_To_Use_Watches">Reminding People To Use Watches</a>:
+<li><a href="#What_Watches_Look_Like_In_The_Repository">What Watches Look Like In The Repository</a>:
+</ul>
+
+<p><hr>
+Node:<a name="How_Watches_Work">How Watches Work</a>,
+Next:<a rel=next href="#Enabling_Watches_In_The_Repository">Enabling Watches In The Repository</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>How Watches Work</h3>
+
+<p>In its default behavior, CVS treats each working copy as an isolated
+sandbox. No one knows what you're doing in your working copy until you
+commit your changes. In turn, you don't know what others are doing in
+theirs - except via the usual methods of communication, such as
+shouting down the hallway, "Hey, I'm going to work on parse.c now. Let
+me know if you're editing it so we can avoid conflicts!"
+
+<p>This informality works for projects where people have a general idea of
+who's responsible for what. However, this process can break down when a
+large number of developers are active in all parts of a code base and
+want to avoid conflicts. In such cases, they frequently have to cross
+each others' areas of responsibility but can't shout down the hallway at
+each other because they're geographically distributed.
+
+<p>A feature of CVS called <code>watches</code> provides developers with a way to
+notify each other about who is working on what files at a given time.
+By "setting a watch" on a file, a developer can have CVS notify her if
+anyone else starts to work on that file. The notifications are normally
+sent via email, although it is possible to set up other notification
+methods.
+
+<p>To use watches, you must modify one or two files in the repository
+administrative area, and developers must add some extra steps to the
+usual checkout/update/commit cycle. The changes on the repository side
+are fairly simple: You may need to edit the <code>CVSROOT/notify</code> file
+so that CVS knows how notifications are to be performed. You may also
+have to add lines to the <code>CVSROOT/users</code> file, which supplies
+external email addresses.
+
+<p>On the working copy side, developers have to tell CVS which files they
+want to watch so that CVS can send them notifications when someone else
+starts editing those files. They also need to tell CVS when they start
+or stop editing a file, so CVS can send out notifications to others who
+may be watching. The following commands are used to implement these
+extra steps:
+
+<ul>
+<li>cvs watch
+<li>cvs edit
+<li>cvs unedit
+</ul>
+
+<p>The command <code>watch</code> differs from the usual CVS command pattern in
+that it requires further subcommands, such as <code>cvs&nbsp;watch&nbsp;add...</code>, <code>cvs&nbsp;watch&nbsp;remove...</code>, and so on.
+
+<p>In the following example, we'll look at how to turn on watches in the
+repository and then how to use watches from the developer's side. The
+two example users, jrandom and qsmith, each have their own separate
+working copies of the same project; the working copies may even be on
+different machines. As usual, all examples assume that the $CVSROOT
+environment variable has already been set, so there's no need to pass -d
+&lt;REPOS&gt; to any CVS commands.
+
+<p><hr>
+Node:<a name="Enabling_Watches_In_The_Repository">Enabling Watches In The Repository</a>,
+Next:<a rel=next href="#Using_Watches_In_Development">Using Watches In Development</a>,
+Previous:<a rel=previous href="#How_Watches_Work">How Watches Work</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>Enabling Watches In The Repository</h3>
+
+<p>First, the CVSROOT/notify file must be edited to turn on email
+notification. One of the developers can do this, or the repository
+administrator can if the developers don't have permission to change the
+repository's administrative files. In any case, the first thing to do is
+check out the administrative area and edit the notify file:
+
+<pre>floss$ cvs -q co CVSROOT
+U CVSROOT/checkoutlist
+U CVSROOT/commitinfo
+U CVSROOT/config
+U CVSROOT/cvswrappers
+U CVSROOT/editinfo
+U CVSROOT/loginfo
+U CVSROOT/modules
+U CVSROOT/notify
+U CVSROOT/rcsinfo
+U CVSROOT/taginfo
+U CVSROOT/verifymsg
+floss$ cd CVSROOT
+floss$ emacs notify
+...
+</pre>
+
+<p>When you edit the notify file for the first time, you'll see something
+like this:
+
+<pre># The "notify" file controls where notifications from watches set by
+# "cvs watch add" or "cvs edit" are sent. The first entry on a line is
+# a regular expression which is tested against the directory that the
+# change is being made to, relative to the $CVSROOT. If it matches,
+# then the remainder of the line is a filter program that should contain
+# one occurrence of %s for the user to notify, and information on its
+# standard input.
+#
+# "ALL" or "DEFAULT" can be used in place of the regular expression.
+#
+# For example:
+# ALL mail %s -s "CVS notification"
+</pre>
+
+<p>All you really need to do is uncomment the last line by removing the
+initial <code>#</code> mark. Although the notify file provides the same
+flexible interface as the other administrative files, with regular
+expressions matching against directory names, the truth is that you
+almost never want to use any of that flexibility. The only reason to
+have multiple lines, with each line's regular expression matching a
+particular part of the repository, would be if you wanted to use a
+different notification method for each project. However, normal email
+is a perfectly good notification mechanism, so most projects just use
+that.
+
+<p>To specify email notification, the line
+
+<pre>ALL mail %s -s "CVS notification"
+</pre>
+
+<p>should work on any standard Unix machine. This command causes
+notifications to be sent as emails with the subject line <code>CVS
+notification</code> (the special expression ALL matches any directory, as
+usual). Having uncommented that line, commit the notify file so the
+repository is aware of the change:
+
+<pre>floss$ cvs ci -m "turned on watch notification"
+cvs commit: Examining .
+Checking in notify;
+/usr/local/newrepos/CVSROOT/notify,v &lt;-- notify
+new revision: 1.2; previous revision: 1.1
+done
+cvs commit: Rebuilding administrative file database
+floss$
+</pre>
+
+<p>Editing the notify file in this way may be all that you'll need to do
+for watches in the repository. However, if there are remote developers
+working on the project, you may need to edit the <code>CVSROOT/users</code>
+file, too. The purpose of the users file is to tell CVS where to send
+email notifications for those users who have external email addresses.
+The format of each line in the users file is:
+
+<pre>CVS_USERNAME:EMAIL_ADDRESS
+</pre>
+
+<p>For example,
+
+<pre>qsmith:quentinsmith@farawayplace.com
+</pre>
+
+<p>The CVS username at the beginning of the line corresponds to a CVS
+username in <code>CVSROOT/password</code> (if present and the pserver access
+method is being used), or failing that, the server-side system username
+of the person running CVS. Following the colon is an external email
+address to which CVS should send watch notifications for that user.
+
+<p>Unfortunately, as of this writing, the users file does not exist in the
+stock CVS distribution. Because it's an administrative file, you must
+not only create, cvs add, and commit it in the usual way, but also add
+it to <code>CVSROOT/checkoutlist</code> so that a checked-out copy is always
+maintained in the repository.
+
+<p>Here is a sample session demonstrating this:
+
+<pre>floss$ emacs checkoutlist
+ ... (add the line for the users file) ...
+floss$ emacs users
+ ... (add the line for qsmith) ...
+floss$ cvs add users
+floss$ cvs ci -m "added users to checkoutlist, qsmith to users"
+cvs commit: Examining .
+Checking in checkoutlist;
+/usr/local/newrepos/CVSROOT/checkoutlist,v &lt;-- checkoutlist
+new revision: 1.2; previous revision: 1.1
+done
+Checking in users;
+/usr/local/newrepos/CVSROOT/users,v &lt;-- users
+new revision: 1.2; previous revision: 1.1
+done
+cvs commit: Rebuilding administrative file database
+floss$
+</pre>
+
+<p>It's possible to use expanded-format email addresses in
+<code>CVSROOT/users</code>, but you have to be careful to encapsulate all
+whitespace within quotes. For example, the following will work
+
+<pre>qsmith:"Quentin Q. Smith &lt;quentinsmith@farawayplace.com&gt;"
+</pre>
+
+<p>or
+
+<pre>qsmith:'Quentin Q. Smith &lt;quentinsmith@farawayplace.com&gt;'
+</pre>
+
+<p>However, this will not work:
+
+<pre>qsmith:"Quentin Q. Smith" &lt;quentinsmith@farawayplace.com&gt;
+</pre>
+
+<p>When in doubt, you should test by running the command line given in the
+notify file manually. Just replace the <code>%s</code> in
+
+<pre>mail %s -s "CVS notification"
+</pre>
+
+<p>with what you have following the colon in users. If it works when you
+run it at a command prompt, it should work in the users file, too.
+
+<p>When it's over, the checkout file will look like this:
+
+<pre># The "checkoutlist" file is used to support additional version controlled
+# administrative files in $CVSROOT/CVSROOT, such as template files.
+#
+# The first entry on a line is a filename which will be checked out from
+# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
+# The remainder of the line is an error message to use if the file cannot
+# be checked out.
+#
+# File format:
+#
+# [&lt;whitespace&gt;]&lt;filename&gt;&lt;whitespace&gt;&lt;error message&gt;&lt;end-of-line&gt;
+#
+# comment lines begin with '#'
+
+users Unable to check out 'users' file in CVSROOT.
+</pre>
+
+<p>The users file will look like this:
+
+<pre>qsmith:quentinsmith@farawayplace.com
+</pre>
+
+<p>Now that the repository is set up for watches, let's look at what
+developers need to do in their working copies.
+
+<p><hr>
+Node:<a name="Using_Watches_In_Development">Using Watches In Development</a>,
+Next:<a rel=next href="#Ending_An_Editing_Session">Ending An Editing Session</a>,
+Previous:<a rel=previous href="#Enabling_Watches_In_The_Repository">Enabling Watches In The Repository</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>Using Watches In Development</h3>
+
+<p>First, a developer checks out a working copy and adds herself to the
+list of watchers for one of the files in the project:
+
+<pre>floss$ whoami
+jrandom
+floss$ cvs -q co myproj
+U myproj/README.txt
+U myproj/foo.gif
+U myproj/hello.c
+U myproj/a-subdir/whatever.c
+U myproj/a-subdir/subsubdir/fish.c
+U myproj/b-subdir/random.c
+floss$ cd myproj
+floss$ cvs watch add hello.c
+floss$
+</pre>
+
+<p>The last command, cvs watch add hello.c, tells CVS to notify jrandom if
+anyone else starts working on hello.c (that is, it adds jrandom to
+hello.c's watch list). For CVS to send notifications as soon as a file
+is being edited, the user who is editing it has to announce the fact by
+running cvs edit on the file first. CVS has no other way of knowing
+when someone starts working on a file. Once checkout is done, CVS isn't
+usually invoked until the next update or commit, which happens after the
+file has already been edited:
+
+<pre>paste$ whoami
+qsmith
+paste$ cvs -q co myproj
+U myproj/README.txt
+U myproj/foo.gif
+U myproj/hello.c
+U myproj/a-subdir/whatever.c
+U myproj/a-subdir/subsubdir/fish.c
+U myproj/b-subdir/random.c
+paste$ cd myproj
+paste$ cvs edit hello.c
+paste$ emacs hello.c
+...
+</pre>
+
+<p>When qsmith runs cvs edit hello.c, CVS looks at the watch list for
+hello.c, sees that jrandom is on it, and sends email to jrandom telling
+her that qsmith has started editing the file. The email even appears to
+come from qsmith:
+
+<pre>From: qsmith
+Subject: CVS notification
+To: jrandom
+Date: Sat, 17 Jul 1999 22:14:43 -0500
+
+myproj hello.c
+--
+Triggered edit watch on /usr/local/newrepos/myproj
+By qsmith
+
+Furthermore, every time that qsmith (or anyone) commits a new revision of hello.c, jrandom will receive another email:
+
+myproj hello.c
+--
+Triggered commit watch on /usr/local/newrepos/myproj
+By qsmith
+</pre>
+
+<p>After receiving these emails, jrandom may want to update hello.c
+immediately to see what qsmith has done, or perhaps she'll email qsmith
+to find out why he's working on that file. Note that nothing forced
+qsmith to remember to run cvs edit - presumably he did it because he
+wanted jrandom to know what he was up to (anyway, even if he forgot to
+do cvs edit, his commits would still trigger notifications). The reason
+to use cvs edit is that it notifies watchers before you start to work on
+a file. The watchers can contact you if they think there may be a
+conflict, before you've wasted a lot of time.
+
+<p>CVS assumes that anyone who runs cvs edit on a file wants to be added to
+the file's watch list, at least temporarily, in case someone else starts
+to edit it. When qsmith ran cvs edit, he became a watcher of hello.c.
+Both he and jrandom would have received notification if a third party
+had run cvs edit on that file (or committed it).
+
+<p>However, CVS also assumes that the person editing the file only wants to
+be on its watch list while he or she is editing it. Such users are
+taken off the watch list when they're done editing. If they prefer to
+be permanent watchers of the file, they would have to run cvs watch add.
+CVS makes a default assumption that someone is done editing when he or
+she commits a file (until the next time, anyway).
+
+<p>Anyone who gets on a file's watch list solely by virtue of having run
+<code>cvs&nbsp;edit</code> on that file is known as a <dfn>temporary watcher</dfn>
+and is taken off the watch list as soon as she commits a change to the
+file. If she wants to edit it again, she has to rerun <code>cvs&nbsp;edit</code>.
+
+<p>CVS's assumption that the first commit ends the editing session is only
+a best guess, of course, because CVS doesn't know how many commits the
+person will need to finish their changes. The guess is probably
+accurate for <dfn>one-off</dfn> changes - changes where someone just needs
+to make one quick fix to a file and commit it. For more prolonged
+editing sessions involving several commits, users should add themselves
+permanently to the file's watch list:
+
+<pre>paste$ cvs watch add hello.c
+paste$ cvs edit hello.c
+paste$ emacs hello.c
+...
+paste$ cvs commit -m "print hello in Sanskrit"
+</pre>
+
+<p>Even after the commit, qsmith remains a watcher of hello.c because he
+ran watch add on it. (By the way, qsmith will not receive notification
+of his own edits; only other watchers will. CVS is smart enough not to
+notify you about actions that you took.)
+
+<p><hr>
+Node:<a name="Ending_An_Editing_Session">Ending An Editing Session</a>,
+Next:<a rel=next href="#Controlling_What_Actions_Are_Watched">Controlling What Actions Are Watched</a>,
+Previous:<a rel=previous href="#Using_Watches_In_Development">Using Watches In Development</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>Ending An Editing Session</h3>
+
+<p>If you don't want to commit but want to explicitly end an editing
+session, you can do so by running cvs unedit:
+
+<pre>paste$ cvs unedit hello.c
+</pre>
+
+<p>But beware! This does more than just notify all watchers that you're
+done editing - it also offers to revert any uncommitted changes that
+you've made to the file:
+
+<pre>paste$ cvs unedit hello.c
+hello.c has been modified; revert changes? y
+paste$
+</pre>
+
+<p>If you answer <code>y</code>, CVS undoes all your changes and notifies
+watchers that you're not editing the file anymore. If you answer
+<code>n</code>, CVS keeps your changes and also keeps you registered as an
+editor of the file (so no notification goes out - in fact, it's as if
+you never ran <code>cvs&nbsp;unedit</code> at all). The possibility of CVS
+undoing all of your changes at a single keystroke is a bit scary, but
+the rationale is easy to understand: If you declare to the world that
+you're ending an editing session, then any changes you haven't committed
+are probably changes you don't mean to keep. At least, that's the way
+CVS sees it. Needless to say, be careful!
+
+<p><hr>
+Node:<a name="Controlling_What_Actions_Are_Watched">Controlling What Actions Are Watched</a>,
+Next:<a rel=next href="#Finding_Out_Who_Is_Watching_What">Finding Out Who Is Watching What</a>,
+Previous:<a rel=previous href="#Ending_An_Editing_Session">Ending An Editing Session</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>Controlling What Actions Are Watched</h3>
+
+<p>By default, watchers are notified about three kinds of action: edits,
+commits, and unedits. However, if you only want to be notified about,
+say, commits, you can restrict notifications by adjusting your watch
+with the -a flag (a for action):
+
+<pre>floss$ cvs watch add -a commit hello.c
+</pre>
+
+<p>Or if you want to watch edits and commits but don't care about unedits,
+you could pass the -a flag twice:
+
+<pre>floss$ cvs watch add -a edit -a commit hello.c
+</pre>
+
+<p>Adding a watch with the -a flag will never cause any of your existing
+watches to be removed. If you were watching for all three kinds of
+actions on hello.c, running
+
+<pre>floss$ cvs watch add -a commit hello.c
+</pre>
+
+<p>has no effect - you'll still be a watcher for all three actions. To
+remove watches, you should run
+
+<pre>floss$ cvs watch remove hello.c
+</pre>
+
+<p>which is similar to add in that, by default, it removes your watches for
+all three actions. If you pass -a arguments, it removes only the
+watches you specify:
+
+<pre>floss$ cvs watch remove -a commit hello.c
+</pre>
+
+<p>This means that you want to stop receiving notifications about commits
+but continue to receive notifications about edits and unedits (assuming
+you were watching edits and unedits to begin with, that is).
+
+<p>There are two special actions you can pass to the -a flag: all or none.
+The former means all actions that are eligible for watching (edits,
+commits, and unedits, as of this writing), and the latter means none of
+these. Because CVS's default behavior, in the absence of -a, is to
+watch all actions, and because watching none is the same as removing
+yourself from the watch list entirely, it's hard to imagine a situation
+in which it would be useful to specify either of these two special
+actions. However, cvs edit also takes the -a option, and in this case,
+it can be useful to specify all or none. For example, someone working
+on a file very briefly may not want to receive any notifications about
+what other people do with the file. Thus, this command
+
+<pre>paste$ whoami
+qsmith
+paste$ cvs edit -a none README.txt
+</pre>
+
+<p>causes watchers of README.txt to be notified that qsmith is about to
+work on it, but qsmith would not be added as a temporary watcher of
+README.txt during his editing session (which he normally would have
+been), because he asked not to watch any actions.
+
+<p>Remember that you can only affect your own watches with the cvs watch
+command. You may stop watching a certain file yourself, but that won't
+change anyone else's watches.
+
+<p><hr>
+Node:<a name="Finding_Out_Who_Is_Watching_What">Finding Out Who Is Watching What</a>,
+Next:<a rel=next href="#Reminding_People_To_Use_Watches">Reminding People To Use Watches</a>,
+Previous:<a rel=previous href="#Controlling_What_Actions_Are_Watched">Controlling What Actions Are Watched</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>Finding Out Who Is Watching What</h3>
+
+<p>Sometimes you may want to know who's watching before you even run cvs
+edit or want to see who is editing what without adding yourself to any
+watch lists. Or you may have forgotten exactly what your own status is.
+After setting and unsetting a few watches and committing some files,
+it's easy to lose track of what you're watching and editing.
+
+<p>CVS provides two commands to show who's watching and who's editing files
+- cvs watchers and cvs editors:
+
+<pre>floss$ whoami
+jrandom
+floss$ cvs watch add hello.c
+floss$ cvs watchers hello.c
+hello.c jrandom edit unedit commit
+floss$ cvs watch remove -a unedit hello.c
+floss$ cvs watchers hello.c
+hello.c jrandom edit commit
+floss$ cvs watch add README.txt
+floss$ cvs watchers
+README.txt jrandom edit unedit commit
+hello.c jrandom edit commit
+floss$
+</pre>
+
+<p>Notice that the last cvs watchers command doesn't specify any files and,
+therefore, shows watchers for all files (all those that have watchers,
+that is).
+
+<p>All of the watch and edit commands have this behavior in common with
+other CVS commands. If you specify file names, they act on those files.
+If you specify directory names, they act on everything in that directory
+and its subdirectories. If you don't specify anything, they act on the
+current directory and everything underneath it, to as many levels of
+depth as are available. For example (continuing with the same session):
+
+<pre>floss$ cvs watch add a-subdir/whatever.c
+floss$ cvs watchers
+README.txt jrandom edit unedit commit
+hello.c jrandom edit commit
+a-subdir/whatever.c jrandom edit unedit commit
+floss$ cvs watch add
+floss$ cvs watchers
+README.txt jrandom edit unedit commit
+foo.gif jrandom edit unedit commit
+hello.c jrandom edit commit unedit
+a-subdir/whatever.c jrandom edit unedit commit
+a-subdir/subsubdir/fish.c jrandom edit unedit commit
+b-subdir/random.c jrandom edit unedit commit
+floss$
+</pre>
+
+<p>The last two commands made jrandom a watcher of every file in the
+project and then showed the watch list for every file in the project,
+respectively. The output of <code>cvs&nbsp;watchers</code> doesn't always line
+up perfectly in columns because it mixes tab stops with information of
+varying length, but the lines are consistently formatted:
+
+<pre>[FILENAME] [whitespace] WATCHER [whitespace] ACTIONS-BEING-WATCHED...
+</pre>
+
+<p>Now watch what happens when qsmith starts to edit one of the files:
+
+<pre>paste$ cvs edit hello.c
+paste$ cvs watchers
+README.txt jrandom edit unedit commit
+foo.gif jrandom edit unedit commit
+hello.c jrandom edit commit unedit
+ qsmith tedit tunedit tcommit
+a-subdir/whatever.c jrandom edit unedit commit
+a-subdir/subsubdir/fish.c jrandom edit unedit commit
+b-subdir/random.c jrandom edit unedit commit
+</pre>
+
+<p>The file hello.c has acquired another watcher: qsmith himself (note that
+the file name is not repeated but is left as white space at the
+beginning of the line - this would be important if you ever wanted to
+write a program that parses watchers output). Because he's editing
+hello.c, qsmith has a <dfn>temporary watch</dfn> on the file; it goes away as
+soon as he commits a new revision of hello.c. The prefix <code>t</code> in
+front of each of the actions indicates that these are temporary watches.
+If qsmith adds himself as a regular watcher of hello.c as well
+
+<pre>paste$ cvs watch add hello.c
+README.txt jrandom edit unedit commit
+foo.gif jrandom edit unedit commit
+hello.c jrandom edit commit unedit
+ qsmith tedit tunedit tcommit edit unedit commit
+a-subdir/whatever.c jrandom edit unedit commit
+a-subdir/subsubdir/fish.c jrandom edit unedit commit
+b-subdir/random.c jrandom edit unedit commit
+</pre>
+
+<p>he is listed as both a temporary watcher and a permanent watcher. You
+may think that the permanent watch status would simply override the
+temporary, so that the line would look like this:
+
+<pre> qsmith edit unedit commit
+</pre>
+
+<p>However, CVS can't just replace the temporary watches because it doesn't
+know in what order things happen. Will qsmith remove himself from the
+permanent watch list before ending his editing session, or will he
+finish the edits while still remaining a watcher? If the former, the
+edit/unedit/commit actions disappear while the tedit/tunedit/tcommit
+ones remain; if the latter, the reverse would happen.
+
+<p>Anyway, that side of the watch list is usually not of great concern.
+Most of the time, what you want to do is run
+
+<pre>floss$ cvs watchers
+</pre>
+
+<p>or
+
+<pre>floss$ cvs editors
+</pre>
+
+<p>from the top level of a project and see who's doing what. You don't
+really need to know the details of who cares about what actions: the
+important things are people and files.
+
+<p><hr>
+Node:<a name="Reminding_People_To_Use_Watches">Reminding People To Use Watches</a>,
+Next:<a rel=next href="#What_Watches_Look_Like_In_The_Repository">What Watches Look Like In The Repository</a>,
+Previous:<a rel=previous href="#Finding_Out_Who_Is_Watching_What">Finding Out Who Is Watching What</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>Reminding People To Use Watches</h3>
+
+<p>You've probably noticed that the watch features are utterly dependent on
+the cooperation of all the developers. If someone just starts editing a
+file without first running cvs edit, no one else will know about it
+until the changes get committed. Because cvs edit is an additional
+step, not part of the normal development routine, people can easily
+forget to do it.
+
+<p>Although CVS can't force someone to use cvs edit, it does have a
+mechanism for reminding people to do so - the watch on command:
+
+<pre>floss$ cvs -q co myproj
+U myproj/README.txt
+U myproj/foo.gif
+U myproj/hello.c
+U myproj/a-subdir/whatever.c
+U myproj/a-subdir/subsubdir/fish.c
+U myproj/b-subdir/random.c
+floss$ cd myproj
+floss$ cvs watch on hello.c
+floss$
+</pre>
+
+<p>By running cvs watch on hello.c, jrandom causes future checkouts of
+myproj to create hello.c read-only in the working copy. When qsmith
+tries to work on it, he'll discover that it's read-only and be reminded
+to run cvs edit first:
+
+<pre>paste$ cvs -q co myproj
+U myproj/README.txt
+U myproj/foo.gif
+U myproj/hello.c
+U myproj/a-subdir/whatever.c
+U myproj/a-subdir/subsubdir/fish.c
+U myproj/b-subdir/random.c
+paste$ cd myproj
+paste$ ls -l
+total 6
+drwxr-xr-x 2 qsmith users 1024 Jul 19 01:06 CVS/
+-rw-r--r-- 1 qsmith users 38 Jul 12 11:28 README.txt
+drwxr-xr-x 4 qsmith users 1024 Jul 19 01:06 a-subdir/
+drwxr-xr-x 3 qsmith users 1024 Jul 19 01:06 b-subdir/
+-rw-r--r-- 1 qsmith users 673 Jun 20 22:47 foo.gif
+-r--r--r-- 1 qsmith users 188 Jul 18 01:20 hello.c
+paste$
+</pre>
+
+<p>When he does so, the file becomes read-write. He can then edit it, and
+when he commits, it becomes read-only again:
+
+<pre>paste$ cvs edit hello.c
+paste$ ls -l hello.c
+-rw-r--r-- 1 qsmith users 188 Jul 18 01:20 hello.c
+paste$ emacs hello.c
+ ...
+paste$ cvs commit -m "say hello in Aramaic" hello.c
+Checking in hello.c;
+/usr/local/newrepos/myproj/hello.c,v &lt;-- hello.c
+new revision: 1.12; previous revision: 1.11
+done
+paste$ ls -l hello.c
+-r--r--r-- 1 qsmith users 210 Jul 19 01:12 hello.c
+paste$
+</pre>
+
+<p>His edit and commit will send notification to all watchers of hello.c.
+Note that jrandom isn't necessarily one of them. By running cvs watch
+on hello.c, jrandom did not add herself to the watch list for that file;
+she merely specified that it should be checked out read-only. People
+who want to watch a file must remember to add themselves to its watch
+list - CVS cannot help them with that.
+
+<p>Turning on watches for a single file may be the exception. Generally,
+it's more common to turn on watches project-wide:
+
+<pre>floss$ cvs -q co myproj
+U myproj/README.txt
+U myproj/foo.gif
+U myproj/hello.c
+U myproj/a-subdir/whatever.c
+U myproj/a-subdir/subsubdir/fish.c
+U myproj/b-subdir/random.c
+floss$ cd myproj
+floss$ cvs watch on
+floss$
+</pre>
+
+<p>This action amounts to announcing a policy decision for the entire
+project: "Please use cvs edit to tell watchers what you're working on,
+and feel free to watch any file you're interested in or responsible
+for." Every file in the project will be checked out read-only, and thus
+people will be reminded that they're expected to use cvs edit before
+working on anything.
+
+<p>Curiously, although checkouts of watched files make them read-only,
+updates do not. If qsmith had checked out his working copy before
+jrandom ran cvs watch on, his files would have stayed read-write,
+remaining so even after updates. However, any file he commits after
+jrandom turns watching on will become read-only. If jrandom turns off
+watches
+
+<pre>floss$ cvs watch off
+</pre>
+
+<p>qsmith's read-only files do not magically become read-write. On the
+other hand, after he commits one, it will not revert to read-only again
+(as it would have if watches were still on).
+
+<p>It's worth noting that qsmith could, were he truly devious, make files
+in his working copy writeable by using the standard Unix <code>chmod</code>
+command, bypassing <code>cvs&nbsp;edit</code> entirely
+
+<pre>paste$ chmod u+w hello.c
+</pre>
+
+<p>or if he wanted to get everything in one fell swoop:
+
+<pre>paste$ chmod -R u+w .
+</pre>
+
+<p>There is nothing CVS can do about this. Working copies by their nature
+are private sandboxes - the watch features can open them up to public
+scrutiny a little bit, but only as far as the developer permits. Only
+when a developer does something that affects the repository (such as
+commits) is her privacy unconditionally lost.
+
+<p>The relationship among watch add, watch remove, watch on, and watch off
+probably seems a bit confusing. It may help to summarize the overall
+scheme: <code>add</code> and <code>remove</code> are about adding or removing users
+from a file's watch list; they don't have anything to do with whether
+files are read-only on checkout or after commits. <code>on</code> and
+<code>off</code> are only about file permissions. They don't have anything to
+do with who is on a file's watch list; rather, they are tools to help
+remind developers of the watch policy by causing working-copy files to
+become read-only.
+
+<p>All of this may seem a little inconsistent. In a sense, using watches
+works against the grain of CVS. It deviates from the idealized universe
+of multiple developers editing freely in their working copies, hidden
+from each other until they choose to commit. With watches, CVS gives
+developers convenient shortcuts for informing each other of what's going
+on in their working copies; however, it has no way to enforce
+observation policies, nor does it have a definitive concept of what
+constitutes an editing session. Nevertheless, watches can be helpful in
+certain circumstances if developers work with them.
+
+<p><hr>
+Node:<a name="What_Watches_Look_Like_In_The_Repository">What Watches Look Like In The Repository</a>,
+Previous:<a rel=previous href="#Reminding_People_To_Use_Watches">Reminding People To Use Watches</a>,
+Up:<a rel=up href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>
+<br>
+
+<h3>What Watches Look Like In The Repository</h3>
+
+<p>In the interests of stamping out black boxes and needless mystery, let's
+take a quick look at how watches are implemented in the repository.
+We'll only take a quick look, though, because it's not pretty.
+
+<p>When you set a watch
+
+<pre>floss$ pwd
+/home/jrandom/myproj
+floss$ cvs watch add hello.c
+floss$ cvs watchers
+hello.c jrandom edit unedit commit
+floss$
+</pre>
+
+<p>CVS records it in the special file, <code>CVS/fileattr</code>, in the
+appropriate repository subdirectory:
+
+<pre>floss$ cd /usr/local/newrepos
+floss$ ls
+CVSROOT/ myproj/
+floss$ cd myproj
+floss$ ls
+CVS/ a-subdir/ foo.gif,v
+README.txt,v b-subdir/ hello.c,v
+floss$ cd CVS
+floss$ ls
+fileattr
+floss$ cat fileattr
+Fhello.c _watchers=jrandom&gt;edit+unedit+commit
+floss$
+</pre>
+
+<p>The fact that fileattr is stored in a CVS subdirectory in the repository
+does not mean that the repository has become a working copy. It's
+simply that the name <code>CVS</code> was already reserved for bookkeeping in
+the working copy, so CVS can be sure no project will ever need a
+subdirectory of that name in the repository.
+
+<p>I won't describe the format of <code>fileattr</code> formally; you can
+probably grok it pretty well just by watching it change from command to
+command:
+
+<pre>floss$ cvs watch add hello.c
+floss$ cat /usr/local/newrepos/myproj/CVS/fileattr
+Fhello.c _watchers=jrandom&gt;edit+unedit+commit
+floss$ cvs watch add README.txt
+floss$ cat /usr/local/newrepos/myproj/CVS/fileattr
+Fhello.c _watchers=jrandom&gt;edit+unedit+commit
+FREADME.txt _watchers=jrandom&gt;edit+unedit+commit
+floss$ cvs watch on hello.c
+floss$ cat /usr/local/newrepos/myproj/CVS/fileattr
+Fhello.c _watchers=jrandom&gt;edit+unedit+commit;_watched=
+FREADME.txt _watchers=jrandom&gt;edit+unedit+commit
+floss$ cvs watch remove hello.c
+floss$ cat /usr/local/newrepos/myproj/CVS/fileattr
+Fhello.c _watched=
+FREADME.txt _watchers=jrandom&gt;edit+unedit+commit
+floss$ cvs watch off hello.c
+floss$ cat /usr/local/newrepos/myproj/CVS/fileattr
+FREADME.txt _watchers=jrandom&gt;edit+unedit+commit
+floss$
+</pre>
+
+<p>Edit records are stored in fileattr, too. Here's what happens when
+qsmith adds himself as an editor:
+
+<pre>paste$ cvs edit hello.c
+
+floss$ cat /usr/local/newrepos/myproj/CVS/fileattr
+Fhello.c _watched=;_editors=qsmith&gt;Tue Jul 20 04:53:23 1999 GMT+floss\
++/home/qsmith/myproj;_watchers=qsmith&gt;tedit+tunedit+tcommit
+FREADME.txt _watchers=jrandom&gt;edit+unedit+commit
+</pre>
+
+<p>Finally, note that CVS removes fileattr and the CVS subdirectory when
+there are no more watchers or editors for any of the files in that
+directory:
+
+<pre>paste$ cvs unedit
+
+floss$ cvs watch off
+floss$ cvs watch remove
+floss$ cat /usr/local/newrepos/myproj/CVS/fileattr
+cat: /usr/local/newrepos/myproj/CVS/fileattr: No such file or directory
+floss$
+</pre>
+
+<p>It should be clear after this brief exposure that the details of parsing
+fileattr format are better left to CVS. The main reason to have a basic
+understanding of the format - aside from the inherent satisfaction of
+knowing what's going on behind the curtain - is if you try to write an
+extension to the CVS watch features or debug some problem in them. It's
+sufficient to know that you shouldn't be alarmed if you see CVS/
+subdirectories popping up in your repository. They're the only safe
+place CVS has to store meta-information such as watch lists.
+
+<p><hr>
+Node:<a name="Log_Messages_And_Commit_Emails">Log Messages And Commit Emails</a>,
+Next:<a rel=next href="#Changing_A_Log_Message_After_Commit">Changing A Log Message After Commit</a>,
+Previous:<a rel=previous href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Log Messages And Commit Emails</h2>
+
+<p>Commit emails are notices sent out at commit time, showing the log
+message and files involved in the commit. They usually go to all
+project participants and sometimes to other interested parties. The
+details of setting up commit emails were covered in <a href="#Repository_Administration">Repository Administration</a>, so I won't repeat them here. I have noticed, however,
+that commit emails can sometimes result in unexpected side effects to
+projects, effects that you may want to take into account if you set up
+commit emails for your project.
+
+<p>First, be prepared for the messages to be mostly ignored. Whether
+people read them depends, at least partly, on the frequency of commits
+in your project. Do developers tend to commit one big change at the end
+of the day, or many small changes throughout the day? The closer your
+project is to the latter, the thicker the barrage of tiny commit notices
+raining down on the developers all day long, and the less inclined they
+will be to pay attention to each message.
+
+<p>This doesn't mean the notices aren't useful, just that you shouldn't
+count on every person reading every message. It's still a convenient
+way for people to keep tabs on who's doing what (without the
+intrusiveness of watches). When the emails go to a publicly
+subscribable mailing list, they are a wonderful mechanism for giving
+interested users (and future developers!) a chance to see what happens
+in the code on a daily basis.
+
+<p>You may want to consider having a designated developer who watches all
+log messages and has an overview of activity across the entire project
+(of course, a good project leader will probably be doing this anyway).
+If there are clear divisions of responsibility - say, certain
+developers are "in charge of" certain subdirectories of the project -
+you could do some fancy scripting in CVSROOT/loginfo to see that each
+responsible party receives specially marked notices of changes made in
+their area. This will help ensure that the developers will at least
+read the email that pertains to their subdirectories.
+
+<p>A more interesting side effect happens when commit emails aren't
+ignored. People start to use them as a realtime communications method.
+Here's the kind of log message that can result:
+
+<pre>Finished feedback form; fixed the fonts and background colors on the
+home page. Whew! Anyone want to go to Mon Lung for lunch?
+</pre>
+
+<p>There's nothing wrong with this, and it makes the logs more fun to read
+over later. However, people need to be aware that log messages, such as
+the following, are not only distributed by email but is also preserved
+forever in the project's history. For example, griping about customer
+specifications is a frequent pastime among programmers; it's not hard to
+imagine someone committing a log message like this one, knowing that the
+other programmers will soon see it in their email:
+
+<pre>Truncate four-digit years to two-digits in input. What the customer
+wants, the customer gets, no matter how silly &amp; wrong. Sigh.
+</pre>
+
+<p>This makes for an amusing email, but what happens if the customer
+reviews the logs someday? (I'll bet similar concerns have led more than
+one site to set up CVSROOT/loginfo so that it invokes scripts to guard
+against offensive words in log messages!)
+
+<p>The overall effect of commit emails seems to be that people become less
+willing to write short or obscure log messages, which is probably a good
+thing. However, they may need to be reminded that their audience is
+anyone who might ever read the logs, not just the people receiving
+commit emails.
+
+<p><hr>
+Node:<a name="Changing_A_Log_Message_After_Commit">Changing A Log Message After Commit</a>,
+Next:<a rel=next href="#Getting_Rid_Of_A_Working_Copy">Getting Rid Of A Working Copy</a>,
+Previous:<a rel=previous href="#Log_Messages_And_Commit_Emails">Log Messages And Commit Emails</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Changing A Log Message After Commit</h2>
+
+<p>Just in case someone does commit a regrettable log message, CVS enables
+you to rewrite logs after they've been committed. It's done with the -m
+option to the admin command (this command is covered in more detail
+later in this chapter) and allows you to change one log message (per
+revision, per file) at a time. Here's how it works:
+
+<pre>floss$ cvs admin -m 1.7:"Truncate four-digit years to two in input." date.c
+RCS file: /usr/local/newrepos/someproj/date.c,v
+done
+floss$
+</pre>
+
+<p>The original, offensive log message that was committed with revision 1.7
+has been replaced with a perfectly innocent - albeit duller - message.
+Don't forget the colon separating the revision number from the new log
+message.
+
+<p>If the new log message consists of multiple lines, put it in a file and
+do this:
+
+<pre>floss$ cvs admin -m 1.7:"`cat new-log-message.txt`" date.c
+</pre>
+
+<p>(This example was sent in by Peter Ross &lt;peter.ross@miscrit.be&gt;; note
+that it only works for Unix users.)
+
+<p>If the bad message was committed into multiple files, you'll have to run
+cvs admin separately for each one, because the revision number is
+different for each file. Therefore, this is one of the few commands in
+CVS that requires you to pass a single file name as argument:
+
+<pre>floss$ cvs admin -m 1.2:"very boring log message" hello.c README.txt foo.gif
+cvs admin: while processing more than one file:
+cvs [admin aborted]: attempt to specify a numeric revision
+floss$
+</pre>
+
+<p>Confusingly, you get the same error if you pass no file names (because
+CVS then assumes all the files in the current directory and below are
+implied arguments):
+
+<pre>floss$ cvs admin -m 1.2:"very boring log message"
+cvs admin: while processing more than one file:
+cvs [admin aborted]: attempt to specify a numeric revision
+floss$
+</pre>
+
+<p>(As is unfortunately often the case with CVS error messages, you have to
+see things from CVS's point of view before the message makes sense!)
+
+<p>Invoking <code>admin&nbsp;-m</code> actually changes the project's history, so
+use it with care. There will be no record that the log message was ever
+changed - it will simply appear as if that revision had been originally
+committed with the new log message. No trace of the old message will be
+left anywhere (unless you saved the original commit email).
+
+<p>Although its name might seem to imply that only the designated CVS
+administrator can use it, in fact anyone can run <code>cvs&nbsp;admin</code>,
+as long as they have write access to the project in question.
+Nevertheless, it is best used with caution; the ability to change log
+messages is mild compared with other potentially damaging things it can
+do. See <a href="#CVS_Reference">CVS Reference</a> for more about <code>admin</code>, as well as a
+way to restrict its use.
+
+<p><hr>
+Node:<a name="Getting_Rid_Of_A_Working_Copy">Getting Rid Of A Working Copy</a>,
+Next:<a rel=next href="#History_--_A_Summary_Of_Repository_Activity">History -- A Summary Of Repository Activity</a>,
+Previous:<a rel=previous href="#Changing_A_Log_Message_After_Commit">Changing A Log Message After Commit</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Getting Rid Of A Working Copy</h2>
+
+<p>In typical CVS usage, the way to get rid of a working copy directory
+tree is to remove it like any other directory tree:
+
+<pre>paste$ rm -rf myproj
+</pre>
+
+<p>However, if you eliminate your working copy this way, other developers
+will not know that you have stopped using it. CVS provides a command to
+relinquish a working copy explicitly. Think of release as the opposite
+of checkout - you're telling the repository that you're done with the
+working copy now. Like checkout, release is invoked from the parent
+directory of the tree:
+
+<pre>paste$ pwd
+/home/qsmith/myproj
+paste$ cd ..
+paste$ ls
+myproj
+paste$ cvs release myproj
+You have [0] altered files in this repository.
+Are you sure you want to release directory 'myproj': y
+paste$
+</pre>
+
+<p>If there are any uncommitted changes in the repository, the release
+fails, meaning that it just lists the modified files and otherwise has
+no effect. Assuming the tree is clean (totally up to date), release
+records in the repository that the working copy has been released.
+
+<p>You can also have release automatically delete the working tree for you,
+by passing the -d flag:
+
+<pre>paste$ ls
+myproj
+paste$ cvs release -d myproj
+You have [0] altered files in this repository.
+Are you sure you want to release (and delete) directory 'myproj: y
+paste$ ls
+paste$
+</pre>
+
+<p>As of CVS version 1.10.6, the release command is not able to deduce the
+repository's location by examining the working copy (this is because
+release is invoked from above the working copy, not within it). You
+must pass the <code>-d&nbsp;&lt;REPOS&gt;</code> global option or make sure that your
+CVSROOT environment variable is set correctly. (This bug may be fixed
+in future versions of CVS.)
+
+<p>The Cederqvist claims that if you use release instead of just deleting
+the working tree, people with watches set on the released files will be
+notified just as if you had run <code>unedit</code>. However, I tried to
+verify this experimentally, and it does not seem to be true.
+
+<p><hr>
+Node:<a name="History_--_A_Summary_Of_Repository_Activity">History -- A Summary Of Repository Activity</a>,
+Next:<a rel=next href="#Annotations_--_A_Detailed_View_Of_Project_Activity">Annotations -- A Detailed View Of Project Activity</a>,
+Previous:<a rel=previous href="#Getting_Rid_Of_A_Working_Copy">Getting Rid Of A Working Copy</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>History - A Summary Of Repository Activity</h2>
+
+<p>In <a href="#Repository_Administration">Repository Administration</a>, I briefly mentioned the cvs history
+command. This command displays a summary of all checkouts, commits,
+updates, rtags, and releases done in the repository (at least, since
+logging was enabled by the creation of the CVSROOT/history file in the
+repository). You can control the format and contents of the summary
+with various options.
+
+<p>The first step is to make sure that logging is enabled in your
+repository. The repository administrator should first make sure there
+is a history file
+
+<pre>floss$ cd /usr/local/newrepos/CVSROOT
+floss$ ls -l history
+ls: history: No such file or directory
+floss$
+</pre>
+
+<p>and if there isn't one, create it, as follows:
+
+<pre>floss$ touch history
+floss$ ls -l history
+-rw-r--r-- 1 jrandom cvs 0 Jul 22 14:57 history
+floss$
+</pre>
+
+<p>This history file also needs to be writeable by everyone who uses the
+repository, otherwise they'll get an error every time they try to run a
+CVS command that modifies that file. The easiest way is simply to make
+the file world-writeable:
+
+<pre>floss$ chmod a+rw history
+floss$ ls -l history
+-rw-rw-rw- 1 jrandom cvs 0 Jul 22 14:57 history
+floss$
+</pre>
+
+<p>If the repository was created with the <code>cvs&nbsp;init</code> command, the
+history file already exists. You may still have to fix its permissions,
+however.
+
+<p>The rest of these examples assume that history logging has been enabled
+for a while, so that data has had time to accumulate in the history
+file.
+
+<p>The output of cvs history is somewhat terse (it's probably intended to
+be parsed by programs rather than humans, although it is readable with a
+little study). Let's run it once and see what we get:
+
+<pre>paste$ pwd
+/home/qsmith/myproj
+paste$ cvs history -e -a
+O 07/25 15:14 +0000 qsmith myproj =mp= ~/*
+M 07/25 15:16 +0000 qsmith 1.14 hello.c myproj == ~/mp
+U 07/25 15:21 +0000 qsmith 1.14 README.txt myproj == ~/mp
+G 07/25 15:21 +0000 qsmith 1.15 hello.c myproj == ~/mp
+A 07/25 15:22 +0000 qsmith 1.1 goodbye.c myproj == ~/mp
+M 07/25 15:23 +0000 qsmith 1.16 hello.c myproj == ~/mp
+M 07/25 15:26 +0000 qsmith 1.17 hello.c myproj == ~/mp
+U 07/25 15:29 +0000 qsmith 1.2 goodbye.c myproj == ~/mp
+G 07/25 15:29 +0000 qsmith 1.18 hello.c myproj == ~/mp
+M 07/25 15:30 +0000 qsmith 1.19 hello.c myproj == ~/mp
+O 07/23 03:45 +0000 jrandom myproj =myproj= ~/src/*
+F 07/23 03:48 +0000 jrandom =myproj= ~/src/*
+F 07/23 04:06 +0000 jrandom =myproj= ~/src/*
+M 07/25 15:12 +0000 jrandom 1.13 README.txt myproj == ~/src/myproj
+U 07/25 15:17 +0000 jrandom 1.14 hello.c myproj == ~/src/myproj
+M 07/25 15:18 +0000 jrandom 1.14 README.txt myproj == ~/src/myproj
+M 07/25 15:18 +0000 jrandom 1.15 hello.c myproj == ~/src/myproj
+U 07/25 15:23 +0000 jrandom 1.1 goodbye.c myproj == ~/src/myproj
+U 07/25 15:23 +0000 jrandom 1.16 hello.c myproj == ~/src/myproj
+U 07/25 15:26 +0000 jrandom 1.1 goodbye.c myproj == ~/src/myproj
+G 07/25 15:26 +0000 jrandom 1.17 hello.c myproj == ~/src/myproj
+M 07/25 15:27 +0000 jrandom 1.18 hello.c myproj == ~/src/myproj
+C 07/25 15:30 +0000 jrandom 1.19 hello.c myproj == ~/src/myproj
+M 07/25 15:31 +0000 jrandom 1.20 hello.c myproj == ~/src/myproj
+M 07/25 16:29 +0000 jrandom 1.3 whatever.c myproj/a-subdir == ~/src/myproj
+paste$
+</pre>
+
+<p>There, isn't that clear?
+
+<p>Before we examine the output, notice that the invocation included two
+options: -e and -a. When you run history, you almost always want to
+pass options telling it what data to report and how to report it. In
+this respect, it differs from most other CVS commands, which usually do
+something useful when invoked without any options. In this example, the
+two flags meant "everything" (show every kind of event that happened)
+and "all" (for all users), respectively.
+
+<p>Another way that history differs from other commands is that, although
+it is usually invoked from within a working copy, it does not restrict
+its output to that working copy's project. Instead, it shows all
+history events from all projects in the repository - the working copy
+merely serves to tell CVS from which repository to retrieve the history
+data. (In the preceding example, the only history data in that
+repository is for the <code>myproj</code> project, so that's all we see.)
+
+<p>The general format of the output is:
+
+<pre>CODE DATE USER [REVISION] [FILE] PATH_IN_REPOSITORY ACTUAL_WORKING_COPY_NAME
+</pre>
+
+<p>The code letters refer to various CVS operations, as shown in Table 6.1.
+
+<p>For operations (such as checkout) that are about the project as a whole
+rather than about individual files, the revision and file are omitted,
+and the repository path is placed between the equal signs.
+
+<p>Although the output of the history command was designed to be compact,
+parseable input for other programs, CVS still gives you a lot of control
+over its scope and content. The options shown in Table 6.2 control what
+types of events get reported.
+
+<pre>Table 6.1 The meaning of the code letters.
+
+Letter Meaning
+====== =========================================================
+O Checkout
+T Tag
+F Release
+W Update (no user file, remove from entries file)
+U Update (file overwrote unmodified user file)
+G Update (file was merged successfully into modified user file)
+C Update (file was merged, but conflicts w/ modified user file)
+M Commit (from modified file)
+A Commit (an added file)
+R Commit (the removal of a file)
+E Export
+</pre>
+
+<pre>Table 6.2 Options to filter by event type.
+
+Option Meaning
+========== =========================================================
+-m MODULE Show historical events affecting MODULE.
+-c Show commit events.
+-o Show checkout events.
+-T Show tag events.
+-x CODE(S) Show all events of type CODE (one or more of OTFWUGCMARE).
+-e Show all types of events, period. Once you have
+ selected what type of events you want reported, you can
+ filter further with the options shown in Table 6.3.
+</pre>
+
+<pre>Table 6.3 Options to filter by user.
+
+Option Meaning
+========== =========================================================
+-a Show actions taken by all users
+-w Show only actions taken from within this working copy
+-l Show only the last time this user took the action
+-u USER Show records for USER
+</pre>
+
+<p><hr>
+Node:<a name="Annotations_--_A_Detailed_View_Of_Project_Activity">Annotations -- A Detailed View Of Project Activity</a>,
+Next:<a rel=next href="#Annotations_And_Branches">Annotations And Branches</a>,
+Previous:<a rel=previous href="#History_--_A_Summary_Of_Repository_Activity">History -- A Summary Of Repository Activity</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Annotations - A Detailed View Of Project Activity</h2>
+
+<h2>The annotate Command</h2>
+
+<p>If the history command gives an overview of project activity, the
+<dfn>annotate</dfn> command is a way of attaching a zoom lens to the view.
+With <code>annotate</code>, you can see who was the last person to touch each
+line of a file, and at what revision they touched it:
+
+<pre>floss$ cvs annotate
+Annotations for README.txt
+***************
+1.14 (jrandom 25-Jul-99): blah
+1.13 (jrandom 25-Jul-99): test 3 for history
+1.12 (qsmith 19-Jul-99): test 2
+1.11 (qsmith 19-Jul-99): test
+1.10 (jrandom 12-Jul-99): blah
+1.1 (jrandom 20-Jun-99): Just a test project.
+1.4 (jrandom 21-Jun-99): yeah.
+1.5 (jrandom 21-Jun-99): nope.
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.15 (jrandom 25-Jul-99): /* another test for history */
+1.13 (qsmith 19-Jul-99): /* random change number two */
+1.10 (jrandom 12-Jul-99): /* test */
+1.21 (jrandom 25-Jul-99): printf ("Hellooo, world!\n");
+1.3 (jrandom 21-Jun-99): printf ("hmmm\n");
+1.4 (jrandom 21-Jun-99): printf ("double hmmm\n");
+1.11 (qsmith 18-Jul-99): /* added this comment */
+1.16 (qsmith 25-Jul-99): /* will merge these changes */
+1.18 (jrandom 25-Jul-99): /* will merge these changes too */
+1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n");
+1.1 (jrandom 20-Jun-99): }
+Annotations for a-subdir/whatever.c
+***************
+1.3 (jrandom 25-Jul-99): /* A completely non-empty C file. */
+Annotations for a-subdir/subsubdir/fish.c
+***************
+1.2 (jrandom 25-Jul-99): /* An almost completely empty C file. */
+Annotations for b-subdir/random.c
+***************
+1.1 (jrandom 20-Jun-99): /* A completely empty C file. */
+floss$
+</pre>
+
+<p>The output of annotate is pretty intuitive. On the left are the
+revision number, developer, and date on which the line in question was
+added or last modified. On the right is the line itself, as of the
+current revision. Because every line is annotated, you can actually see
+the entire contents of the file, pushed over to the right by the
+annotation information.
+
+<p>If you specify a revision number or tag, the annotations are given as of
+that revision, meaning that it shows the most recent modification to
+each line at or before that revision. This is probably the most common
+way to use annotations - examining a particular revision of a single
+file to determine which developers were active in which parts of the
+file.
+
+<p>For example, in the output of the previous example, you can see that the
+most recent revision of hello.c is 1.21, in which jrandom did something
+to the line:
+
+<pre>printf ("Hellooo, world!\n");
+</pre>
+
+<p>One way to find out what she did is to diff that revision against the
+previous one:
+
+<pre>floss$ cvs diff -r 1.20 -r 1.21 hello.c
+Index: hello.c
+===================================================================
+RCS file: /usr/local/newrepos/myproj/hello.c,v
+retrieving revision 1.20
+retrieving revision 1.21
+diff -r1.20 -r1.21
+9c9
+&lt; printf ("Hello, world!\n");
+--
+&gt; printf ("Hellooo, world!\n");
+floss$
+</pre>
+
+<p>Another way to find out, while still retaining a file-wide view of
+everyone's activity, is to compare the current annotations with the
+annotations from a previous revision:
+
+<pre>floss$ cvs annotate -r 1.20 hello.c
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.15 (jrandom 25-Jul-99): /* another test for history */
+1.13 (qsmith 19-Jul-99): /* random change number two */
+1.10 (jrandom 12-Jul-99): /* test */
+1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n");
+1.3 (jrandom 21-Jun-99): printf ("hmmm\n");
+1.4 (jrandom 21-Jun-99): printf ("double hmmm\n");
+1.11 (qsmith 18-Jul-99): /* added this comment */
+1.16 (qsmith 25-Jul-99): /* will merge these changes */
+1.18 (jrandom 25-Jul-99): /* will merge these changes too */
+1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n");
+1.1 (jrandom 20-Jun-99): }
+floss$
+</pre>
+
+<p>Although the diff reveals the textual facts of the change more
+concisely, the annotation may be preferable because it places them in
+their historical context by showing how long the previous incarnation of
+the line had been present (in this case, all the way since revision
+1.1). That knowledge can help you decide whether to look at the logs to
+find out the motivation for the change:
+
+<pre>floss$ cvs log -r 1.21 hello.c
+RCS file: /usr/local/newrepos/myproj/hello.c,v
+Working file: hello.c
+head: 1.21
+branch:
+locks: strict
+access list:
+symbolic names:
+ random-tag: 1.20
+ start: 1.1.1.1
+ jrandom: 1.1.1
+keyword substitution: kv
+total revisions: 22; selected revisions: 1
+description:
+----------------------------
+revision 1.21
+date: 1999/07/25 20:17:42; author: jrandom; state: Exp; lines: +1 -1
+say hello with renewed enthusiasm
+============================================================================
+floss$
+</pre>
+
+<p>In addition to -r, you can also filter annotations using the -D DATE
+option:
+
+<pre>floss$ cvs annotate -D "5 weeks ago" hello.c
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n");
+1.1 (jrandom 20-Jun-99): }
+floss$ cvs annotate -D "3 weeks ago" hello.c
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n");
+1.3 (jrandom 21-Jun-99): printf ("hmmm\n");
+1.4 (jrandom 21-Jun-99): printf ("double hmmm\n");
+1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n");
+1.1 (jrandom 20-Jun-99): }
+floss$
+</pre>
+
+<p><hr>
+Node:<a name="Annotations_And_Branches">Annotations And Branches</a>,
+Next:<a rel=next href="#Using_Keyword_Expansion">Using Keyword Expansion</a>,
+Previous:<a rel=previous href="#Annotations_--_A_Detailed_View_Of_Project_Activity">Annotations -- A Detailed View Of Project Activity</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Annotations And Branches</h2>
+
+<p>By default, annotation always shows activity on the main trunk of
+development. Even when invoked from a branch working copy, it shows
+annotations for the trunk unless you specify otherwise. (This tendency
+to favor the trunk is either a bug or a feature, depending on your point
+of view.) You can force CVS to annotate a branch by passing the branch
+tag as an argument to -r. Here is an example from a working copy in
+which hello.c is on a branch named <code>Brancho_Gratuito</code>, with at
+least one change committed on that branch:
+
+<pre>floss$ cvs status hello.c
+===================================================================
+File: hello.c Status: Up-to-date
+
+ Working revision: 1.10.2.2 Sun Jul 25 21:29:05 1999
+ Repository revision: 1.10.2.2 /usr/local/newrepos/myproj/hello.c,v
+ Sticky Tag: Brancho_Gratuito (branch: 1.10.2)
+ Sticky Date: (none)
+ Sticky Options: (none)
+
+floss$ cvs annotate hello.c
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.10 (jrandom 12-Jul-99): /* test */
+1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n");
+1.3 (jrandom 21-Jun-99): printf ("hmmm\n");
+1.4 (jrandom 21-Jun-99): printf ("double hmmm\n");
+1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n");
+1.1 (jrandom 20-Jun-99): }
+floss$ cvs annotate -r Brancho_Gratuito hello.c
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.10 (jrandom 12-Jul-99): /* test */
+1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n");
+1.10.2.2 (jrandom 25-Jul-99): printf ("hmmmmm\n");
+1.4 (jrandom 21-Jun-99): printf ("double hmmm\n");
+1.10.2.1 (jrandom 25-Jul-99): printf ("added this line");
+1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n");
+1.1 (jrandom 20-Jun-99): }
+floss$
+</pre>
+
+<p>You can also pass the branch number itself:
+
+<pre>floss$ cvs annotate -r 1.10.2 hello.c
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.10 (jrandom 12-Jul-99): /* test */
+1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n");
+1.10.2.2 (jrandom 25-Jul-99): printf ("hmmmmm\n");
+1.4 (jrandom 21-Jun-99): printf ("double hmmm\n");
+1.10.2.1 (jrandom 25-Jul-99): printf ("added this line");
+1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n");
+1.1 (jrandom 20-Jun-99): }
+floss$
+</pre>
+
+<p>or a full revision number from the branch:
+
+<pre>floss$ cvs annotate -r 1.10.2.1 hello.c
+Annotations for hello.c
+***************
+1.1 (jrandom 20-Jun-99): #include &lt;stdio.h&gt;
+1.1 (jrandom 20-Jun-99):
+1.1 (jrandom 20-Jun-99): void
+1.1 (jrandom 20-Jun-99): main ()
+1.1 (jrandom 20-Jun-99): {
+1.10 (jrandom 12-Jul-99): /* test */
+1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n");
+1.3 (jrandom 21-Jun-99): printf ("hmmm\n");
+1.4 (jrandom 21-Jun-99): printf ("double hmmm\n");
+1.10.2.1 (jrandom 25-Jul-99): printf ("added this line");
+1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n");
+1.1 (jrandom 20-Jun-99): }
+floss$
+</pre>
+
+<p>If you do this, remember that the numbers are only valid for that
+particular file. In general, it's probably better to use the branch
+name wherever possible.
+
+<p><hr>
+Node:<a name="Using_Keyword_Expansion">Using Keyword Expansion</a>,
+Next:<a rel=next href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>,
+Previous:<a rel=previous href="#Annotations_And_Branches">Annotations And Branches</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Using Keyword Expansion</h2>
+
+<p>You may recall a brief mention of <code>keyword expansion</code> in <a href="#An_Overview_of_CVS">An Overview of CVS</a>. RCS keywords are special words, surrounded by dollar
+signs, that CVS looks for in text files and expands into
+revision-control information. For example, if a file contains
+
+<pre>$Author$
+</pre>
+
+<p>then when updating the file to a given revision, CVS will expand it to
+the username of the person who committed that revision:
+
+<pre>$Author$
+</pre>
+
+<p>CVS is also sensitive to keywords in their expanded form, so that once
+expanded, they continue to be updated as appropriate.
+
+<p>Although keywords don't actually offer any information that's not
+available by other means, they give people a convenient way to see
+revision control facts embedded in the text of the file itself, rather
+than by invoking some arcane CVS operation.
+
+<p>Here are a few other commonly used keywords:
+
+<pre>$Date$ ==&gt; date of last commit, expands to ==&gt;
+$Date$
+
+$Id$ ==&gt; filename, revision, date, and author; expands to ==&gt;
+$Id$
+
+$Revision$ ==&gt; exactly what you think it is, expands to ==&gt;
+$Revision$
+
+$Source$ ==&gt; path to corresponding repository file, expands to ==&gt;
+$Source$
+
+$Log$
+Revision 1.1 2002/06/23 14:32:50 llornkcor
+some dev docs
+ ==&gt; accumulating log messages for the file, expands to ==&gt;
+$Log$
+Revision 1.1 2002/06/23 14:32:50 llornkcor
+some dev docs
+
+Revision 1.2 1999/07/26 06:47:52 jrandom
+...and this is the second log message.
+
+Revision 1.1 1999/07/26 06:39:46 jrandom
+This is the first log message...
+</pre>
+
+<p>The $Log$
+<p>The Revision 1.1 2002/06/23 14:32:50 llornkcor
+<p>The some dev docs
+<p>The keyword is the only one of these that expands to cover
+multiple lines, so its behavior is unique. Unlike the others, it does
+not replace the old expansion with the new one, but instead inserts the
+latest expansion, plus an additional blank line, right after the keyword
+(thereby pushing any previous expansions downward). Furthermore, any
+text between the beginning of the line and $Log is used as a prefix for
+the expansions (this is done to ensure that the log messages stay
+commented in program code). For example, if you put this into the file
+
+<pre>// $Log$
+<pre>// Revision 1.1 2002/06/23 14:32:50 llornkcor
+<pre>// some dev docs
+<pre>//
+</pre>
+
+<p>it will expand to something like this on the first commit:
+
+<pre>// $Log$
+<pre>// Revision 1.1 2002/06/23 14:32:50 llornkcor
+<pre>// some dev docs
+<pre>//
+// Revision 1.14 1999/07/26 07:03:20 jrandom
+// this is the first log message...
+//
+</pre>
+
+<p>this on the second:
+
+<pre>// $Log$
+<pre>// Revision 1.1 2002/06/23 14:32:50 llornkcor
+<pre>// some dev docs
+<pre>//
+// Revision 1.15 1999/07/26 07:04:40 jrandom
+// ...and this is the second log message...
+//
+// Revision 1.14 1999/07/26 07:03:20 jrandom
+// this is the first log message...
+//
+</pre>
+
+<p>and so on:
+
+<pre>// $Log$
+<pre>// Revision 1.1 2002/06/23 14:32:50 llornkcor
+<pre>// some dev docs
+<pre>//
+// Revision 1.16 1999/07/26 07:05:34 jrandom
+// ...and this is the third!
+//
+// Revision 1.15 1999/07/26 07:04:40 jrandom
+// ...and this is the second log message...
+//
+// Revision 1.14 1999/07/26 07:03:20 jrandom
+// this is the first log message...
+//
+</pre>
+
+<p>You may not want to keep your entire log history in the file all the
+time; if you do, you can always remove the older sections when it starts
+to get too lengthy. It's certainly more convenient than running cvs
+log, and it may be worthwhile in projects where people must constantly
+read over the logs.
+
+<p>A more common technique may be to include $Revision$ in a file and use
+it as the version number for the program. This can work if the project
+consists of essentially one file or undergoes frequent releases and has
+at least one file that is guaranteed to be modified between every
+release. You can even use an RCS keyword as a value in program code:
+
+<pre>VERSION = "$Revision$";
+</pre>
+
+<p>CVS expands that keyword just like any other; it has no concept of the
+programming language's semantics and does not assume that the double
+quotes protect the string in any way.
+
+<p>A complete list of keywords (there are a few more, rather obscure ones)
+is given in <a href="#CVS_Reference">CVS Reference</a>.
+
+<p><hr>
+Node:<a name="Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>,
+Next:<a rel=next href="#Tracking_Third-Party_Sources__Vendor_Branches_">Tracking Third-Party Sources (Vendor Branches)</a>,
+Previous:<a rel=previous href="#Using_Keyword_Expansion">Using Keyword Expansion</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Going Out On A Limb (How To Work With Branches And Survive)</h2>
+
+<p>Branches are simultaneously one of the most important and most easily
+misused features of CVS. Isolating risky or disruptive changes onto a
+separate line of development until they stabilize can be immensely
+helpful. If not properly managed, however, branches can quickly propel
+a project into confusion and cascading chaos, as people lose track of
+what changes have been merged when.
+
+<ul>
+<li><a href="#Some_Principles_For_Working_With_Branches">Some Principles For Working With Branches</a>:
+<li><a href="#Merging_Repeatedly_Into_The_Trunk">Merging Repeatedly Into The Trunk</a>:
+<li><a href="#The_Dovetail_Approach_--_Merging_In_And_Out_Of_The_Trunk">The Dovetail Approach -- Merging In And Out Of The Trunk</a>:
+<li><a href="#The_Flying_Fish_Approach_--_A_Simpler_Way_To_Do_It">The Flying Fish Approach -- A Simpler Way To Do It</a>:
+<li><a href="#Branches_And_Keyword_Expansion_--_Natural_Enemies">Branches And Keyword Expansion -- Natural Enemies</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Some_Principles_For_Working_With_Branches">Some Principles For Working With Branches</a>,
+Next:<a rel=next href="#Merging_Repeatedly_Into_The_Trunk">Merging Repeatedly Into The Trunk</a>,
+Up:<a rel=up href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>
+<br>
+
+<h3>Some Principles For Working With Branches</h3>
+
+<p>To work successfully with branches, your development group should adhere
+to these principles:
+
+<ul>
+
+<li>Minimize the number of branches active at any one time. The more
+branches under development at the same time, the more likely they are to
+conflict when merged into the trunk. In practical terms, the way to
+accomplish this is to merge as frequently as you can (whenever a branch
+is at a stable point) and to move development back onto the trunk as
+soon as feasible. By minimizing the amount of parallel development
+going on, everyone is better able to keep track of what's going on on
+each branch, and the possibility of conflicts on merge is reduced.
+
+<p>This does not mean minimizing the absolute number of branches in the
+project, just the number being worked on at any given time.
+
+</p><li>Minimize the complexity - that is, the depth - of your branching
+scheme. There are circumstances in which it's appropriate to have
+branches from branches, but they are very rare (you may get through your
+entire programming life without ever encountering one). Just because
+CVS makes it technically possible to have arbitrary levels of nested
+branching, and to merge from any branch to any other branch, doesn't
+mean you actually want to do these things. In most situations, it's
+best to have all your branches rooted at the trunk and to merge from
+branch to trunk and back out again.
+
+<li>Use consistently named tags to mark all branch and merge events.
+Ideally, the meaning of each tag and its relationship to other branches
+and tags should be apparent from the tag name. (The point of this will
+become clearer as we go through the examples.)
+
+</ul>
+
+<p>With those principles in mind, let's take a look at a typical branch
+development scenario. We'll have jrandom on the trunk and qsmith on the
+branch, but note that there could just as well be multiple developers on
+the trunk and/or on the branch. Regular development along either line
+can involve any number of people; however, the tagging and merging are
+best done by one person on each side, as you'll see.
+
+<p><hr>
+Node:<a name="Merging_Repeatedly_Into_The_Trunk">Merging Repeatedly Into The Trunk</a>,
+Next:<a rel=next href="#The_Dovetail_Approach_--_Merging_In_And_Out_Of_The_Trunk">The Dovetail Approach -- Merging In And Out Of The Trunk</a>,
+Previous:<a rel=previous href="#Some_Principles_For_Working_With_Branches">Some Principles For Working With Branches</a>,
+Up:<a rel=up href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>
+<br>
+
+<h3>Merging Repeatedly Into The Trunk</h3>
+
+<p>Let's assume qsmith needs to do development on a branch for a while, to
+avoid destabilizing the trunk that he shares with jrandom. The first
+step is to create the branch. Notice how qsmith creates a regular
+(non-branch) tag at the branch point first, and then creates the branch:
+
+<pre>paste$ pwd
+/home/qsmith/myproj
+paste$ cvs tag Root-of-Exotic_Greetings
+cvs tag: Tagging .
+T README.txt
+T foo.gif
+T hello.c
+cvs tag: Tagging a-subdir
+T a-subdir/whatever.c
+cvs tag: Tagging a-subdir/subsubdir
+T a-subdir/subsubdir/fish.c
+cvs tag: Tagging b-subdir
+T b-subdir/random.c
+paste$ cvs tag -b Exotic_Greetings-branch
+cvs tag: Tagging .
+T README.txt
+T foo.gif
+T hello.c
+cvs tag: Tagging a-subdir
+T a-subdir/whatever.c
+cvs tag: Tagging a-subdir/subsubdir
+T a-subdir/subsubdir/fish.c
+cvs tag: Tagging b-subdir
+T b-subdir/random.c
+paste$
+</pre>
+
+<p>The point of tagging the trunk first is that it may be necessary someday
+to retrieve the trunk as it was the moment the branch was created. If
+you ever need to do that, you'll have to have a way of referring to the
+trunk snapshot without referring to the branch itself. Obviously, you
+can't use the branch tag because that would retrieve the branch, not the
+revisions in the trunk that form the root of the branch. The only way
+to do it is to make a regular tag at the same revisions the branch
+sprouts from. (Some people stick to this rule so faithfully that I
+considered listing it as "Branching Principle Number 4: Always create a
+non-branch tag at the branch point." However, many sites don't do it,
+and they generally seem to do okay, so it's really a matter of taste.)
+From here on, I will refer to this non-branch tag as the <dfn>branch
+point tag</dfn>.
+
+<p>Notice also that a naming convention is being adhered to: The branch
+point tag begins with <code>Root-of-</code>, then the actual branch name,
+which uses underscores instead of hyphens to separate words. When the
+actual branch is created, its tag ends with the suffix <code>-branch</code> so
+that you can identify it as a branch tag just by looking at the tag
+name. (The branch point tag <code>Root-of-Exotic_Greetings</code> does not
+include the -branch because it is not a branch tag.) You don't have to
+use this particular naming convention, of course, but you should use
+some convention.
+
+<p>Of course, I'm being extra pedantic here. In smallish projects, where
+everyone knows who's doing what and confusion is easy to recover from,
+these conventions don't have to be used. Whether you use a branch point
+tag or have a strict naming convention for your tags depends on the
+complexity of the project and the branching scheme. (Also, don't forget
+that you can always go back later and update old tags to use new
+conventions by retrieving an old tagged version, adding the new tag, and
+then deleting the old tag.)
+
+<p>Now, qsmith is ready to start working on the branch:
+
+<pre>paste$ cvs update -r Exotic_Greetings-branch
+cvs update: Updating .
+cvs update: Updating a-subdir
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+paste$
+</pre>
+
+<p>He makes some changes to a couple of files and commits them on the branch:
+
+<pre>paste$ emacs README.txt a-subdir/whatever.c b-subdir/random.c
+...
+paste$ cvs ci -m "print greeting backwards, etc"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in README.txt;
+/usr/local/newrepos/myproj/README.txt,v &lt;-- README.txt
+new revision: 1.14.2.1; previous revision: 1.14
+done
+Checking in a-subdir/whatever.c;
+/usr/local/newrepos/myproj/a-subdir/whatever.c,v &lt;-- whatever.c
+new revision: 1.3.2.1; previous revision: 1.3
+done
+Checking in b-subdir/random.c;
+/usr/local/newrepos/myproj/b-subdir/random.c,v &lt;-- random.c
+new revision: 1.1.1.1.2.1; previous revision: 1.1.1.1
+done
+paste$
+</pre>
+
+<p>Meanwhile, jrandom is continuing to work on the trunk. She modifies two
+of the three files that qsmith touched. Just for kicks, we'll have her
+make changes that conflict with qsmith's work:
+
+<pre>floss$ emacs README.txt whatever.c
+ ...
+floss$ cvs ci -m "some very stable changes indeed"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in README.txt;
+/usr/local/newrepos/myproj/README.txt,v &lt;-- README.txt
+new revision: 1.15; previous revision: 1.14
+done
+Checking in a-subdir/whatever.c;
+/usr/local/newrepos/myproj/a-subdir/whatever.c,v &lt;-- whatever.c
+new revision: 1.4; previous revision: 1.3
+done
+floss$
+</pre>
+
+<p>The conflict is not apparent yet, of course, because neither developer
+has tried to merge branch and trunk. Now, jrandom does the merge:
+
+<pre>floss$ cvs update -j Exotic_Greetings-branch
+cvs update: Updating .
+RCS file: /usr/local/newrepos/myproj/README.txt,v
+retrieving revision 1.14
+retrieving revision 1.14.2.1
+Merging differences between 1.14 and 1.14.2.1 into README.txt
+rcsmerge: warning: conflicts during merge
+cvs update: Updating a-subdir
+RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v
+retrieving revision 1.3
+retrieving revision 1.3.2.1
+Merging differences between 1.3 and 1.3.2.1 into whatever.c
+rcsmerge: warning: conflicts during merge
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v
+retrieving revision 1.1.1.1
+retrieving revision 1.1.1.1.2.1
+Merging differences between 1.1.1.1 and 1.1.1.1.2.1 into random.c
+floss$ cvs update
+cvs update: Updating .
+C README.txt
+cvs update: Updating a-subdir
+C a-subdir/whatever.c
+cvs update: Updating a-subdir/subsubdir
+cvs update: Updating b-subdir
+M b-subdir/random.c
+floss$
+</pre>
+
+<p>Two of the files conflict. No big deal; with her usual savoir-faire,
+jrandom resolves the conflicts, commits, and tags the trunk as
+successfully merged:
+
+<pre>floss$ emacs README.txt a-subdir/whatever.c
+ ...
+floss$ cvs ci -m "merged from Exotic_Greetings-branch (conflicts resolved)"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in README.txt;
+/usr/local/newrepos/myproj/README.txt,v &lt;-- README.txt
+new revision: 1.16; previous revision: 1.15
+done
+Checking in a-subdir/whatever.c;
+/usr/local/newrepos/myproj/a-subdir/whatever.c,v &lt;-- whatever.c
+new revision: 1.5; previous revision: 1.4
+done
+Checking in b-subdir/random.c;
+/usr/local/newrepos/myproj/b-subdir/random.c,v &lt;-- random.c
+new revision: 1.2; previous revision: 1.1
+done
+floss$ cvs tag merged-Exotic_Greetings
+cvs tag: Tagging .
+T README.txt
+T foo.gif
+T hello.c
+cvs tag: Tagging a-subdir
+T a-subdir/whatever.c
+cvs tag: Tagging a-subdir/subsubdir
+T a-subdir/subsubdir/fish.c
+cvs tag: Tagging b-subdir
+T b-subdir/random.c
+floss$
+</pre>
+
+<p>Meanwhile, qsmith needn't wait for the merge to finish before continuing
+development, as long as he makes a tag for the batch of changes from
+which jrandom merged (later, jrandom will need to know this tag name; in
+general, branches depend on frequent and thorough developer
+communications):
+
+<pre>paste$ cvs tag Exotic_Greetings-1
+cvs tag: Tagging .
+T README.txt
+T foo.gif
+T hello.c
+cvs tag: Tagging a-subdir
+T a-subdir/whatever.c
+cvs tag: Tagging a-subdir/subsubdir
+T a-subdir/subsubdir/fish.c
+cvs tag: Tagging b-subdir
+T b-subdir/random.c
+paste$ emacs a-subdir/whatever.c
+ ...
+paste$ cvs ci -m "print a randomly capitalized greeting"
+cvs commit: Examining .
+cvs commit: Examining a-subdir
+cvs commit: Examining a-subdir/subsubdir
+cvs commit: Examining b-subdir
+Checking in a-subdir/whatever.c;
+/usr/local/newrepos/myproj/a-subdir/whatever.c,v &lt;-- whatever.c
+new revision: 1.3.2.2; previous revision: 1.3.2.1
+done
+paste$
+</pre>
+
+<p>And of course, qsmith should tag those changes once he's done:
+
+<pre>paste$ cvs -q tag Exotic_Greetings-2
+T README.txt
+T foo.gif
+T hello.c
+T a-subdir/whatever.c
+T a-subdir/subsubdir/fish.c
+T b-subdir/random.c
+paste$
+</pre>
+
+<p>While all this is going on, jrandom makes a change in a different file,
+one that qsmith hasn't touched in his new batch of edits:
+
+<pre>floss$ emacs README.txt
+ ...
+floss$ cvs ci -m "Mention new Exotic Greeting features" README.txt
+Checking in README.txt;
+/usr/local/newrepos/myproj/README.txt,v &lt;-- README.txt
+new revision: 1.17; previous revision: 1.16
+done
+floss$
+</pre>
+
+<p>At this point, qsmith has committed a new change on the branch, and
+jrandom has committed a nonconflicting change in a different file on the
+trunk. Watch what happens when jrandom tries to merge from the branch
+again:
+
+<pre>floss$ cvs -q update -j Exotic_Greetings-branch
+RCS file: /usr/local/newrepos/myproj/README.txt,v
+retrieving revision 1.14
+retrieving revision 1.14.2.1
+Merging differences between 1.14 and 1.14.2.1 into README.txt
+rcsmerge: warning: conflicts during merge
+RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v
+retrieving revision 1.3
+retrieving revision 1.3.2.2
+Merging differences between 1.3 and 1.3.2.2 into whatever.c
+rcsmerge: warning: conflicts during merge
+RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v
+retrieving revision 1.1
+retrieving revision 1.1.1.1.2.1
+Merging differences between 1.1 and 1.1.1.1.2.1 into random.c
+floss$ cvs -q update
+C README.txt
+C a-subdir/whatever.c
+floss$
+</pre>
+
+<p>There are conflicts! Is that what you expected?
+
+<p>The problem lies in the semantics of merging. Back in <a href="#An_Overview_of_CVS">An Overview of CVS</a>, I explained that when you run
+
+<pre>floss$ cvs update -j BRANCH
+</pre>
+
+<p>in a working copy, CVS merges into the working copy the differences
+between BRANCH's root and its tip. The trouble with that behavior, in
+this situation, is that most of those changes had already been
+incorporated into the trunk the first time that jrandom did a merge.
+When CVS tried to merge them in again (over themselves, as it were), it
+naturally registered a conflict.
+
+<p>What jrandom really wanted to do was merge into her working copy the
+changes between the branch's most recent merge and its current tip. You
+can do this by using two -j flags to update, as you may recall from
+<a href="#An_Overview_of_CVS">An Overview of CVS</a>, as long as you know what revision to specify
+with each flag. Fortunately, qsmith made a tag at exactly the last
+merge point (hurrah for planning ahead!), so this will be no problem.
+First, let's have jrandom restore her working copy to a clean state,
+from which she can redo the merge:
+
+<pre>floss$ rm README.txt a-subdir/whatever.c
+floss$ cvs -q update
+cvs update: warning: README.txt was lost
+U README.txt
+cvs update: warning: a-subdir/whatever.c was lost
+U a-subdir/whatever.c
+floss$
+</pre>
+
+<p>Now she's ready to do the merge, this time using qsmith's conveniently
+placed tag:
+
+<pre>floss$ cvs -q update -j Exotic_Greetings-1 -j Exotic_Greetings-branch
+RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v
+retrieving revision 1.3.2.1
+retrieving revision 1.3.2.2
+Merging differences between 1.3.2.1 and 1.3.2.2 into whatever.c
+floss$ cvs -q update
+M a-subdir/whatever.c
+floss$
+</pre>
+
+<p>Much better. The change from qsmith has been incorporated into
+whatever.c; jrandom can now commit and tag:
+
+<pre>floss$ cvs -q ci -m "merged again from Exotic_Greetings (1)"
+Checking in a-subdir/whatever.c;
+/usr/local/newrepos/myproj/a-subdir/whatever.c,v &lt;-- whatever.c
+new revision: 1.6; previous revision: 1.5
+done
+floss$ cvs -q tag merged-Exotic_Greetings-1
+T README.txt
+T foo.gif
+T hello.c
+T a-subdir/whatever.c
+T a-subdir/subsubdir/fish.c
+T b-subdir/random.c
+floss$
+</pre>
+
+<p>Even if qsmith had forgotten to tag at the merge point, all hope would
+not be lost. If jrandom knew approximately when qsmith's first batch of
+changes had been committed, she could try filtering by date:
+
+<pre>floss$ cvs update -j Exotic_Greetings-branch:3pm -j Exotic_Greetings_branch
+</pre>
+
+<p>Although useful as a last resort, filtering by date is less than ideal
+because it selects the changes based on people's recollections rather
+than dependable developer designations. If qsmith's first mergeable set
+of changes had happened over several commits instead of in one commit,
+jrandom may mistakenly choose a date or time that would catch some of
+the changes, but not all of them.
+
+<p>There's no reason why each taggable point in qsmith's changes needs to
+be sent to the repository in a single commit - it just happens to have
+worked out that way in these examples. In real life, qsmith may make
+several commits between tags. He can work on the branch in isolation,
+as he pleases. The point of the tags is to record successive points on
+the branch where he considers the changes to be mergeable into the
+trunk. As long as jrandom always merges using two -j flags and is
+careful to use qsmith's merge tags in the right order and only once
+each, the trunk should never experience the double-merge problem.
+Conflicts may occur, but they will be the unavoidable kind that requires
+human resolution - situations in which both branch and trunk made
+changes to the same area of code.
+
+<p><hr>
+Node:<a name="The_Dovetail_Approach_--_Merging_In_And_Out_Of_The_Trunk">The Dovetail Approach -- Merging In And Out Of The Trunk</a>,
+Next:<a rel=next href="#The_Flying_Fish_Approach_--_A_Simpler_Way_To_Do_It">The Flying Fish Approach -- A Simpler Way To Do It</a>,
+Previous:<a rel=previous href="#Merging_Repeatedly_Into_The_Trunk">Merging Repeatedly Into The Trunk</a>,
+Up:<a rel=up href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>
+<br>
+
+<h3>The Dovetail Approach - Merging In And Out Of The Trunk</h3>
+
+<p>Merging repeatedly from branch to trunk is good for the people on the
+trunk, because they see all of their own changes and all the changes
+from the branch. However, the developer on the branch never gets to
+incorporate any of the work being done on the trunk.
+
+<p>To allow that, the branch developer needs to add an extra step every now
+and then (meaning whenever he feels like merging in recent trunk changes
+and dealing with the inevitable conflicts):
+
+<pre>paste$ cvs update -j HEAD
+</pre>
+
+<p>The special reserved tag <code>HEAD</code> means the tip of the trunk. The
+preceding command merges in all of the trunk changes between the root of
+the current branch (<code>Exotic_Greetings-branch</code>) and the current
+highest revisions of each file on the trunk. Of course, qsmith should
+tag again after doing this, so that the trunk developers can avoid
+accidentally merging in their own changes when they're trying to get
+qsmith's.
+
+<p>The branch developer can likewise use the trunk's merge tags as
+boundaries, allowing the branch to merge exactly those trunk changes
+between the last merge and the trunk's current state (the same way the
+trunk does merges). For example, supposing jrandom had made some
+changes to hello.c after merging from the branch:
+
+<pre>floss$ emacs hello.c
+ ...
+floss$ cvs ci -m "clarify algorithm" hello.c
+Checking in hello.c;
+/usr/local/newrepos/myproj/hello.c,v &lt;-- hello.c
+new revision: 1.22; previous revision: 1.21
+done
+floss$
+</pre>
+
+<p>Then, qsmith can merge those changes into his branch, commit, and, of
+course, tag:
+
+<pre>paste$ cvs -q update -j merged-Exotic_Greetings-1 -j HEAD
+RCS file: /usr/local/newrepos/myproj/hello.c,v
+retrieving revision 1.21
+retrieving revision 1.22
+Merging differences between 1.21 and 1.22 into hello.c
+paste$ cvs -q update
+M hello.c
+paste$ cvs -q ci -m "merged trunk, from merged-Exotic_Greetings-1 to HEAD"
+Checking in hello.c;
+/usr/local/newrepos/myproj/hello.c,v &lt;-- hello.c
+new revision: 1.21.2.1; previous revision: 1.21
+done
+paste$ cvs -q tag merged-merged-Exotic_Greetings-1
+T README.txt
+T foo.gif
+T hello.c
+T a-subdir/whatever.c
+T a-subdir/subsubdir/fish.c
+T b-subdir/random.c
+paste$
+</pre>
+
+<p>Notice that jrandom did not bother to tag after committing the changes
+to hello.c, but qsmith did. The principle at work here is that although
+you don't need to tag after every little change, you should always tag
+after a merge or after committing your line of development up to a
+mergeable state. That way, other people - perhaps on other branches -
+have a reference point against which to base their own merges.
+
+<p><hr>
+Node:<a name="The_Flying_Fish_Approach_--_A_Simpler_Way_To_Do_It">The Flying Fish Approach -- A Simpler Way To Do It</a>,
+Next:<a rel=next href="#Branches_And_Keyword_Expansion_--_Natural_Enemies">Branches And Keyword Expansion -- Natural Enemies</a>,
+Previous:<a rel=previous href="#The_Dovetail_Approach_--_Merging_In_And_Out_Of_The_Trunk">The Dovetail Approach -- Merging In And Out Of The Trunk</a>,
+Up:<a rel=up href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>
+<br>
+
+<h3>The Flying Fish Approach - A Simpler Way To Do It</h3>
+
+<p>There is a simpler, albeit slightly limiting, variant of the preceding.
+In it, the branch developers freeze while the trunk merges, and then the
+trunk developers create an entirely new branch, which replaces the old
+one. The branch developers move onto that branch and continue working.
+The cycle continues until there is no more need for branch development.
+It goes something like this (in shorthand - we'll assume jrandom@floss
+has the trunk and qsmith@paste has the branch, as usual):
+
+<pre>floss$ cvs tag -b BRANCH-1
+paste$ cvs checkout -r BRANCH-1 myproj
+</pre>
+
+<p>Trunk and branch both start working; eventually, the developers confer
+and decide it's time to merge the branch into the trunk:
+
+<pre>paste$ cvs ci -m "committing all uncommitted changes"
+floss$ cvs update -j BRANCH-1
+</pre>
+
+<p>All the changes from the branch merge in; the branch developers stop
+working while the trunk developers resolve any conflicts, commit, tag,
+and create a new branch:
+
+<pre>floss$ cvs ci -m "merged from BRANCH-1"
+floss$ cvs tag merged-from-BRANCH-1
+floss$ cvs tag -b BRANCH-2
+</pre>
+
+<p>Now the branch developers switch their working copies over to the new
+branch; they know they won't lose any uncommitted changes by doing so,
+because they were up-to-date when the merge happened, and the new branch
+is coming out of a trunk that has incorporated the changes from the old
+branch:
+
+<pre>paste$ cvs update -r BRANCH-2
+</pre>
+
+<p>And the cycle continues in that way, indefinitely; just substitute
+BRANCH-2 for BRANCH-1 and BRANCH-3 for BRANCH-2.
+
+<p>I call this the <dfn>Flying Fish</dfn> technique, because the branch is
+constantly emerging from the trunk, traveling a short distance, then
+rejoining it. The advantages of this approach are that it's simple (the
+trunk always merges in all the changes from a given branch) and the
+branch developers never need to resolve conflicts (they're simply handed
+a new, clean branch on which to work each time). The disadvantage, of
+course, is that the branch people must sit idle while the trunk is
+undergoing merge (which can take an arbitrary amount of time, depending
+on how many conflicts need to be resolved). Another minor disadvantage
+is that it results in many little, unused branches laying around instead
+of many unused non-branch tags. However, if having millions of tiny,
+obsolete branches doesn't bother you, and you anticipate fairly
+trouble-free merges, Flying Fish may be the easiest way to go in terms
+of mental bookkeeping.
+
+<p>Whichever way you do it, you should try to keep the separations as short
+as possible. If the branch and the trunk go too long without merging,
+they could easily begin to suffer not just from textual drift, but
+semantic drift as well. Changes that conflict textually are the easiest
+ones to resolve. Changes that conflict conceptually, but not textually,
+often prove hardest to find and fix. The isolation of a branch, so
+freeing to the developers, is dangerous precisely because it shields
+each side from the effects of others' changes...for a time. When you
+use branches, communication becomes more vital than ever: Everyone needs
+to make extra sure to review each others' plans and code to ensure that
+they're all staying on the same track.
+
+<p><hr>
+Node:<a name="Branches_And_Keyword_Expansion_--_Natural_Enemies">Branches And Keyword Expansion -- Natural Enemies</a>,
+Previous:<a rel=previous href="#The_Flying_Fish_Approach_--_A_Simpler_Way_To_Do_It">The Flying Fish Approach -- A Simpler Way To Do It</a>,
+Up:<a rel=up href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>
+<br>
+
+<h3>Branches And Keyword Expansion - Natural Enemies</h3>
+
+<p>If your files contain RCS keywords that expand differently on branch and
+trunk, you're almost guaranteed to get spurious conflicts on every
+merge. Even if nothing else changed, the keywords are overlapping, and
+their expansions won't match. For example, if README.txt contains this
+on the trunk
+
+<pre>$Revision$
+</pre>
+
+<p>and this on the branch
+
+<pre>$Revision$
+</pre>
+
+<p>then when the merge is performed, you'll get the following conflict:
+
+<pre>floss$ cvs update -j Exotic_Greetings-branch
+RCS file: /usr/local/newrepos/myproj/README.txt,v
+retrieving revision 1.14
+retrieving revision 1.14.2.1
+Merging differences between 1.14 and 1.14.2.1 into README.txt
+rcsmerge: warning: conflicts during merge
+floss$ cat README.txt
+ ...
+&lt;&lt;&lt;&lt;&lt;&lt;&lt; README.txt
+key $Revision$
+=======
+key $Revision$
+&gt;&gt;&gt;&gt;&gt;&gt;&gt; 1.14.2.1
+ ...
+floss$
+</pre>
+
+<p>To avoid this, you can temporarily disable expansion by passing the -kk
+option (I don't know what it stands for; "kill keywords" maybe?) when
+you do the merge:
+
+<pre>floss$ cvs update -kk -j Exotic_Greetings-branch
+RCS file: /usr/local/newrepos/myproj/README.txt,v
+retrieving revision 1.14
+retrieving revision 1.14.2.1
+Merging differences between 1.14 and 1.14.2.1 into README.txt
+floss$ cat README.txt
+ ...
+$Revision$
+ ...
+floss$
+</pre>
+
+<p>There is one thing to be careful of, however: If you use -kk, it
+overrides whatever other keyword expansion mode you may have set for
+that file. Specifically, this is a problem for binary files, which are
+normally -kb (which suppresses all keyword expansion and line-end
+conversion). So if you have to merge binary files in from a branch,
+don't use -kk. Just deal with the conflicts by hand instead.
+
+<p><hr>
+Node:<a name="Tracking_Third-Party_Sources__Vendor_Branches_">Tracking Third-Party Sources (Vendor Branches)</a>,
+Next:<a rel=next href="#Exporting_For_Public_Distribution">Exporting For Public Distribution</a>,
+Previous:<a rel=previous href="#Going_Out_On_A_Limb__How_To_Work_With_Branches_And_Survive_">Going Out On A Limb (How To Work With Branches And Survive)</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Tracking Third-Party Sources (Vendor Branches)</h2>
+
+<p>Sometimes a site will make local changes to a piece of software received
+from an outside source. If the outside source does not incorporate the
+local changes (and there might be many legitimate reasons why it can't),
+the site has to maintain its changes in each received upgrade of the
+software.
+
+<p>CVS can help with this task, via a feature known as <dfn>vendor
+branches</dfn>. In fact, vendor branches are the explanation behind the
+puzzling (until now) final two arguments to cvs import: the vendor tag
+and release tag that I glossed over in <a href="#An_Overview_of_CVS">An Overview of CVS</a>.
+
+<p>Here's how it works. The initial import is just like any other initial
+import of a CVS project (except that you'll want to choose the vendor
+tag and release tag with a little care):
+
+<pre>floss$ pwd
+/home/jrandom/theirproj-1.0
+floss$ cvs import -m "Import of TheirProj 1.0" theirproj Them THEIRPROJ_1_0
+N theirproj/INSTALL
+N theirproj/README
+N theirproj/src/main.c
+N theirproj/src/parse.c
+N theirproj/src/digest.c
+N theirproj/doc/random.c
+N theirproj/doc/manual.txt
+
+No conflicts created by this import
+
+floss$
+</pre>
+
+<p>Then you check out a working copy somewhere, make your local
+modifications, and commit:
+
+<pre>floss$ cvs -q co theirproj
+U theirproj/INSTALL
+U theirproj/README
+U theirproj/doc/manual.txt
+U theirproj/doc/random.c
+U theirproj/src/digest.c
+U theirproj/src/main.c
+U theirproj/src/parse.c
+floss$ cd theirproj
+floss$ emacs src/main.c src/digest.c
+ ...
+floss$ cvs -q update
+M src/digest.c
+M src/main.c
+floss$ cvs -q ci -m "changed digestion algorithm; added comment to main"
+Checking in src/digest.c;
+/usr/local/newrepos/theirproj/src/digest.c,v &lt;-- digest.c
+new revision: 1.2; previous revision: 1.1
+done
+Checking in src/main.c;
+/usr/local/newrepos/theirproj/src/main.c,v &lt;-- main.c
+new revision: 1.2; previous revision: 1.1
+done
+floss$
+</pre>
+
+<p>A year later, the next version of the software arrives from Them, Inc.,
+and you must incorporate your local changes into it. Their changes and
+yours overlap slightly. They've added one new file, modified a couple
+of files that you didn't touch, but also modified two files that you
+modified.
+
+<p>First you must do another import, this time from the new sources.
+Almost everything is the same as it was in the initial import - you're
+importing to the same project in the repository, and on the same vendor
+branch. The only thing different is the release tag:
+
+<pre>floss$ pwd
+/home/jrandom/theirproj-2.0
+floss$ cvs -q import -m "Import of TheirProj 2.0" theirproj Them THEIRPROJ_2_0
+U theirproj/INSTALL
+N theirproj/TODO
+U theirproj/README
+cvs import: Importing /usr/local/newrepos/theirproj/src
+C theirproj/src/main.c
+U theirproj/src/parse.c
+C theirproj/src/digest.c
+cvs import: Importing /usr/local/newrepos/theirproj/doc
+U theirproj/doc/random.c
+U theirproj/doc/manual.txt
+
+2 conflicts created by this import.
+Use the following command to help the merge:
+
+ cvs checkout -jThem:yesterday -jThem theirproj
+
+floss$
+</pre>
+
+<p>My goodness - we've never seen CVS try to be so helpful. It's actually
+telling us what command to run to merge the changes. And it's almost
+right, too! Actually, the command as given works (assuming that you
+adjust yesterday to be any time interval that definitely includes the
+first import but not the second), but I mildly prefer to do it by
+release tag instead:
+
+<pre>floss$ cvs checkout -j THEIRPROJ_1_0 -j THEIRPROJ_2_0 theirproj
+cvs checkout: Updating theirproj
+U theirproj/INSTALL
+U theirproj/README
+U theirproj/TODO
+cvs checkout: Updating theirproj/doc
+U theirproj/doc/manual.txt
+U theirproj/doc/random.c
+cvs checkout: Updating theirproj/src
+U theirproj/src/digest.c
+RCS file: /usr/local/newrepos/theirproj/src/digest.c,v
+retrieving revision 1.1.1.1
+retrieving revision 1.1.1.2
+Merging differences between 1.1.1.1 and 1.1.1.2 into digest.c
+rcsmerge: warning: conflicts during merge
+U theirproj/src/main.c
+RCS file: /usr/local/newrepos/theirproj/src/main.c,v
+retrieving revision 1.1.1.1
+retrieving revision 1.1.1.2
+Merging differences between 1.1.1.1 and 1.1.1.2 into main.c
+U theirproj/src/parse.c
+floss$
+</pre>
+
+<p>Notice how the import told us that there were two conflicts, but the
+merge only seems to claim one conflict. It seems that CVS's idea of a
+conflict is a little different when importing than at other times.
+Basically, import reports a conflict if both you and the vendor modified
+a file between the last import and this one. However, when it comes
+time to merge, update sticks with the usual definition of "conflict" -
+overlapping changes. Changes that don't overlap are merged in the usual
+way, and the file is simply marked as modified.
+
+<p>A quick diff verifies that only one of the files actually has conflict
+markers:
+
+<pre>floss$ cvs -q update
+C src/digest.c
+M src/main.c
+floss$ cvs diff -c
+Index: src/digest.c
+===================================================================
+RCS file: /usr/local/newrepos/theirproj/src/digest.c,v
+retrieving revision 1.2
+diff -c -r1.2 digest.c
+*** src/digest.c 1999/07/26 08:02:18 1.2
+-- src/digest.c 1999/07/26 08:16:15
+***************
+*** 3,7 ****
+-- 3,11 ----
+ void
+ digest ()
+ {
++ &lt;&lt;&lt;&lt;&lt;&lt;&lt; digest.c
+ printf ("gurgle, slorp\n");
++ =======
++ printf ("mild gurgle\n");
++ &gt;&gt;&gt;&gt;&gt;&gt;&gt; 1.1.1.2
+ }
+Index: src/main.c
+===================================================================
+RCS file: /usr/local/newrepos/theirproj/src/main.c,v
+retrieving revision 1.2
+diff -c -r1.2 main.c
+*** src/main.c 1999/07/26 08:02:18 1.2
+-- src/main.c 1999/07/26 08:16:15
+***************
+*** 7,9 ****
+-- 7,11 ----
+ {
+ printf ("Goodbye, world!\n");
+ }
++
++ /* I, the vendor, added this comment for no good reason. */
+floss$
+</pre>
+
+<p>From here, it's just a matter of resolving the conflicts as with any
+other merge:
+
+<pre>floss$ emacs src/digest.c src/main.c
+ ...
+floss$ cvs -q update
+M src/digest.c
+M src/main.c
+floss$ cvs diff src/digest.c
+cvs diff src/digest.c
+Index: src/digest.c
+===================================================================
+RCS file: /usr/local/newrepos/theirproj/src/digest.c,v
+retrieving revision 1.2
+diff -r1.2 digest.c
+6c6
+&lt; printf ("gurgle, slorp\n");
+--
+&gt; printf ("mild gurgle, slorp\n");
+floss$
+</pre>
+
+<p>Then commit the changes
+
+<pre>floss$ cvs -q ci -m "Resolved conflicts with import of 2.0"
+Checking in src/digest.c;
+/usr/local/newrepos/theirproj/src/digest.c,v &lt;-- digest.c
+new revision: 1.3; previous revision: 1.2
+done
+Checking in src/main.c;
+/usr/local/newrepos/theirproj/src/main.c,v &lt;-- main.c
+new revision: 1.3; previous revision: 1.2
+done
+floss$
+</pre>
+
+<p>and wait for the next release from the vendor. (Of course, you'll also
+want to test that your local modifications still work!)
+
+<p>-------------------------------------------------------------
+<p><hr>
+Node:<a name="Exporting_For_Public_Distribution">Exporting For Public Distribution</a>,
+Next:<a rel=next href="#The_Humble_Guru">The Humble Guru</a>,
+Previous:<a rel=previous href="#Tracking_Third-Party_Sources__Vendor_Branches_">Tracking Third-Party Sources (Vendor Branches)</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>Exporting For Public Distribution</h2>
+
+<p>CVS is a good distribution mechanism for developers, but most users will
+obtain the software through a downloadable package instead. This
+package is generally not a CVS working copy - it's just a source tree
+that can be easily configured and compiled on the user's system.
+
+<p>However, CVS does offer a mechanism to help you create that package,
+namely the <code>cvs&nbsp;export</code> command. To <dfn>export</dfn> a project is
+just like checking out a working copy of the project, except that it
+checks out the project tree <em>without</em> any <code>CVS</code> administrative
+subdirectories. That is to say, you don't get a working copy, you just
+get a source tree that knows nothing about where it came from or what
+the CVS versions of its files are. Thus, the exported copy is just like
+what the public sees after it downloads and unpacks a distribution.
+Assuming the project is arranged to be directly compilable from a
+working copy (and it certainly should be!), then it will still be
+compilable from the exported copy.
+
+<p>The <code>export</code> command works like <code>checkout</code>, except that it
+requires a tag name or date. For example, here we tag the project with
+a release name, and then export based on that:
+
+<pre>floss$ pwd
+/home/jrandom/myproj
+floss$ cvs -q tag R_1_0
+T README.txt
+T hello.c
+T a-subdir/whatever.c
+T a-subdir/subsubdir/fish.c
+T b-subdir/random.c
+floss$ cd ..
+floss$ cvs -d /usr/local/newrepos -q export -r R_1_0 -d myproj-1.0 myproj
+U myproj-1.0/README.txt
+U myproj-1.0/hello.c
+U myproj-1.0/a-subdir/whatever.c
+U myproj-1.0/a-subdir/subsubdir/fish.c
+U myproj-1.0/b-subdir/random.c
+floss$ cd myproj-1.0
+floss$ ls
+README.txt a-subdir b-subdir hello.c
+</pre>
+
+<p>Notice how, since the <code>export</code> command is not invoked from within a
+working copy, it's necessary to use the global <code>-d</code> option to tell
+CVS which repository to use. Also, in this particular example, we
+exported into an explicitly named directory (<code>myproj-1.0</code>) instead
+of defaulting to the project's name (<code>myproj</code>), since there was a
+working copy of that name already present. This situation is not
+uncommon.
+
+<p>After the exported copy is created, as in the above example, the
+following might be sufficient to complete the release, if the project is
+a simple one:
+
+<pre>floss$ tar cf myproj-1.0.tar myproj-1.0
+floss$ gzip --best myproj-1.0.tar
+floss$ ls
+myproj/ myproj-1.0/ myproj-1.0.tar.gz
+floss$ rm -rf myproj-1.0
+floss$ mv myproj-1.0.tar.gz /home/ftp/pub/myproj/
+</pre>
+
+<p>Of course, running all of these commands by hand is rare. More often,
+<code>cvs&nbsp;export</code> is called from within some script that handles all
+aspects of release and packaging process. Given that there are often
+several "test" releases leading up to each public release, it is
+desirable that the procedures for creating a releasable package be
+highly automated.
+
+<p><hr>
+Node:<a name="The_Humble_Guru">The Humble Guru</a>,
+Previous:<a rel=previous href="#Exporting_For_Public_Distribution">Exporting For Public Distribution</a>,
+Up:<a rel=up href="#Advanced_CVS">Advanced CVS</a>
+<br>
+
+<h2>The Humble Guru</h2>
+
+<p>If you read and understood (and better yet, experimented with)
+everything in this chapter, you may rest assured that there are no big
+surprises left for you in CVS - at least until someone adds a major new
+feature to CVS. Everything you need to know to use CVS on a major
+project has been presented.
+
+<p>Before that goes to your head, let me reiterate the suggestion, first
+made in Chapter 4, that you subscribe to the <a href="mailto:info-cvs@gnu.org">info-cvs@gnu.org</a>
+mailing list. Despite having the impoverished signal-to-noise ratio
+common to most Internet mailing lists, the bits of signal that do come
+through are almost always worth the wait. I was subscribed during the
+entire time I wrote this chapter (indeed, for all previous chapters as
+well), and you would be amazed to know how many important details I
+learned about CVS's behavior from reading other people's posts. If
+you're going to be using CVS seriously, and especially if you're the CVS
+administrator for a group of developers, you can benefit a lot from the
+shared knowledge of all the other serious users out there.
+
+<p><hr>
+Node:<a name="Tips_And_Troubleshooting">Tips And Troubleshooting</a>,
+Next:<a rel=next href="#CVS_Reference">CVS Reference</a>,
+Previous:<a rel=previous href="#Advanced_CVS">Advanced CVS</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>Tips And Troubleshooting</h1>
+
+<p>I've said in earlier chapters that CVS is not "black box" software.
+Black boxes don't let you peek inside; they don't give you internal
+access so that you can fix (or break) things. The premise is that the
+black box usually doesn't need to be fixed. Most of the time, the
+software should work perfectly, so users don't need internal access.
+But when black boxes do fail, they tend to fail completely. Any problem
+at all is a showstopper, because there aren't many options for repair.
+
+<p>CVS is more like a perfectly transparent box - except without the box.
+Its moving parts are exposed directly to the environment, not
+hermetically sealed off, and bits of that environment (unexpected file
+permissions, interrupted commands, competing processes, whatever) can
+sometimes get inside the mechanism and gum up the gears. But even
+though CVS does not always work perfectly, it rarely fails completely,
+either. It has the advantage of graceful degradation; the degree to
+which it doesn't work is usually proportional to the number and severity
+of problems in its environment. If you know enough about what CVS is
+trying to do - and how it's trying to do it - you'll know what to do
+when things go wrong.
+
+<p>Although I can't list all of the problems that you might encounter, I've
+included some of the more common ones here. This chapter is divided
+into two sections: The first describes those parts of the environment to
+which CVS is most sensitive (mainly repository permissions and the
+working copy administrative area), and the second describes some of the
+most frequently encountered problems and their solutions. By seeing how
+to handle these common situations, you will get a feeling for how to
+approach any unexpected problem in CVS.
+
+<ul>
+<li><a href="#The_Usual_Suspects">The Usual Suspects</a>: Things that often cause trouble.
+<li><a href="#General_Troubleshooting_Tips">General Troubleshooting Tips</a>: General diagnostic techniques.
+<li><a href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>: A compendium of actual problems.
+</ul>
+
+<p><hr>
+Node:<a name="The_Usual_Suspects">The Usual Suspects</a>,
+Next:<a rel=next href="#General_Troubleshooting_Tips">General Troubleshooting Tips</a>,
+Up:<a rel=up href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>
+<br>
+
+<h2>The Usual Suspects</h2>
+
+<p>As a CVS administrator (read "field doctor"), you will find that 90
+percent of your users' problems are caused by inconsistent working
+copies, and the other 90 percent by incorrect repository permissions.
+Therefore, before looking at any specific situations, I'll give a quick
+overview of the working copy administrative area and review a few
+important things about repository permissions.
+
+<ul>
+<li><a href="#The_Working_Copy_Administrative_Area">The Working Copy Administrative Area</a>:
+<li><a href="#Repository_Permissions">Repository Permissions</a>:
+</ul>
+
+<p><hr>
+Node:<a name="The_Working_Copy_Administrative_Area">The Working Copy Administrative Area</a>,
+Next:<a rel=next href="#Repository_Permissions">Repository Permissions</a>,
+Up:<a rel=up href="#The_Usual_Suspects">The Usual Suspects</a>
+<br>
+
+<h3>The Working Copy Administrative Area</h3>
+
+<p>You've already seen the basics of working copy structure in <a href="#An_Overview_of_CVS">An Overview of CVS</a>; in this section, we'll go into a bit more detail.
+Most of the details concern the files in the CVS/ administrative
+subdirectories. You already know about Entries, Root, and Repository,
+but the CVS/ subdirectory can also contain other files, depending on the
+circumstances. I'll describe those other files here, partly so they
+don't surprise you when you encounter them, and partly so you can fix
+them if they ever cause trouble.
+
+<h2><code>CVS/Entries.Log</code></h2>
+
+<p>Sometimes, a file named <code>CVS/Entries.Log</code> will mysteriously appear.
+The sole purpose of this file is to temporarily cache minor changes to
+CVS/Entries, until some operation significant enough to be worth
+rewriting the entire Entries file comes along. CVS has no ability to
+edit the Entries file in place; it must read the entire file in and
+write it back out to make any change. To avoid this effort, CVS
+sometimes records small changes in Entries.Log, until the next time it
+needs to rewrite Entries.
+
+<p>The format of Entries.Log is like Entries, except for an extra letter at
+the beginning of each line. <code>A</code> means that the line is to be added
+to the main Entries file, and <code>R</code> means it is to be removed.
+
+<p>For the most part, you can ignore Entries.Log; it's rare that a human
+has to understand the information it contains. However, if you're
+reading over an Entries file to debug some problem in a working copy,
+you should also examine Entries.Log.
+
+<h2><code>CVS/Entries.Backup</code></h2>
+
+<p>The CVS/Entries.Backup file is where CVS actually writes out a new
+Entries file, before renaming it to <code>Entries</code> (similar to the way
+it writes to temporary RCS files in the repository and then moves them
+to their proper name when they're complete). Because it becomes Entries
+when it's complete, you'll rarely see an Entries.Backup file; if you do
+see one, it probably means CVS got interrupted in the middle of some
+operation.
+
+<h2><code>CVS/Entries.Static</code></h2>
+
+<p>If the CVS/Entries.Static file exists, it means that the entire
+directory has not been fetched from the repository. (When CVS knows a
+working directory is in an incomplete state, it will not bring
+additional files into that directory.)
+
+<p>The Entries.Static file is present during checkouts and updates and
+removed immediately when the operation is complete. If you see
+Entries.Static, it means that CVS was interrupted, and its presence
+prevents CVS from creating any new files in the working copy. (Often,
+running <code>cvs&nbsp;update&nbsp;-d</code> solves the problem and removes
+Entries.Static.)
+
+<p>The absence of Entries.Static does not necessarily imply that the
+working copy contains all of the project's files. Whenever a new
+directory is created in the project's repository, and someone updates
+their working copy without passing the -d flag to update, the new
+directory will not be created in the working copy. Locally, CVS is
+unaware that there is a new directory in the repository, so it goes
+ahead and removes the Entries.Static file when the update is complete,
+even though the new directory is not present in the working copy.
+
+<h2><code>CVS/Tag</code></h2>
+
+<p>If the CVS/Tag file is present, it names a tag associated, in some
+sense, with the directory. I say "in some sense" because, as you know,
+CVS does not actually keep any revision history for directories and,
+strictly speaking, cannot attach tags to them. Tags are attached to
+regular files only or, more accurately, to particular revisions in
+regular files.
+
+<p>However, if every file in a directory is on a particular tag, CVS likes
+to think of the entire directory as being on the tag, too. For example,
+if you were to check out a working copy on a particular branch:
+
+<pre>floss$ cvs co -r Bugfix_Branch_1
+</pre>
+
+<p>and then add a file inside it, you'd want the new file's initial
+revision to be on that branch, too. For similar reasons, CVS also needs
+to know if the directory has a nonbranch sticky tag or date set on it.
+
+<p>Tag files contain one line. The first character on the line is a
+single-letter code telling what kind of tag it is, and the rest of the
+line is the tag's name. Currently, CVS uses only these three
+single-letter codes:
+
+<ul>
+
+<li>T - A branch tag
+
+<li>N - A nonbranch (regular) tag
+
+<li>D - A sticky date, which occurs if a command such as
+
+<pre>floss$ cvs checkout -D 1999-05-15 myproj
+</pre>
+
+<p>or
+
+<pre>floss$ cvs update -D 1999-05-15 myproj
+</pre>
+
+<p>is run.
+
+</ul>
+
+<p>(If you see some other single-letter code, it just means that CVS has
+added a new tag type since this chapter was written.)
+
+<p>You should not remove the Tag file manually; instead, use <code>cvs&nbsp;update&nbsp;-A</code>.
+
+<h2>Rarities</h2>
+
+<p>There are a few other files you may occasionally find in a CVS/ subdirectory:
+
+<ul>
+<li>CVS/Checkin.prog, CVS/Update.prog
+<li>CVS/Notify, CVS/Notify.tmp
+<li>CVS/Base/, CVS/Baserev, CVS/Baserev.tmp
+<li>CVS/Template
+</ul>
+
+<p>These files are usually not the cause of problems, so I'm just listing
+them (see <a href="#CVS_Reference">CVS Reference</a> for their full descriptions).
+
+<h2>Portability And Future Extension</h2>
+
+<p>As features are added to CVS, new files (not listed here) may appear in
+working copy administrative areas. As new files are added, they'll
+probably be documented in the Cederqvist manual, in the node
+<cite>Working Directory Storage</cite>. You can also start looking in
+src/cvs.h in the source distribution, if you prefer to learn from code.
+
+<p>Finally, note that all CVS/* files - present and future - use whatever
+line-ending convention is appropriate for the working copy's local
+system (for example, LF for Unix or CRLF for Windows). This means that
+if you transport a working copy from one kind of machine to the other,
+CVS won't be able to handle it (but then, you'd have other problems,
+because the revision-controlled files themselves would have the wrong
+line-end conventions for their new location).
+
+<p><hr>
+Node:<a name="Repository_Permissions">Repository Permissions</a>,
+Previous:<a rel=previous href="#The_Working_Copy_Administrative_Area">The Working Copy Administrative Area</a>,
+Up:<a rel=up href="#The_Usual_Suspects">The Usual Suspects</a>
+<br>
+
+<h3>Repository Permissions</h3>
+
+<p>CVS does not require any particular repository permission scheme - it
+can handle a wide variety of permission arrangements. However, to avoid
+getting confusing behaviors, you should make sure your repository setup
+meets at least the following criteria:
+
+<ul>
+
+<li>If a user wants any kind of access at all - even read-only access - to
+a given subdirectory of the repository, she usually needs file
+system-level write permission to that subdirectory. This is necessary
+because CVS creates temporary lock files in the repository to ensure
+data consistency. Even read-only operations (such as checkout or
+update) create locks, to signal that they need the data to stay in one
+state until they're done.
+
+<p>As noted in <a href="#Repository_Administration">Repository Administration</a>, you can get around this
+writeability requirement by setting the LockDir parameter in
+CVSROOT/config, like this:
+
+<pre>LockDir=/usr/local/cvslocks
+</pre>
+
+<p>Of course, then you would need to make sure the directory
+/usr/local/cvslocks is writeable by all CVS users. Either way, most CVS
+operations, including read-only ones, are going to require a writeable
+directory somewhere. By default, that directory is the project's
+repository; if you're very security conscious, you can change it to be
+somewhere else.
+
+</p><li>Make sure the CVSROOT/history file is world-writeable (if it exists at
+all). If the history file exists, most CVS operations attempt to append
+a record to it; if the attempt fails, the operation exits with an error.
+
+<p>Unfortunately (and inexplicably), the history file is not born
+world-writeable when you create a new repository with cvs init. At
+least with the current version of CVS, you should explicitly change its
+permissions after you create a new repository (or just remove it, if you
+want to disable history logging entirely).
+
+<p>(This problem may go away - I just now submitted a patch to the CVS
+maintainers that makes the history file world-writeable when you
+initialize a new repository. So perhaps if you get a more recent
+version of CVS than the one available now (September 1999), it won't be
+a problem for you.)
+
+</p><li>For security purposes, you almost certainly want to make sure that most
+CVS users do not have Unix-level write access to the CVSROOT directory
+in the repository. If someone has checkin access to CVSROOT, they can
+edit commitinfo, loginfo, or any of the other trigger files to invoke a
+program of their choice - they could even commit a new program if the
+one they want isn't on the system already. Therefore, you should assume
+that anyone who has commit access to CVSROOT is able to run arbitrary
+commands on the system.
+
+</ul>
+
+<p><hr>
+Node:<a name="General_Troubleshooting_Tips">General Troubleshooting Tips</a>,
+Next:<a rel=next href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>,
+Previous:<a rel=previous href="#The_Usual_Suspects">The Usual Suspects</a>,
+Up:<a rel=up href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>
+<br>
+
+<h2>General Troubleshooting Tips</h2>
+
+<p>The bulk of this chapter is organized into a series of questions and
+answers, similar to an Internet FAQ (Frequently Asked Questions)
+document. These are all based on actual CVS experiences. But before we
+look at individual cases, let's take a moment to consider CVS
+troubleshooting from a more general point of view.
+
+<p>The first step in solving a CVS problem is usually to determine whether
+it's a working copy or repository problem. The best technique for doing
+that, not surprisingly, is to see if the problem occurs in working
+copies other than the one where it was first noticed. If it does, it's
+likely a repository issue; otherwise, it's probably just a local issue.
+
+<p>Working copy problems tend to be encountered more frequently, not
+because working copies are somehow less reliable than repositories, but
+because each repository usually has many working copies. Although most
+working copy knots can be untied with enough patience, you may
+occasionally find it more time-efficient simply to delete the working
+copy and check it out again.
+
+<p>Of course, if checking out again takes too long, or there is
+considerable uncommitted state in the working copy that you don't want
+to lose, or if you just want to know what's wrong, it's worth digging
+around to find the cause of the problem. When you start digging around,
+one of the first places to look is in the CVS/ subdirectories. Check
+the file contents and the file permissions. Very occasionally, the
+permissions can mysteriously become read-only or even unreadable. (I
+suspect this is caused by users accidentally mistyping Unix commands
+rather than any mistake on CVS's part.)
+
+<p>Repository problems are almost always caused by incorrect file and
+directory permissions. If you suspect a problem may be due to bad
+repository permissions, first find out the effective repository user ID
+of the person who's having the trouble. For all local and most remote
+users, this is either their regular username or the username they
+specified when they checked out their working copy. If they're using
+the pserver method with user-aliasing (see the section <a href="#Anonymous_Access">Anonymous Access</a> in <a href="#Repository_Administration">Repository Administration</a>), the effective user ID is
+the one on the right in the CVSROOT/passwd file. Failure to discover
+this early on can cause you to waste a lot of time debugging the wrong
+thing.
+
+<p>And now, without further ado...
+
+<p><hr>
+Node:<a name="Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>,
+Previous:<a rel=previous href="#General_Troubleshooting_Tips">General Troubleshooting Tips</a>,
+Up:<a rel=up href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>
+<br>
+
+<h2>Some Real Life Problems (With Solutions)</h2>
+
+<p>All of these situations are ones I've encountered in my real-life
+adventures as a CVS troubleshooter (plus a few items that are not really
+problems, just questions that I've heard asked so often that they may as
+well be answered here). The list is meant to be fairly comprehensive,
+and it may repeat material you've seen in earlier chapters.
+
+<p>The situations are listed according to how frequently they seem to
+arise, with the most common ones first.
+
+<ul>
+<li><a href="#CVS_says_it_is_waiting_for_a_lock__what_does_that_mean_">CVS says it is waiting for a lock; what does that mean?</a>:
+<li><a href="#CVS_claims_a_file_is_failing_Up-To-Date_check__what_do_I_do_">CVS claims a file is failing Up-To-Date check; what do I do?</a>:
+<li><a href="#The_pserver_access_method_is_not_working">The pserver access method is not working</a>:
+<li><a href="#The_pserver_access_method_is_STILL_not_working">The pserver access method is STILL not working</a>:
+<li><a href="#My_commits_seem_to_happen_in_pieces_instead_of_atomically">My commits seem to happen in pieces instead of atomically</a>:
+<li><a href="#CVS_keeps_changing_file_permissions__why_does_it_do_that_">CVS keeps changing file permissions; why does it do that?</a>:
+<li><a href="#CVS_on_Windows_complains_it_cannot_find_my_.cvspass_file__why_">CVS on Windows complains it cannot find my .cvspass file; why?</a>:
+<li><a href="#My_working_copy_is_on_several_different_branches__help_">My working copy is on several different branches; help?</a>:
+<li><a href="#When_I_do_export_-d_I_sometimes_miss_recent_commits">When I do export -d I sometimes miss recent commits</a>:
+<li><a href="#I_get_an_error_about_val-tags__what_should_I_do_">I get an error about val-tags; what should I do?</a>:
+<li><a href="#I_am_having_problems_with_sticky_tags__how_do_I_get_rid_of_them_">I am having problems with sticky tags; how do I get rid of them?</a>:
+<li><a href="#Checkouts_updates_exit_with_error_saying_cannot_expand_modules">Checkouts/updates exit with error saying cannot expand modules</a>:
+<li><a href="#I_cannot_seem_to_turn_off_watches">I cannot seem to turn off watches</a>:
+<li><a href="#My_binary_files_are_messed_up">My binary files are messed up</a>:
+<li><a href="#CVS_is_not_doing_line-end_conversion_correctly">CVS is not doing line-end conversion correctly</a>:
+<li><a href="#I_need_to_remove_a_subdirectory_in_my_project__how_do_I_do_it_">I need to remove a subdirectory in my project; how do I do it?</a>:
+<li><a href="#Can_I_copy_.cvspass_files_or_portions_of_them_">Can I copy .cvspass files or portions of them?</a>:
+<li><a href="#I_just_committed_some_files_with_the_wrong_log_message">I just committed some files with the wrong log message</a>:
+<li><a href="#I_need_to_move_files_around_without_losing_revision_history">I need to move files around without losing revision history</a>:
+<li><a href="#How_can_I_get_a_list_of_all_tags_in_a_project_">How can I get a list of all tags in a project?</a>:
+<li><a href="#How_can_I_get_a_list_of_all_projects_in_a_repository_">How can I get a list of all projects in a repository?</a>:
+<li><a href="#Some_commands_fail_remotely_but_not_locally__how_should_I_debug_">Some commands fail remotely but not locally; how should I debug?</a>:
+<li><a href="#I_do_not_see_my_problem_covered_in_this_chapter">I do not see my problem covered in this chapter</a>:
+<li><a href="#I_think_I_have_discovered_a_bug_in_CVS__what_do_I_do_">I think I have discovered a bug in CVS; what do I do?</a>:
+<li><a href="#I_have_implemented_a_new_feature_for_CVS__to_whom_do_I_send_it_">I have implemented a new feature for CVS; to whom do I send it?</a>:
+<li><a href="#How_can_I_keep_up_with_changes_to_CVS_">How can I keep up with changes to CVS?</a>:
+</ul>
+
+<p><hr>
+Node:<a name="CVS_says_it_is_waiting_for_a_lock__what_does_that_mean_">CVS says it is waiting for a lock; what does that mean?</a>,
+Next:<a rel=next href="#CVS_claims_a_file_is_failing_Up-To-Date_check__what_do_I_do_">CVS claims a file is failing Up-To-Date check; what do I do?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>CVS says it is waiting for a lock; what does that mean?</h3>
+
+<p>If you see a message like this
+
+<pre>cvs update: [22:58:26] waiting for qsmith's lock in /usr/local/newrepos/myproj
+</pre>
+
+<p>it means you're trying to access a subdirectory of the repository that
+is locked by some other CVS process at the moment. A process is being
+run in that directory so it may not be in a consistent state for other
+CVS processes to use.
+
+<p>However, if the wait message persists for a long time, it probably means
+that a CVS process failed to clean up after itself, for whatever reason.
+It can happen when CVS dies suddenly and unexpectedly, say, due to a
+power failure on the repository machine.
+
+<p>The solution is to remove the lock files by hand from the repository
+subdirectory in question. Go into that part of the repository and look
+for files named <code>#cvs.lock</code> or that begin with <code>#cvs.wfl</code> or
+<code>#cvs.rfl</code>. Compare the file's timestamps with the start times of
+any currently running CVS processes. If the files could not possibly
+have been created by any of those processes, it's safe to delete them.
+The waiting CVS processes eventually notice when the lock files are gone
+- this should take about 30 seconds - and allow the requested
+operation to proceed.
+
+<p>See the node <cite>Locks</cite> in the Cederqvist manual for more details.
+
+<p><hr>
+Node:<a name="CVS_claims_a_file_is_failing_Up-To-Date_check__what_do_I_do_">CVS claims a file is failing Up-To-Date check; what do I do?</a>,
+Next:<a rel=next href="#The_pserver_access_method_is_not_working">The pserver access method is not working</a>,
+Previous:<a rel=previous href="#CVS_says_it_is_waiting_for_a_lock__what_does_that_mean_">CVS says it is waiting for a lock; what does that mean?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>CVS claims a file is failing Up-To-Date check; what do I do?</h3>
+
+<p>Don't panic - it just means that the file has changed in the repository
+since the last time you checked it out or updated it.
+
+<p>Run <code>cvs&nbsp;update</code> on the file to merge in the changes from the
+repository. If the received changes conflict with your local changes,
+edit the file to resolve the conflict. Then try your commit again - it
+will succeed, barring the possibility that someone committed yet another
+revision while you were busy merging the last changes.
+
+<p><hr>
+Node:<a name="The_pserver_access_method_is_not_working">The pserver access method is not working</a>,
+Next:<a rel=next href="#The_pserver_access_method_is_STILL_not_working">The pserver access method is STILL not working</a>,
+Previous:<a rel=previous href="#CVS_claims_a_file_is_failing_Up-To-Date_check__what_do_I_do_">CVS claims a file is failing Up-To-Date check; what do I do?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>The pserver access method is not working</h3>
+
+<p>The most common, less obvious cause of this problem is that you forgot
+to list the repository using an <code>--allow-root</code> option in your inetd
+configuration file.
+
+<p>Recall this example /etc/inetd.conf line from <a href="#Repository_Administration">Repository Administration</a>:
+
+<pre>cvspserver stream tcp nowait root /usr/local/bin/cvs cvs \
+ --allow-root=/usr/local/newrepos pserver
+</pre>
+
+<p>(In the actual file, this is all one long line, with no backslash.)
+
+<p>The <code>--allow-root=/usr/local/newrepos</code> portion is a security
+measure, to make sure that people can't use CVS to get pserver access to
+repositories that are not supposed to be served remotely. Any
+repository intended to be accessible via pserver must be mentioned in an
+<code>--allow-root</code>. You can have as many different <code>--allow-root</code>
+options as you need for all of your system's repositories (or anyway, as
+many as you want until you bump up against your inetd's argument limit).
+
+<p>See <a href="#Repository_Administration">Repository Administration</a> for more details on setting up the
+password-authenticating server.
+
+<p><hr>
+Node:<a name="The_pserver_access_method_is_STILL_not_working">The pserver access method is STILL not working</a>,
+Next:<a rel=next href="#My_commits_seem_to_happen_in_pieces_instead_of_atomically">My commits seem to happen in pieces instead of atomically</a>,
+Previous:<a rel=previous href="#The_pserver_access_method_is_not_working">The pserver access method is not working</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>The pserver access method is STILL not working</h3>
+
+<p>Okay, if the problem is not a missing <code>--allow-root</code>, here are a
+few other possibilities:
+
+<ul>
+
+<li>The user has no entry in the CVSROOT/passwd file, and the CVSROOT/config
+file has SystemAuth=no so CVS will not fall back on the system password
+file (or SystemAuth=yes, but the system password file has no entry for
+this user either).
+
+<li>The user has an entry in the CVSROOT/passwd file, but there is no user
+by that name on the system, and the CVSROOT/passwd entry does not map
+the user to any valid system username.
+
+<li>The password is wrong (but CVS is usually pretty good about informing
+the user of this, so that's probably not the answer).
+
+<li>Everything is set up correctly with the passwd files and in
+/etc/inetd.conf, but you forgot an entry like this in /etc/services:
+
+<pre>cvspserver 2401/tcp
+</pre>
+
+<p>so inetd is not even listening on that port to pass connections off to
+CVS.
+
+</ul>
+
+<p><hr>
+Node:<a name="My_commits_seem_to_happen_in_pieces_instead_of_atomically">My commits seem to happen in pieces instead of atomically</a>,
+Next:<a rel=next href="#CVS_keeps_changing_file_permissions__why_does_it_do_that_">CVS keeps changing file permissions; why does it do that?</a>,
+Previous:<a rel=previous href="#The_pserver_access_method_is_STILL_not_working">The pserver access method is STILL not working</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>My commits seem to happen in pieces instead of atomically</h3>
+
+<p>That's because CVS commits happen in pieces, not atomically. :-)
+
+<p>More specifically, CVS operations happen directory by directory. When
+you do a commit (or an update, or anything else, for that matter)
+spanning multiple directories, CVS locks each corresponding repository
+directory in turn while it performs the operation for that directory.
+
+<p>For small- to medium-sized projects, this is rarely a problem - CVS
+manages to do its thing in each directory so quickly that you never
+notice the nonatomicity. Unfortunately, in large projects, scenarios
+like the following can occur (imagine this taking place in a project
+with at least two deep, many-filed subdirectories, A and B):
+
+<ol type=1 start=1>
+
+</p><li>User qsmith starts a commit, involving files from both subdirectories.
+CVS commits the files in B first (perhaps because qsmith specified the
+directories on the command line in that order).
+
+<li>User jrandom starts a cvs update. The update, for whatever reason,
+starts with working copy directory A (CVS makes no guarantees about the
+order in which it processes directories or files, if left to its own
+devices). Note that there is no locking contention, because qsmith is
+not active in A yet.
+
+<li>Then, qsmith's commit finishes B, moves on to A, and finishes A.
+
+<li>Finally, jrandom's update moves on to B and finishes it.
+
+</ol>
+
+<p>Clearly, when this is all over, jrandom's working copy reflects qsmith's
+changes to B but not A. Even though qsmith intended the changes to be
+committed as a single unit, it didn't happen that way. Now jrandom's
+working copy is in a state that qsmith never anticipated.
+
+<p>The solution, of course, is for jrandom to do another cvs update to
+fetch the uncaught changes from qsmith's commit. However, that assumes
+that jrandom has some way of finding out in the first place that he only
+got part of qsmith's changes.
+
+<p>There's no easy answer to this quandary. You simply have to hope that
+the inconsistent state of the working copy will somehow become apparent
+(maybe the software won't build, or jrandom and qsmith will have a
+conversation that's confusing until they realize what must have
+happened).
+
+<p>CVS's failure to provide <em>atomic</em> transaction guarantees is widely
+considered a bug. The only reason that locks are not made at the top
+level of the repository is that this would result in intolerably
+frequent lock contentions for large projects with many developers.
+Therefore, CVS has chosen the lesser of two evils, reducing the
+contention frequency but allowing the possibility of interleaved reads
+and writes. Someday, someone may modify CVS (say, speeding up
+repository operations) so that it doesn't have to choose between two
+evils; until then, we're stuck with nonatomic actions.
+
+<p>For more information, see the node <cite>Concurrency</cite> in the Cederqvist
+manual.
+
+<p><hr>
+Node:<a name="CVS_keeps_changing_file_permissions__why_does_it_do_that_">CVS keeps changing file permissions; why does it do that?</a>,
+Next:<a rel=next href="#CVS_on_Windows_complains_it_cannot_find_my_.cvspass_file__why_">CVS on Windows complains it cannot find my .cvspass file; why?</a>,
+Previous:<a rel=previous href="#My_commits_seem_to_happen_in_pieces_instead_of_atomically">My commits seem to happen in pieces instead of atomically</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>CVS keeps changing file permissions; why does it do that?</h3>
+
+<p>In general, CVS doesn't do a very good job of preserving permissions on
+files. When you import a project and then check it out, there is no
+guarantee that the file permissions in the new working copy will be the
+same as when the project was imported. More likely, the working copy
+files will be created with the same standard permissions that you
+normally get on newly created files.
+
+<p>However, there is at least one exception. If you want to store
+executable shell scripts in the project, you can keep them executable in
+all working copies by making the corresponding repository file
+executable:
+
+<pre>floss$ ls -l /usr/local/newrepos/someproj
+total 6
+-r--r--r-- 1 jrandom users 630 Aug 17 01:10 README.txt,v
+-r-xr-xr-x 1 jrandom users 1041 Aug 17 01:10 scrub.pl,v*
+-r--r--r-- 1 jrandom users 750 Aug 17 01:10 hello.c,v
+</pre>
+
+<p>Notice that although the file is executable, it is still read-only, as
+all repository files should be (remember that CVS works by making a
+temporary copy of the RCS file, doing everything in the copy, and then
+replacing the original with the copy when ready).
+
+<p>When you import or add an executable file, CVS preserves the executable
+bits, so if the permissions were correct from the start, you have
+nothing to worry about. However, if you accidentally add the file
+before making it executable, you must go into the repository and
+manually set the RCS file to be executable.
+
+<p>The repository permissions always dominate. If the file is
+nonexecutable in the repository, but executable in the working copy, the
+working copy file will also be nonexecutable after you do an update.
+Having your files' permissions silently change can be extremely
+frustrating. If this happens, first check the repository and see if you
+can solve it by setting the appropriate permissions on the corresponding
+RCS files.
+
+<p>A feature called <code>PreservePermissions</code> has recently been added to
+CVS that may alleviate some of these problems. However, using this
+feature can cause other unexpected results (which is why I'm not
+recommending it unconditionally here). Make sure you read the nodes
+<cite>config</cite> and <cite>Special Files</cite> in the Cederqvist before putting
+<code>PreservePermissions=yes</code> in CVSROOT/config.
+
+<p><hr>
+Node:<a name="CVS_on_Windows_complains_it_cannot_find_my_.cvspass_file__why_">CVS on Windows complains it cannot find my .cvspass file; why?</a>,
+Next:<a rel=next href="#My_working_copy_is_on_several_different_branches__help_">My working copy is on several different branches; help?</a>,
+Previous:<a rel=previous href="#CVS_keeps_changing_file_permissions__why_does_it_do_that_">CVS keeps changing file permissions; why does it do that?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>CVS on Windows complains it cannot find my .cvspass file; why?</h3>
+
+<p>For pserver connections, CVS on the client side tries to find the
+.cvspass file in your home directory. Windows machines don't have a
+natural "home" directory, so CVS consults the environment variable
+<code>%HOME%</code>. However, you have to be very careful about how you set
+HOME. This will work:
+
+<pre>set HOME=C:
+</pre>
+
+<p>This will not:
+
+<pre>set HOME=C:\
+</pre>
+
+<p>That extra backslash is enough to confuse CVS, and it will be unable to
+open <code>C:\\.cvspass</code>.
+
+<p>So, the quick and permanent solution is to put
+
+<pre>set HOME=C:
+</pre>
+
+<p>into your autoexec.bat and reboot. CVS pserver should work fine after
+that.
+
+<p><hr>
+Node:<a name="My_working_copy_is_on_several_different_branches__help_">My working copy is on several different branches; help?</a>,
+Next:<a rel=next href="#When_I_do_export_-d_I_sometimes_miss_recent_commits">When I do export -d I sometimes miss recent commits</a>,
+Previous:<a rel=previous href="#CVS_on_Windows_complains_it_cannot_find_my_.cvspass_file__why_">CVS on Windows complains it cannot find my .cvspass file; why?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>My working copy is on several different branches; help?</h3>
+
+<p>You mean different subdirectories of your working copy somehow got on
+different branches? You probably ran updates with the -r flag, but from
+places other than the top level of the working copy.
+
+<p>No big deal. If you want to return to the trunk, just run this
+
+<pre>cvs update -r HEAD
+</pre>
+
+<p>or this
+
+<pre>cvs update -A
+</pre>
+
+<p>from the top directory. Or, if you want to put the whole working copy
+on one of the branches, do this:
+
+<pre>cvs update -r Branch_Name
+</pre>
+
+<p>There's nothing necessarily wrong with having one or two subdirectories
+of your working copy on a different branch than the rest of it, if you
+need to do some temporary work on that branch just in those locations.
+However, it's usually a good idea to switch them back when you're done
+- life is much less confusing when your whole working copy is on the
+same line of development.
+
+<p><hr>
+Node:<a name="When_I_do_export_-d_I_sometimes_miss_recent_commits">When I do export -d I sometimes miss recent commits</a>,
+Next:<a rel=next href="#I_get_an_error_about_val-tags__what_should_I_do_">I get an error about val-tags; what should I do?</a>,
+Previous:<a rel=previous href="#My_working_copy_is_on_several_different_branches__help_">My working copy is on several different branches; help?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>When I do export -d I sometimes miss recent commits</h3>
+
+<p>This is due to a clock difference between the repository and local
+machines. You can solve it by resetting one or both of the clocks, or
+specifying a different date as the argument to -D. It's perfectly
+acceptable to specify a date in the future (such as -D tomorrow), if
+that's what it takes to compensate for the time difference.
+
+<p><hr>
+Node:<a name="I_get_an_error_about_val-tags__what_should_I_do_">I get an error about val-tags; what should I do?</a>,
+Next:<a rel=next href="#I_am_having_problems_with_sticky_tags__how_do_I_get_rid_of_them_">I am having problems with sticky tags; how do I get rid of them?</a>,
+Previous:<a rel=previous href="#When_I_do_export_-d_I_sometimes_miss_recent_commits">When I do export -d I sometimes miss recent commits</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I get an error about val-tags; what should I do?</h3>
+
+<p>If you see an error like this:
+
+<pre>cvs [export aborted]: cannot write /usr/local/myproj/CVSROOT/val-tags: \
+ Operation not permitted
+</pre>
+
+<p>it means the user CVS is running as does not have permission to write to
+the CVSROOT/val-tags file. This file stores valid tag names, to give
+CVS a fast way to determine what tags are valid. Unfortunately, CVS
+sometimes modifies this file even for operations that are read-only with
+respect to the repository, such as checking out a project.
+
+<p>This is a bug in CVS and may be fixed by the time you read this. Until
+then, the solution is either to make val-tags world-writeable or,
+failing that, to remove it or change its ownership to the user running
+the CVS operation. (You'd think just changing the permissions would be
+enough, but on several occasions I've had to change the ownership, too.)
+
+<p><hr>
+Node:<a name="I_am_having_problems_with_sticky_tags__how_do_I_get_rid_of_them_">I am having problems with sticky tags; how do I get rid of them?</a>,
+Next:<a rel=next href="#Checkouts_updates_exit_with_error_saying_cannot_expand_modules">Checkouts/updates exit with error saying cannot expand modules</a>,
+Previous:<a rel=previous href="#I_get_an_error_about_val-tags__what_should_I_do_">I get an error about val-tags; what should I do?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I am having problems with sticky tags; how do I get rid of them?</h3>
+
+<p>Various CVS operations cause the working copy to have a <dfn>sticky
+tag</dfn>, meaning a single tag that corresponds to each revision for each
+file (in the case of a branch, the sticky tag is applied to any new
+files added in the working copy). You get a sticky tagged working area
+whenever you check out or update by tag or date, for example:
+
+<pre>floss$ cvs update -r Tag_Name
+</pre>
+
+<p>or
+
+<pre>floss$ cvs checkout -D '1999-08-16'
+</pre>
+
+<p>If a date or a nonbranch tag name is used, the working copy will be a
+frozen snapshot of that moment in the project's history - so naturally
+you will not be able to commit any changes from it.
+
+<p>To remove a sticky tag, run update with the -A flag
+
+<pre>floss$ cvs update -A
+</pre>
+
+<p>which clears all the sticky tags and updates each file to its most
+recent trunk revision.
+
+<p><hr>
+Node:<a name="Checkouts_updates_exit_with_error_saying_cannot_expand_modules">Checkouts/updates exit with error saying cannot expand modules</a>,
+Next:<a rel=next href="#I_cannot_seem_to_turn_off_watches">I cannot seem to turn off watches</a>,
+Previous:<a rel=previous href="#I_am_having_problems_with_sticky_tags__how_do_I_get_rid_of_them_">I am having problems with sticky tags; how do I get rid of them?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>Checkouts/updates exit with error saying cannot expand modules</h3>
+
+<p>This is just a case of a bad error message in CVS; probably someone will
+get around to fixing it sooner or later, but meanwhile it may bite you.
+The error message looks something like this:
+
+<pre>floss$ cvs co -d bwf-misc user-space/bwf/writings/misc
+cvs server: cannot find module `user-space/bwf/writings/misc' - ignored
+cvs [checkout aborted]: cannot expand modules
+</pre>
+
+<p>CVS appears to be saying that there's something wrong with the
+CVSROOT/modules file. However, what's really going on is a permission
+problem in the repository. The directory I'm trying to check out isn't
+readable, or one of its parents isn't readable. In this case, it was a
+parent:
+
+<pre>floss$ ls -ld /usr/local/cvs/user-space/bwf
+
+drwx------ 19 bwf users 1024 Aug 17 01:24 bwf/
+</pre>
+
+<p>Don't let that egregiously wrong error message fool you - this is a
+repository permission problem.
+
+<p><hr>
+Node:<a name="I_cannot_seem_to_turn_off_watches">I cannot seem to turn off watches</a>,
+Next:<a rel=next href="#My_binary_files_are_messed_up">My binary files are messed up</a>,
+Previous:<a rel=previous href="#Checkouts_updates_exit_with_error_saying_cannot_expand_modules">Checkouts/updates exit with error saying cannot expand modules</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I cannot seem to turn off watches</h3>
+
+<p>You probably did
+
+<pre>floss$ cvs watch remove
+</pre>
+
+<p>on all the files, but forgot to also do:
+
+<pre>floss$ cvs watch off
+</pre>
+
+<p>A hint for diagnosing watch problems: Sometimes it can be immensely
+clarifying to just go into the repository and examine the CVS/fileattr
+files directly. See <a href="#Repository_Administration">Repository Administration</a> for more
+information about them.
+
+<p><hr>
+Node:<a name="My_binary_files_are_messed_up">My binary files are messed up</a>,
+Next:<a rel=next href="#CVS_is_not_doing_line-end_conversion_correctly">CVS is not doing line-end conversion correctly</a>,
+Previous:<a rel=previous href="#I_cannot_seem_to_turn_off_watches">I cannot seem to turn off watches</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>My binary files are messed up</h3>
+
+<p>Did you remember to use -kb when you added them? If not, CVS may have
+performed line-end conversion or RCS keyword substitution on them. The
+easiest solution is usually to mark them as binary
+
+<pre>floss$ cvs admin -kb foo.gif
+</pre>
+
+<p>and then commit a fixed version of the file. CVS will not corrupt the
+new commit or any of the commits thereafter, because it now knows the
+file is binary.
+
+<p><hr>
+Node:<a name="CVS_is_not_doing_line-end_conversion_correctly">CVS is not doing line-end conversion correctly</a>,
+Next:<a rel=next href="#I_need_to_remove_a_subdirectory_in_my_project__how_do_I_do_it_">I need to remove a subdirectory in my project; how do I do it?</a>,
+Previous:<a rel=previous href="#My_binary_files_are_messed_up">My binary files are messed up</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>CVS is not doing line-end conversion correctly</h3>
+
+<p>If you're running the CVS client on a non-Unix platform and are not
+getting the line-end conventions that you want in some working copy
+files, it's usually because they were accidentally added with -kb when
+they shouldn't have been. This can be fixed in the repository with,
+believe it or not, the command:
+
+<pre>floss$ cvs admin -kkv FILE
+</pre>
+
+<p>The -kkv means to do normal keyword substitution and implies normal
+line-end conversions as well. (Internally, CVS is a bit confused about
+the difference between keyword substitution and line-end conversion.
+This confusion is reflected in the way the -k options can control both
+parameters.)
+
+<p>Unfortunately, that admin command only fixes the file in the repository
+- your working copy still thinks the file is binary. You can hand edit
+the CVS/Entries line for that file, removing the -kb, but that won't
+solve the problem for any other working copies out there.
+
+<p><hr>
+Node:<a name="I_need_to_remove_a_subdirectory_in_my_project__how_do_I_do_it_">I need to remove a subdirectory in my project; how do I do it?</a>,
+Next:<a rel=next href="#Can_I_copy_.cvspass_files_or_portions_of_them_">Can I copy .cvspass files or portions of them?</a>,
+Previous:<a rel=previous href="#CVS_is_not_doing_line-end_conversion_correctly">CVS is not doing line-end conversion correctly</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I need to remove a subdirectory in my project; how do I do it?</h3>
+
+<p>Well, you can't exactly remove the subdirectory, but you can remove all
+of the files in it (first remove them, then cvs remove them, and then
+commit). Once the directory is empty, people can have it automatically
+pruned out of their working copies by passing the -P flag to update.
+
+<p><hr>
+Node:<a name="Can_I_copy_.cvspass_files_or_portions_of_them_">Can I copy .cvspass files or portions of them?</a>,
+Next:<a rel=next href="#I_just_committed_some_files_with_the_wrong_log_message">I just committed some files with the wrong log message</a>,
+Previous:<a rel=previous href="#I_need_to_remove_a_subdirectory_in_my_project__how_do_I_do_it_">I need to remove a subdirectory in my project; how do I do it?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>Can I copy .cvspass files or portions of them?</h3>
+
+<p>Yes, you can. You can copy <code>.cvspass</code> files from machine to
+machine, and you can even copy individual lines from one .cvspass file
+to another. For high-latency servers, this may be faster than running
+cvs login from each working copy machine.
+
+<p>Remember that if you transport a .cvspass file between two machines with
+different line-ending conventions, it probably won't work (of course,
+you can probably do the line-end conversion manually without too much
+trouble).
+
+<p><hr>
+Node:<a name="I_just_committed_some_files_with_the_wrong_log_message">I just committed some files with the wrong log message</a>,
+Next:<a rel=next href="#I_need_to_move_files_around_without_losing_revision_history">I need to move files around without losing revision history</a>,
+Previous:<a rel=previous href="#Can_I_copy_.cvspass_files_or_portions_of_them_">Can I copy .cvspass files or portions of them?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I just committed some files with the wrong log message</h3>
+
+<p>You don't need to hand-edit anything in the repository to solve this.
+Just run admin with the -m flag. Remember to have no space between -m
+and its argument, and to quote the replacement log message as you would
+a normal one:
+
+<pre>floss$ cvs admin -m1.17:'I take back what I said about the customer.' hello.c
+</pre>
+
+<p><hr>
+Node:<a name="I_need_to_move_files_around_without_losing_revision_history">I need to move files around without losing revision history</a>,
+Next:<a rel=next href="#How_can_I_get_a_list_of_all_tags_in_a_project_">How can I get a list of all tags in a project?</a>,
+Previous:<a rel=previous href="#I_just_committed_some_files_with_the_wrong_log_message">I just committed some files with the wrong log message</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I need to move files around without losing revision history</h3>
+
+<p>In the repository, copy (don't move) the RCS files to the desired new
+location in the project. They must remain in their old locations as
+well. Then, in a working copy, do:
+
+<pre>floss$ rm oldfile1 oldfile2 ...
+floss$ cvs remove oldfile1 oldfile2 ...
+floss$ cvs commit -m removed from here oldfile1 oldfile2 ...
+</pre>
+
+<p>When people do updates after that, CVS correctly removes the old files
+and brings the new files into the working copies just as though they had
+been added to the repository in the usual way (except that they'll be at
+unusually high revision numbers for supposedly new files).
+
+<p><hr>
+Node:<a name="How_can_I_get_a_list_of_all_tags_in_a_project_">How can I get a list of all tags in a project?</a>,
+Next:<a rel=next href="#How_can_I_get_a_list_of_all_projects_in_a_repository_">How can I get a list of all projects in a repository?</a>,
+Previous:<a rel=previous href="#I_need_to_move_files_around_without_losing_revision_history">I need to move files around without losing revision history</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>How can I get a list of all tags in a project?</h3>
+
+<p>Currently, there is no convenient way to do this in CVS. The lack is
+sorely felt by all users, and I believe work is under way to make this
+feature available. By the time you read this, a <code>cvs&nbsp;tags</code>
+command or something similar may be available.
+
+<p>Until then, there are workarounds. You can run cvs log -h and read the
+sections of the output following the header <code>symbolic names:</code>. Or,
+if you happen to be on the repository machine, you can just look at the
+beginnings of some of the RCS files directly in the repository. All of
+the tags (branches and nonbranches) are listed in the <code>symbols</code>
+field:
+
+<pre>floss$ head /usr/local/newrepos/hello.c,v
+head 2.0;
+access;
+symbols
+ Release_1_0:1.22
+ Exotic_Greetings-2:1.21
+ merged-Exotic_Greetings-1:1.21
+ Exotic_Greetings-1:1.21
+ merged-Exotic_Greetings:1.21
+ Exotic_Greetings-branch:1.21.0.2
+ Root-of-Exotic_Greetings:1.21
+ start:1.1.1.1
+ jrandom:1.1.1;
+locks; strict;
+comment @ * @;
+</pre>
+
+<p><hr>
+Node:<a name="How_can_I_get_a_list_of_all_projects_in_a_repository_">How can I get a list of all projects in a repository?</a>,
+Next:<a rel=next href="#Some_commands_fail_remotely_but_not_locally__how_should_I_debug_">Some commands fail remotely but not locally; how should I debug?</a>,
+Previous:<a rel=previous href="#How_can_I_get_a_list_of_all_tags_in_a_project_">How can I get a list of all tags in a project?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>How can I get a list of all projects in a repository?</h3>
+
+<p>As with getting a list of tags, this is not implemented in the most
+current version of CVS, but it's highly likely that it will be
+implemented soon. I imagine the command will be called cvs list with a
+short form of cvs ls, and it probably will both parse the modules file
+and list the repository subdirectories.
+
+<p>In the meantime, examining the CVSROOT/modules file (either directly or
+by running cvs checkout -c) is probably your best bet. However, if no
+one has explicitly made a module for a particular project, it won't show
+up there.
+
+<p><hr>
+Node:<a name="Some_commands_fail_remotely_but_not_locally__how_should_I_debug_">Some commands fail remotely but not locally; how should I debug?</a>,
+Next:<a rel=next href="#I_do_not_see_my_problem_covered_in_this_chapter">I do not see my problem covered in this chapter</a>,
+Previous:<a rel=previous href="#How_can_I_get_a_list_of_all_projects_in_a_repository_">How can I get a list of all projects in a repository?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>Some commands fail remotely but not locally; how should I debug?</h3>
+
+<p>Sometimes there's a problem in the communication between the client and
+the server. If so, it's a bug in CVS, but how would you go about
+tracking down such a thing?
+
+<p>CVS gives you a way to watch the protocol between the client and server.
+Before you run the command on the local (working copy) machine, set the
+environment variable <code>CVS_CLIENT_LOG</code>. Here's how in Bourne shell
+syntax:
+
+<pre>floss$ CVS_CLIENT_LOG=clog; export CVS_CLIENT_LOG
+</pre>
+
+<p>Once that variable is set, CVS will record all communications between
+client and server in two files whose names are based on the variable's
+value:
+
+<pre>floss$ ls
+CVS/ README.txt a-subdir/ b-subdir/ foo.gif hello.c
+floss$ cvs update
+? clog.in
+? clog.out
+cvs server: Updating .
+cvs server: Updating a-subdir
+cvs server: Updating a-subdir/subsubdir
+cvs server: Updating b-subdir
+floss$ ls
+CVS/ a-subdir/ clog.in foo.gif
+README.txt b-subdir/ clog.out hello.c
+floss$
+</pre>
+
+<p>The <code>clog.in</code> file contains everything that the client sent into
+the server, and <code>clog.out</code> contains everything the server sent back
+out to the client. Here are the contents of clog.out, to give you a
+sense of what the protocol looks like:
+
+<pre>Valid-requests Root Valid-responses valid-requests Repository \
+Directory Max-dotdot Static-directory Sticky Checkin-prog Update-prog \
+Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged \
+Notify Questionable Case Argument Argumentx Global_option Gzip-stream \
+wrapper-sendme-rcsOptions Set expand-modules ci co update diff log add \
+remove update-patches gzip-file-contents status rdiff tag rtag import \
+admin export history release watch-on watch-off watch-add watch-remove \
+watchers editors init annotate noop
+ok
+M ? clog.in
+M ? clog.out
+E cvs server: Updating .
+E cvs server: Updating a-subdir
+E cvs server: Updating a-subdir/subsubdir
+E cvs server: Updating b-subdir
+ok
+</pre>
+
+<p>The clog.in file is even more complex, because it has to send revision
+numbers and other per-file information to the server.
+
+<p>There isn't space here to document the client/server protocol, but you
+can read the <code>cvsclient</code> Info pages that were distributed with CVS
+for a complete description. You may be able to figure out a good deal
+of it just from reading the raw protocol itself. Although you probably
+won't find yourself using client logging until you've eliminated all of
+the other possible causes of a problem, it is an invaluable tool for
+finding out what's really going on between the client and server.
+
+<p><hr>
+Node:<a name="I_do_not_see_my_problem_covered_in_this_chapter">I do not see my problem covered in this chapter</a>,
+Next:<a rel=next href="#I_think_I_have_discovered_a_bug_in_CVS__what_do_I_do_">I think I have discovered a bug in CVS; what do I do?</a>,
+Previous:<a rel=previous href="#Some_commands_fail_remotely_but_not_locally__how_should_I_debug_">Some commands fail remotely but not locally; how should I debug?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I do not see my problem covered in this chapter</h3>
+
+<p>Email an accurate and complete description of your problem to
+<a href="mailto:info-cvs@gnu.org">info-cvs@gnu.org</a>, the CVS discussion list. Its members are
+located in many different time zones, and I've usually gotten a response
+within an hour or two of sending a question. Please join the list by
+sending email to <a href="mailto:info-cvs-request@gnu.org">info-cvs-request@gnu.org</a>, so you can help
+answer questions, too.
+
+<p><hr>
+Node:<a name="I_think_I_have_discovered_a_bug_in_CVS__what_do_I_do_">I think I have discovered a bug in CVS; what do I do?</a>,
+Next:<a rel=next href="#I_have_implemented_a_new_feature_for_CVS__to_whom_do_I_send_it_">I have implemented a new feature for CVS; to whom do I send it?</a>,
+Previous:<a rel=previous href="#I_do_not_see_my_problem_covered_in_this_chapter">I do not see my problem covered in this chapter</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I think I have discovered a bug in CVS; what do I do?</h3>
+
+<p>CVS is far from perfect - if you've already tried reading the manual
+and posting a question on the mailing list, and you still think you're
+looking at a bug, then you probably are.
+
+<p>Send as complete a description of the bug as you can to
+<a href="mailto:bug-cvs@gnu.org">bug-cvs@gnu.org</a> (you can also subscribe to that list; just use
+<a href="mailto:bug-cvs-request@gnu.org">bug-cvs-request@gnu.org</a> instead). Be sure to include the
+version number of CVS (both client and server versions, if applicable),
+and a recipe for reproducing the bug.
+
+<p>If you have written a patch to fix the bug, include it and mention on
+the subject line of your message that you have a patch. The maintainers
+will be very grateful.
+
+<p>(Further details about these procedures are outlined in the node
+<cite>BUGS</cite> in the Cederqvist manual and the file HACKING in the source
+distribution.)
+
+<p><hr>
+Node:<a name="I_have_implemented_a_new_feature_for_CVS__to_whom_do_I_send_it_">I have implemented a new feature for CVS; to whom do I send it?</a>,
+Next:<a rel=next href="#How_can_I_keep_up_with_changes_to_CVS_">How can I keep up with changes to CVS?</a>,
+Previous:<a rel=previous href="#I_think_I_have_discovered_a_bug_in_CVS__what_do_I_do_">I think I have discovered a bug in CVS; what do I do?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>I have implemented a new feature for CVS; to whom do I send it?</h3>
+
+<p>Same as with a bug: Send the patch to <a href="mailto:bug-cvs@gnu.org">bug-cvs@gnu.org</a>. Make
+sure you've read over the HACKING file first, though.
+
+<p><hr>
+Node:<a name="How_can_I_keep_up_with_changes_to_CVS_">How can I keep up with changes to CVS?</a>,
+Previous:<a rel=previous href="#I_have_implemented_a_new_feature_for_CVS__to_whom_do_I_send_it_">I have implemented a new feature for CVS; to whom do I send it?</a>,
+Up:<a rel=up href="#Some_Real_Life_Problems__With_Solutions_">Some Real Life Problems (With Solutions)</a>
+<br>
+
+<h3>How can I keep up with changes to CVS?</h3>
+
+<p>The troubleshooting techniques and known bugs described in this chapter
+are accurate as of (approximately) CVS Version 1.10.7. Things move fast
+in the CVS world, however. While I was writing the last few chapters,
+the unofficial mantle of CVS maintainership passed from Cyclic Software
+to SourceGear, Inc (<a href="http://www.sourcegear.com">http://www.sourcegear.com</a>), which purchased
+Cyclic. SourceGear has publicly announced its intention to take an
+active role in CVS maintainer-ship and has received Cyclic's approval,
+which is more or less enough to make it the "lead maintainer" of CVS as
+of right now. (The <a href="http://www.cyclic.com">http://www.cyclic.com</a> address will continue
+to work, however, so all of the URLs given previously in this book
+should remain valid.)
+
+<p>SourceGear is, at this very moment, busy organizing and cleaning up
+various patches that have been floating around, with the intention of
+incorporating many of them into CVS. Some of these patches will
+probably fix bugs listed previously, and others may afford new
+troubleshooting tools to CVS users.
+
+<p>The best way to stay up to date with what's going on is to read the NEWS
+file in your CVS distribution, watch the mailing lists, and look for
+changes to the Cederqvist manual and the online version of this book
+(<a href="http://cvsbook.red-bean.com">http://cvsbook.red-bean.com</a>).
+
+<p><hr>
+Node:<a name="CVS_Reference">CVS Reference</a>,
+Next:<a rel=next href="#Third-Party_Tools">Third-Party Tools</a>,
+Previous:<a rel=previous href="#Tips_And_Troubleshooting">Tips And Troubleshooting</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>CVS Reference</h1>
+
+<p>This chapter is a complete reference to CVS commands, repository
+administrative files, keyword substitution, run control files, working
+copy files, and environment variables - everything in CVS as of CVS
+version 1.10.7 (more accurately, as of August 20, 1999).
+
+<ul>
+<li><a href="#Commands_And_Options">Commands And Options</a>: All CVS global options and commands.
+<li><a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a>: CVS can maintain some text for you.
+<li><a href="#Repository_Administrative_Files">Repository Administrative Files</a>: Server-side files affecting CVS.
+<li><a href="#Run_Control_Files">Run Control Files</a>: Client-side files affecting CVS.
+<li><a href="#Working_Copy_Files">Working Copy Files</a>: Administrivia in the working copy.
+<li><a href="#Environment_Variables">Environment Variables</a>: Environment variables affecting CVS.
+</ul>
+
+<p><hr>
+Node:<a name="Commands_And_Options">Commands And Options</a>,
+Next:<a rel=next href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a>,
+Up:<a rel=up href="#CVS_Reference">CVS Reference</a>
+<br>
+
+<h2>Commands And Options</h2>
+
+<p>This section is a reference to all CVS commands. If you are not already
+familiar with the syntactic conventions shared by most CVS commands, you
+should probably read the relevant subsections before you look up any
+particular command.
+
+<ul>
+<li><a href="#Organization_And_Conventions">Organization And Conventions</a>: How to read this section.
+<li><a href="#General_Patterns_In_CVS_Commands">General Patterns In CVS Commands</a>: CVS commands share some properties.
+<li><a href="#Date_Formats">Date Formats</a>: CVS accepts a variety of date formats.
+<li><a href="#Global_Options">Global Options</a>: A list of all global options to CVS.
+<li><a href="#add">add</a>: The <code>add</code> command.
+<li><a href="#admin">admin</a>: The <code>admin</code> command.
+<li><a href="#annotate">annotate</a>: The <code>annotate</code> command.
+<li><a href="#checkout">checkout</a>: The <code>checkout</code> command.
+<li><a href="#commit">commit</a>: The <code>commit</code> command.
+<li><a href="#diff">diff</a>: The <code>diff</code> command.
+<li><a href="#edit">edit</a>: The <code>edit</code> command.
+<li><a href="#editors">editors</a>: The <code>editors</code> command.
+<li><a href="#export">export</a>: The <code>export</code> command.
+<li><a href="#gserver">gserver</a>: The <code>gserver</code> command.
+<li><a href="#history">history</a>: The <code>history</code> command.
+<li><a href="#import">import</a>: The <code>import</code> command.
+<li><a href="#init">init</a>: The <code>init</code> command.
+<li><a href="#kserver">kserver</a>: The <code>kserver</code> command.
+<li><a href="#log">log</a>: The <code>log</code> command.
+<li><a href="#login">login</a>: The <code>login</code> command.
+<li><a href="#logout">logout</a>: The <code>logout</code> command.
+<li><a href="#pserver">pserver</a>: The <code>pserver</code> command.
+<li><a href="#rdiff">rdiff</a>: The <code>rdiff</code> command.
+<li><a href="#release">release</a>: The <code>release</code> command.
+<li><a href="#remove">remove</a>: The <code>remove</code> command.
+<li><a href="#rtag">rtag</a>: The <code>rtag</code> command.
+<li><a href="#server">server</a>: The <code>server</code> command.
+<li><a href="#status">status</a>: The <code>status</code> command.
+<li><a href="#tag">tag</a>: The <code>tag</code> command.
+<li><a href="#unedit">unedit</a>: The <code>unedit</code> command.
+<li><a href="#update">update</a>: The <code>update</code> command.
+<li><a href="#watch">watch</a>: The <code>watch</code> command.
+<li><a href="#watchers">watchers</a>: The <code>watchers</code> command.
+</ul>
+
+<p><hr>
+Node:<a name="Organization_And_Conventions">Organization And Conventions</a>,
+Next:<a rel=next href="#General_Patterns_In_CVS_Commands">General Patterns In CVS Commands</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>Organization And Conventions</h3>
+
+<p>This section is organized alphabetically to make it easy for you to look
+up a particular command or option. The following conventions are used:
+
+<ul>
+
+<li>Arguments to commands and options are in all-capitalized letters in the
+synopsis that begins each explanation. (Note: in the treeware version
+of the book, meta-arguments are italicized as well as capitalized; due
+to the limitations of standard terminal fonts, I have omitted the
+italicization here.)
+
+<li>Optional items appear between square brackets: <code>[ ]</code>. (This works
+out okay because square brackets turn out not used in CVS syntaces.)
+
+<li>If you must choose one from a set, the choices are separated by bars,
+like this: <code>x|y|z</code>. (And therefore forward slashes (<code>/</code>)
+should be interpreted literally - they do not divide choices in a set.)
+
+<li>Plurals or ellipses indicate multiples, usually separated by whitespace.
+For example, FILES means one or more files, but [FILES] means zero or
+more files. The entry [&amp;MOD...] means an ampersand followed immediately
+by a module name, then whitespace, then maybe another ampersand-module,
+and so on, zero or more times. (The ellipsis is used because a plural
+would have left it unclear whether the ampersand is needed only the
+first time or once for each module.)
+
+<p>When a plural is parenthesized, as in FILE(S), it means that although
+technically there can be two or more files, usually there is only one.
+
+</p><li>REV is often used to stand for a revision argument. This is usually
+either a revision number or a tag name. There are very few places in
+CVS where you can use one but not the other, and those places are noted
+in the text.
+
+</ul>
+
+<p><hr>
+Node:<a name="General_Patterns_In_CVS_Commands">General Patterns In CVS Commands</a>,
+Next:<a rel=next href="#Date_Formats">Date Formats</a>,
+Previous:<a rel=previous href="#Organization_And_Conventions">Organization And Conventions</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>General Patterns In CVS Commands</h3>
+
+<p>CVS commands follow this form:
+
+<pre>cvs [GLOBAL_OPTIONS] COMMAND [OPTIONS] [FILES]
+</pre>
+
+<p>The second set of options is sometimes called <dfn>command options</dfn>.
+Because there are so many of them, though, I'll just call them "options"
+in most places to save space.
+
+<p>Many commands are meant to be run within a working copy and, therefore,
+may be invoked without file arguments. These commands default to all of
+the files in the current directory and below. So when I refer to the
+"file" or "files" in the text, I'm talking about the files on which CVS
+is acting. Depending on how you invoked CVS, these files may or may not
+have been explicitly mentioned on the command line.
+
+<p><hr>
+Node:<a name="Date_Formats">Date Formats</a>,
+Next:<a rel=next href="#Global_Options">Global Options</a>,
+Previous:<a rel=previous href="#General_Patterns_In_CVS_Commands">General Patterns In CVS Commands</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>Date Formats</h3>
+
+<p>Many options take a date argument. CVS accepts a wide variety of date
+formats - too many to list here. When in doubt, stick with the
+standard ISO 8601 format:
+
+<pre>1999-08-23
+</pre>
+
+<p>This means "23 August 1999" (in fact, "23 August 1999" is a perfectly
+valid date specifier too, as long as you remember to enclose it in
+double quotes). If you need a time of day as well, you can do this:
+
+<pre>"1999-08-23 21:20:30 CDT"
+</pre>
+
+<p>You can even use certain common English constructs, such as "now",
+"yesterday", and "12 days ago". In general, you can safely experiment
+with date formats; if CVS understands your format at all, it most likely
+will understand it in the way you intended. If it doesn't understand,
+it will exit with an error immediately.
+
+<p><hr>
+Node:<a name="Global_Options">Global Options</a>,
+Next:<a rel=next href="#add">add</a>,
+Previous:<a rel=previous href="#Date_Formats">Date Formats</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>Global Options</h3>
+
+<p>Here are all the global options to CVS.
+
+<h2><code>--allow-root=REPOSITORY</code></h2>
+
+<p>The alphabetically first global option is one that is virtually never
+used on the command line. The -allow-root option is used with the
+<code>pserver</code> command to allow authenticated access to the named
+repository (which is a repository top level, such as
+<code>/usr/local/newrepos</code>, not a project subdirectory such as
+<code>/usr/local/newrepos/myproj</code>).
+
+<p>This global option is virtually never used on the command line.
+Normally, the only place you'd ever use it is in /etc/inetd.conf files
+(see <a href="#Repository_Administration">Repository Administration</a>), which is also about the only
+place the <code>pserver</code> command is used.
+
+<p>Every repository to be accessed via <code>cvs&nbsp;pserver</code> on a given
+host needs a corresponding -allow-root option in
+<code>/etc/inetd.conf</code>. This is a security device, meant to ensure that
+people can't use a CVS pserver to gain access to private repositories.
+
+<p>(See <a href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a> also the node
+<cite>Password Authentication Server</cite> in the Cederqvist manual.)
+
+<h2><code>-a</code></h2>
+
+<p>This authenticates all communications with the server. This option has
+no effect unless you're connecting via the GSSAPI server (gserver).
+GSSAPI connections are not covered in this book, because they're still
+somewhat rarely used (although that may change). (See the nodes
+<cite>Global Options</cite> and <cite>GSSAPI Authenticated</cite> in the Cederqvist
+manual for more information.)
+
+<h2><code>-b</code> (Obsolete)</h2>
+
+<p>This option formerly specified the directory where the RCS binaries
+could be found. CVS now implements the RCS functions internally, so
+this option has no effect (it is kept only for backward compatibility).
+
+<h2><code>-d</code>&nbsp;REPOSITORY</h2>
+
+<p>This specifies the repository, which might be an absolute pathname or a
+more complex expression involving a connection method, username and
+host, and path. If it is an expression specifying a connection method,
+the general syntax is:
+
+<pre>:METHOD:USER@HOSTNAME:PATH_TO_REPOSITORY
+</pre>
+
+<p>Here are examples using each of the connection methods:
+
+<ul>
+
+<li><code>:ext:jrandom@floss.red-bean.com:/usr/local/newrepos</code> - Connects
+using <code>rsh</code>, <code>ssh</code>, or some other external connection program.
+If the <code>$CVS_RSH</code> environment variable is unset, this defaults to
+<code>rsh</code>; otherwise, it uses the value of that variable.
+
+<li><code>:server:jrandom@floss.red-bean.com:/usr/local/newrepos</code> - Like
+<code>:ext:</code>, but uses CVS's internal implementation of rsh. (This may
+not be available on all platforms.)
+
+<li><code>:pserver:jrandom@floss.red-bean.com:/usr/local/newrepos</code> -
+Connects using the password authenticating server (see <a href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a> in <a href="#Repository_Administration">Repository Administration</a>; see
+also the <a href="#login">login</a> command.)
+
+<li><code>:kserver:jrandom@floss.red-bean.com:/usr/local/newrepos</code> -
+Connects using Kerberos authentication.
+
+<li><code>:gserver:jrandom@floss.red-bean.com:/usr/local/newrepos</code> -
+Connects using GSSAPI authentication.
+
+<li><code>:fork:jrandom@floss.red-bean.com:/usr/local/newrepos</code> - Connects
+to a local repository, but using the client/server network protocol
+instead of directly accessing the repository files. This is useful for
+testing or debugging remote CVS behaviors from your local machine.
+
+<li><code>:local:jrandom@floss.red-bean.com:/usr/local/newrepos</code> -
+Accesses a local repository directly, as though only the absolute path
+to the repository had been given.
+
+</ul>
+
+<h2><code>-e</code>&nbsp;EDITOR</h2>
+
+<p>Invokes EDITOR for your commit message, if the commit message was not
+specified on the command line with the -m option. Normally, if you
+don't give a message with -m, CVS invokes the editor based on the
+<code>$CVSEDITOR</code>, <code>$VISUAL</code>, or <code>$EDITOR</code> environment
+variables, which it checks in that order. Failing that, it invokes the
+popular Unix editor <code>vi</code>.
+
+<p>If you pass both the -e global option and the -m option to commit, the
+-e is ignored in favor of the commit message given on the command line
+(that way it's safe to use -e in a <code>.cvsrc</code> file).
+
+<h2><code>-f</code></h2>
+
+<p>This global option suppresses reading of the <code>.cvsrc</code> file.
+
+<h2><code>--help</code>&nbsp;[COMMAND]&nbsp;or&nbsp;<code>-H</code>&nbsp;[COMMAND]</h2>
+
+<p>These two options are synonymous. If no COMMAND is specified, a basic
+usage message is printed to the standard output. If COMMAND is
+specified, a usage message for that command is printed.
+
+<h2><code>--help-options</code></h2>
+
+<p>Prints out a list of all global options to CVS, with brief explanations.
+
+<h2><code>--help-synonyms</code></h2>
+
+<p>Prints out a list of CVS commands and their short forms ("up" for
+"update", and so on).
+
+<h2><code>-l</code></h2>
+
+<p>Suppresses logging of this command in the <code>CVSROOT/history</code> file in
+the repository. The command is still executed normally, but no record
+of it is made in the history file.
+
+<h2><code>-n</code></h2>
+
+<p>Doesn't change any files in the working copy or in the repository. In
+other words, the command is executed as a "dry run" - CVS goes through
+most of the steps of the command but stops short of actually running it.
+
+<p>This is useful when you want to see what the command would have done had
+you actually run it. One common scenario is when you want to see what
+files in your working directory have been modified, but not do a full
+update (which would bring down changes from the repository). By running
+<code>cvs&nbsp;-n&nbsp;update</code>, you can see a summary of what's been done
+locally, without changing your working copy.
+
+<h2><code>-q</code></h2>
+
+<p>This tells CVS to be moderately quiet by suppressing the printing of
+unimportant informational messages. What is considered "important"
+depends on the command. For example, in updates, the messages that CVS
+normally prints on entering each subdirectory of the working copy are
+suppressed, but the one-line status messages for modified or updated
+files are still printed.
+
+<h2><code>-Q</code></h2>
+
+<p>This tells CVS to be very quiet, by suppressing all output except what
+is absolutely necessary to complete the command. Commands whose sole
+purpose is to produce some output (such as <code>diff</code> or
+<code>annotate</code>), of course, still give that output. However, commands
+that could have an effect independent of any messages that they may
+print (such as <code>update</code> or <code>commit</code>) print nothing.
+
+<h2><code>-r</code></h2>
+
+<p>Causes new working files to be created read-only (the same effect as
+setting the <code>$CVSREAD</code> environment variable).
+
+<p>If you pass this option, checkouts and updates make the files in your
+working copy read-only (assuming your operating system permits it).
+Frankly, I'm not sure why one would ever want to use this option.
+
+<h2><code>-s</code>&nbsp;VARIABLE<code>=</code>VALUE</h2>
+
+<p>This sets an internal CVS variable named VARIABLE to
+VALUE.
+
+<p>On the repository side, the <code>CVSROOT/*info</code> trigger files can
+expand such variables to values that were assigned in the -s option.
+For example, if <code>CVSROOT/loginfo</code> contains a line like this
+
+<pre>myproj /usr/local/bin/foo.pl ${=FISH}
+</pre>
+
+<p>and someone runs a commit from a myproj working copy like this
+
+<pre>floss$ cvs -s FISH=carp commit -m "fixed the bait bug"
+</pre>
+
+<p>the <code>foo.pl</code> script is invoked with <code>carp</code> as an argument.
+Note the funky syntax, though: The dollar sign, equal sign, and curly
+braces are all necessary - if any of them are missing, the expansion
+will not take place (at least not as intended). Variable names may
+contain alphanumerics and underscores only. Although it is not required
+that they consist entirely of capital letters, most people do seem to
+follow that convention.
+
+<p>You can use the -s flag as many times as you like in a single command.
+However, if the trigger script refers to variables that aren't set in a
+particular invocation of CVS, the command still succeeds, but none of
+the variables are expanded, and the user sees a warning. For example,
+if loginfo has this
+
+<pre>myproj /usr/local/bin/foo.pl ${=FISH} ${=BIRD}
+</pre>
+
+<p>but the same command as before is run
+
+<pre>floss$ cvs -s FISH=carp commit -m "fixed the bait bug"
+</pre>
+
+<p>the person running the command sees a warning something like this
+(placed last in the output)
+
+<pre>loginfo:31: no such user variable ${=BIRD}
+</pre>
+
+<p>and the <code>foo.pl</code> script is invoked with no arguments. But if this
+command were run
+
+<pre>floss$ cvs -s FISH=carp -s BIRD=vulture commit -m "fixed the bait bug"
+</pre>
+
+<p>there would be no warning, and both <code>${=FISH}</code> and
+<code>${=BIRD}</code> in loginfo would be correctly expanded. In either
+case, the commit itself would still succeed.
+
+<p>Although these examples all use <code>commit</code>, variable expansion can be
+done with any CVS command that can be noticed in a <code>CVSROOT/</code>
+trigger file - which is why the -s option is global.
+
+<p>(See the section <a href="#Repository_Administrative_Files">Repository Administrative Files</a> later in this
+chapter for more details about variable expansion in trigger files.)
+
+<h2><code>-T</code>&nbsp;DIR</h2>
+
+<p>Stores any temporary files in DIR instead of wherever CVS normally puts
+them (specifically, this overrides the value of the <code>$TMPDIR</code>
+environment variable, if any exists). DIR should be an absolute path.
+
+<p>This option is useful when you don't have write permission (and,
+therefore, CVS doesn't either) to the usual temporary locations.
+
+<h2><code>-t</code></h2>
+
+<p>Traces the execution of a CVS command. This causes CVS to print
+messages showing the steps that it's going through to complete a
+command. You may find it particularly useful in conjunction with the -n
+global option, to preview the effects of an unfamiliar command before
+running it for real. It can also be handy when you're trying to
+discover why a command failed.
+
+<h2><code>-v</code>&nbsp;or&nbsp;<code>--version</code></h2>
+
+<p>Causes CVS to print out its version and copyright information and then
+exit with no error.
+
+<h2><code>-w</code></h2>
+
+<p>Causes new working files to be created read-write (overrides any setting
+of the <code>$CVSREAD</code> environment variable). Because files are created
+read-write by default anyway, this option is rarely used.
+
+<p>If both -r and -w are passed, -w dominates.
+
+<h2><code>-x</code></h2>
+
+<p>Encrypts all communications with the server. This option has no effect
+unless you're connecting via the GSSAPI server (gserver). GSSAPI
+connections are not covered in this book, because they're still somewhat
+rarely used (although that may change). (See the nodes <cite>Global
+Options</cite> and <cite>GSSAPI Authenticated</cite> in the Cederqvist manual for
+more information.)
+
+<h2><code>-z</code>&nbsp;GZIPLEVEL</h2>
+
+<p>Sets the compression level on communications with the server. The
+argument GZIPLEVEL must be a number from 1 to 9. Level 1 is
+minimal compression (very fast, but doesn't compress much); Level 9 is
+highest compression (uses a lot of CPU time, but sure does squeeze the
+data). Level 9 is only useful on very slow network connections. Most
+people find levels between 3 and 5 to be most beneficial.
+
+<p>A space between -z and its argument is optional.
+
+<p><hr>
+Node:<a name="add">add</a>,
+Next:<a rel=next href="#admin">admin</a>,
+Previous:<a rel=previous href="#Global_Options">Global Options</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>add</h3>
+
+<p>Synopsis:&nbsp;add&nbsp;[OPTIONS]&nbsp;FILES
+
+<ul>
+<li>Alternate names - ad, new
+<li>Requires - Working copy, repository
+<li>Changes - Working copy
+</ul>
+
+<p>Adds a new file or files to an existing project. Although the
+repository is contacted for confirmation, the file does not actually
+appear in it until a subsequent commit is performed. (See also
+<a href="#remove">remove</a> and <a href="#import">import</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-kKEYWORD_SUBSTITUTION_MODE - Specifies that the file is to be stored
+with the given RCS keyword substitution mode. There is no space between
+the -k and its argument. (See the section <a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> later in this chapter for a list of valid modes and
+examples.)
+
+<li>-m MESSAGE - Records MESSAGE as the creation message, or description,
+for the file. This is different from a per-revision log message - each
+file has only one description. Descriptions are optional.
+
+<p>As of version 1.10.7, there is a bug in CVS whereby the description is
+lost if you add a file via client/server CVS. The rest of the add
+process seems to work fine, however, if that's any comfort.
+
+</ul>
+
+<p><hr>
+Node:<a name="admin">admin</a>,
+Next:<a rel=next href="#annotate">annotate</a>,
+Previous:<a rel=previous href="#add">add</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>admin</h3>
+
+<p>Synopsis:&nbsp;admin&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - adm, rcs
+<li>Requires - Working copy, repository
+<li>Changes - Repository
+</ul>
+
+<p>This command is an interface to various administrative tasks -
+specifically, tasks applicable to individual RCS files in the
+repository, such as changing a file's keyword substitution mode or
+changing a log message after it's been committed.
+
+<p>Although admin behaves recursively if no files are given as arguments,
+you normally will want to name files explicitly. It's very rare for a
+single admin command to be meaningful when applied to all files in a
+project, or even in a directory. Accordingly, when the following
+explanations refer to the "file", they mean the file or (rarely) files
+passed as arguments to the admin command.
+
+<p>If there is a system group named <code>cvsadmin</code> on the repository
+machine, only members of that group can run admin (with the exception of
+the <code>cvs&nbsp;admin&nbsp;-k</code> command, which is always permitted). Thus
+you can disallow admin for all users by setting the group to have no
+users.
+
+<p>Options:
+
+<ul>
+
+<li>-AOLDFILE - (Obsolete) Appends the RCS access list of OLDFILE to the
+access list of the file that is the argument to admin. CVS ignores RCS
+access lists, so this option is useless.
+
+<li>-a USER1 [,USER2...] - (Obsolete) Appends the users in the
+comma-separated list to the access list of the file. Like -A, this
+option is useless in CVS.
+
+<li>-bREV - Sets the revision of the file's default branch (usually the
+trunk) to REV. You won't normally need this option, because you can
+usually get the revisions you need via sticky tags, but you may use it
+to revert to a vendor's version if you're using vendor branches. There
+should be no space between the -b and its argument.
+
+<li>-cCOMMENT_PREFIX - (Obsolete) Sets the comment leader of the file to
+COMMENT_PREFIX. The comment leader is not used by CVS or even by recent
+versions of RCS; therefore, this option is useless and is included only
+for backward-compatibility.
+
+<li>-eUSER1[,USER2...] - (Obsolete) Removes the usernames appearing in the
+comma-separated list from the access list of the RCS file. Like -a and
+-A, this option is now useless in CVS.
+
+<li>-i or -I - These two are so obsolete I'm not even going to tell you
+what they used to do. (See the Cederqvist manual if you're curious.)
+
+<li>-kMODE - Sets the file's default keyword substitution mode to MODE.
+This option behaves like the -k option to add, only it gives you a way
+to change a file's mode after it's been added. (See the section
+<a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> later in this chapter for
+valid modes.) There should be no space between -k and its argument.
+
+<li>-L - Sets locking to <code>strict</code>. (See -l below.)
+
+<li>-l[REV] - Locks the file's revision to REV. If REV is omitted, it
+locks the latest revision on the default branch (usually the trunk). If
+REV is a branch, it locks the latest revision on that branch.
+
+<p>The intent of this option is to give you a way to do <dfn>reserved
+checkouts</dfn>, where only one user can be editing the file at a time. I'm
+not sure how useful this really is, but if you want to try it, you
+should probably do so in conjunction with the rcslock.pl script in the
+CVS source distribution's contrib/ directory. See comments in that file
+for further information. Among other things, those comments indicate
+that the locking must be set to <code>strict</code>. (See -L.) There is no
+space between -l and its argument.
+
+</p><li>-mREV:MESSAGE - Changes the log message for revision REV to MESSAGE.
+Very handy - along with -k, this is probably the most frequently used
+admin option. There are no spaces between option and arguments or
+around the colon between the two arguments. Of course, MESSAGE may
+contain spaces within itself (in which case, remember to surround it
+with quotes so the shell knows it's all one thing).
+
+<li>-NNAME[:[REV]] - Just like -n, except it forces the override of any
+existing assignment of the symbolic name NAME, instead of exiting with
+error.
+
+<li>-nNAME[:[REV]] - This is a generic interface to assigning, renaming,
+and deleting tags. There is no reason, as far as I can see, to prefer
+it to the tag command and the various options available there (-d, -r,
+-b, -f, and so on). I recommend using the tag command instead. The
+NAME and optional REV can be combined in the following ways:
+
+<ul>
+
+<li>If only the NAME argument is given, the symbolic name (tag) named NAME
+is deleted.
+
+<li>If NAME: is given but no REV, NAME is assigned to the latest revision on
+the default branch (usually the trunk).
+
+<li>If NAME:REV is given, NAME is assigned to that revision. REV can be a
+symbolic name itself, in which case it is translated to a revision
+number first (can be a branch number).
+
+<li>If REV is a branch number and is followed by a period (<code>.</code>), NAME
+is attached to the highest revision on that branch. If REV is just $,
+NAME is attached to revision numbers found in keyword strings in the
+working files.
+
+<p>In all cases where a NAME is assigned, CVS exits with an error if there
+is already a tag named NAME in the file (but see -N). There are no
+spaces between -n and its arguments.
+
+</ul>
+
+</p><li>-oRANGE - Deletes the revisions specified by RANGE (also known as
+"outdating", hence the -o). Range can be specified in one of the
+following ways:
+
+<ul>
+<li>REV1::REV2 - Collapses all intermediate revisions between REV1 and
+REV2, so that the revision history goes directly from REV1 to REV2.
+After this, any revisions between the two no longer exist, and there
+will be a noncontiguous jump in the revision number sequence.
+
+<li>::REV - Collapses all revisions between the beginning of REV's branch
+(which may be the beginning of the trunk) and REV, noninclusively of
+course. REV is then the first revision on that line.
+
+<li>REV:: - Collapses all revisions between REV and the end of its branch
+(which may be the trunk). REV is then the last revision on that line.
+
+<li>REV - Deletes the revision REV (-o1.8 would be equivalent to
+-o1.7::1.9).
+
+<li>REV1:REV2 - Deletes the revisions from REV1 to REV2, inclusive. They
+must be on the same branch. After this, you cannot retrieve REV1, REV2,
+or any of the revisions in between.
+
+<li>:REV - Deletes revisions from the beginning of the branch (or trunk) to
+REV, inclusive. (See the preceding warning.)
+
+<li>REV: - Deletes revisions from REV to the end of its branch (or trunk),
+inclusive. (See the preceding warning.)
+
+<p>None of the revisions being deleted may have branches or locks. If any
+of the revisions have symbolic names attached, you have to delete them
+first with tag -d or admin -n. (Actually, right now CVS only protects
+against deleting symbolically named revisions if you're using one of the
+:: syntaxes, but the single-colon syntaxes may soon change to this
+behavior as well.)
+
+<p>Instead of using this option to undo a bad commit, you should commit a
+new revision that undoes the bad change. There are no spaces between -o
+and its arguments.
+
+</ul>
+
+</p><li>-q - Tells CVS to run quietly - don't print diagnostic messages (just
+like the global -q option).
+
+<li>-sSTATE[:REV] - Sets the state attribute of revision REV to STATE. If
+REV is omitted, the latest revision on the default branch (usually the
+trunk) is used. If REV is a branch tag or number, the latest revision
+on that branch is used.
+
+<p>Any string of letters or numbers is acceptable for STATE; some commonly
+used states are Exp for experimental, Stab for stable, and Rel for
+released. (In fact, CVS sets the state to Exp when a file is created.)
+Note that CVS uses the state dead for its own purposes, so don't specify
+that one.
+
+<p>States are displayed in cvs log output, and in the $Log and $State RCS
+keywords in files. There is no space between -s and its arguments.
+
+</p><li>-t[DESCFILE] - Replaces the description (creation message) for the file
+with the contents of DESCFILE, or reads from standard input if no
+DESCFILE is specified.
+
+<p>This useful option, unfortunately, does not currently work in
+client/server CVS. In addition, if you try it in client/server and omit
+DESCFILE, any existing description for the file is wiped out and
+replaced with the empty string. If you need to rewrite a file's
+description, either do so using only local CVS on the same machine as
+the repository or -t-STRING (see below). There is no space between -t
+and its argument. DESCFILE may not begin with a hyphen (<code>-</code>).
+
+</p><li>-t-STRING - Like -t, except that STRING is taken directly as the new
+description. STRING may contain spaces, in which case you should
+surround it with quotes. Unlike the other syntax for -t, this works in
+client/server as well as locally.
+
+<li>-U - Sets locking to nonstrict. (See -l and -L options, discussed
+earlier.)
+
+<li>-u[REV] - Unlocks revision REV. (See -l.) If REV is omitted, CVS
+unlocks the latest lock held by the caller. If REV is a branch, CVS
+unlocks the latest revision on that branch. If someone other than the
+owner of a lock breaks the lock, a mail message is sent to the original
+locker. The content for this message is solicited on standard input
+from the person breaking the lock. There is no space between -u and its
+argument.
+
+<li>-VRCS_VERSION_NUMBER - (Obsolete) This used to be a way to tell CVS to
+produce RCS files acceptable to previous versions of RCS. Now the RCS
+format used by CVS is drifting away from the RCS format used by RCS, so
+this option is useless. Specifying it results in an error.
+
+<li>-xSUFFIX - (Obsolete) Theoretically, this gives you a way to specify
+the suffix for RCS file names. However, CVS and related tools all
+depend on that suffix being the default (,v), so this option does
+nothing.
+
+</ul>
+
+<p><hr>
+Node:<a name="annotate">annotate</a>,
+Next:<a rel=next href="#checkout">checkout</a>,
+Previous:<a rel=previous href="#admin">admin</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>annotate</h3>
+
+<p>Synopsis:&nbsp;annotate&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate name - ann
+<li>Requires - Working copy, repository
+<li>Changes - Nothing
+</ul>
+
+<p>Shows information on who last modified each line of each file and when.
+Each line of output corresponds to one line of the file. From left to
+right, the line displays the revision number of the last modification of
+that line, a parenthetical expression containing the user and date of
+the modification, a colon, and the contents of the line in the file.
+
+<p>For example, if a file looks like this
+
+<pre>this is a test file
+it only has too lines
+I mean "two"
+</pre>
+
+<p>the annotations for that file could look like this
+
+<pre>1.1 (jrandom 22-Aug-99): this is a test file
+1.1 (jrandom 22-Aug-99): it only has too lines
+1.2 (jrandom 22-Aug-99): I mean "two"
+</pre>
+
+<p>from which you would know that the first two lines were in the initial
+revision, and the last line was added or modified (also by jrandom) in
+Revision 1.2.
+
+<p>Options:
+
+<ul>
+
+<li>-D DATE - Shows the annotations as of the latest revision no later than
+DATE.
+
+<li>-f - Forces use of the head revision if the specified tag or date is
+not found. You can use this in combination with -D or -r to ensure that
+there is some output from the annotate command, even if only to show
+Revision 1.1 of the file.
+
+<li>-l - Local. Runs in the current working directory only. Does not
+descend into subdirectories.
+
+<li>-R - Recursive. Descends into subdirectories (the default). The point
+of the -R option is to override any -l option set in a .cvsrc file.
+
+<li>-r REV - Shows annotations as of revision REV (can be a revision number
+or a tag).
+
+</ul>
+
+<p><hr>
+Node:<a name="checkout">checkout</a>,
+Next:<a rel=next href="#commit">commit</a>,
+Previous:<a rel=previous href="#annotate">annotate</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>checkout</h3>
+
+<p>Synopsis:&nbsp;checkout&nbsp;[OPTIONS]&nbsp;PROJECT(S)
+
+<ul>
+<li>Alternate names - co, get
+<li>Requires - Repository
+<li>Changes - Current directory
+</ul>
+
+<p>Checks out a module from the repository into a working copy. The
+working copy is created if it doesn't exist already and updated if it
+does. (See also <a href="#update">update</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-A - Resets any sticky tags, sticky dates, or sticky -k (RCS keyword
+substitution mode) options. This is like the -A option to update and is
+probably more often used there than with checkout.
+
+<li>-c - Doesn't check anything out; just prints the CVSROOT/modules file,
+sorted, on standard output. This is a good way to get an overview of
+what projects are in a repository. However, a project without an entry
+in modules does not appear (this situation is quite normal because the
+name of the project's top-level directory in the repository functions as
+the project's "default" module name).
+
+<li>-D DATE - Checks out the latest revisions no later than DATE. This
+option is sticky, so you won't be able to commit from the working copy
+without resetting the sticky date. (See -A.) This option also implies
+-P, described later.
+
+<li>-d DIR - Creates the working copy in a directory named DIR, instead of
+creating a directory with the same name as the checked-out module. If
+you check out only a portion of a project and the portion is located
+somewhere beneath the project's top level, the locally empty
+intermediate directories are omitted. You can use -N to suppress this
+directory-collapsing behavior.
+
+<li>-f - Forces checkout of the head revision if the specified tag or date
+is not found. Most often used in combination with -D or -r to ensure
+that something always gets checked out.
+
+<li>-j&nbsp;REV[:DATE]&nbsp;or&nbsp;-j&nbsp;REV1[:DATE]&nbsp;-j&nbsp;REV2[:DATE] - Joins (merges) two
+lines of development. This is just like the -j option to update, where
+it is more commonly used. (See <a href="#update">update</a> for details.)
+
+<li>-k MODE - Substitutes RCS keywords according to MODE (which can
+override the default modes for the files). (See the section <a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> later in this chapter for valid modes.)
+The mode chosen will be sticky - future updates of the working copy
+will keep that mode.
+
+<li>-l - Local. Checks out the top-level directory of the project only.
+Does not process subdirectories.
+
+<li>-N - Suppresses collapsing of empty directories with -d option. (See
+-d.)
+
+<li>-n - Doesn't run any checkout program that was specified with -o in
+CVSROOT/modules. (See the section <a href="#Repository_Administrative_Files">Repository Administrative Files</a> later in this chapter for more on this.)
+
+<li>-P - Prunes empty directories from the working copy (like the -P option
+to update).
+
+<li>-p - Checks files out to standard output, not into files (like the -p
+option to update).
+
+<li>-R - Checks out subdirectories as well (the default). (See also the -f
+option.)
+
+<li>-r TAG - Checks out the project as of revision TAG (it would make
+almost no sense to specify a numeric revision for TAG, although CVS lets
+you). This option is sticky and implies -P.
+
+<li>-s - Like -c, but shows the status of each module and sorts by status.
+(See <a href="#modules">modules</a> in the section <a href="#Repository_Administrative_Files">Repository Administrative Files</a>
+for more information.)
+
+</ul>
+
+<p><hr>
+Node:<a name="commit">commit</a>,
+Next:<a rel=next href="#diff">diff</a>,
+Previous:<a rel=previous href="#checkout">checkout</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>commit</h3>
+
+<p>Synopsis:&nbsp;commit&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - ci, com
+<li>Requires - Working copy, repository
+<li>Changes - Repository (and working copy administrative area)
+</ul>
+
+<p>Commits changes from a working copy to the repository.
+
+<p>Options:
+
+<ul>
+
+<li>-F MSGFILE - Uses the contents of MSGFILE for the log message instead
+of invoking an editor. This option cannot be combined with -m.
+
+<li>-f - Forces commit of a new revision even if no changes have been made
+to the files. <code>commit</code> does not recurse with this option (it
+implies -l). You can force it to recurse with -R.
+
+<p>This meaning of -f is at odds with its usual meaning ("force to head
+revision") in CVS commands.
+
+</p><li>-l - Local. Commits changes from the current directory only. Doesn't
+descend into subdirectories.
+
+<li>-m MESSAGE - Uses MESSAGE as the log message instead of invoking an
+editor. Cannot be used with -F.
+
+<li>-n - Does not run any module program. (See the section
+<a href="#Repository_Administrative_Files">Repository Administrative Files</a> in this chapter for information
+about module programs.)
+
+<li>-R - Commits changes from subdirectories as well as from the current
+directory (the default). This option is used only to counteract the
+effect of a -l in .cvsrc.
+
+<li>-r REV - Commits to revision REV, which must be either a branch or a
+revision on the trunk that is higher than any existing revision.
+Commits to a branch always go on the tip of the branch (extending it);
+you cannot commit to a specific revision on a branch. Use of this
+option sets the new revision as a sticky tag on the file. This can be
+cleared with update -A.
+
+<p>The -r REV option implies -f as well. A new revision is committed even
+if there are no changes to commit.
+
+</ul>
+
+<p><hr>
+Node:<a name="diff">diff</a>,
+Next:<a rel=next href="#edit">edit</a>,
+Previous:<a rel=previous href="#commit">commit</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>diff</h3>
+
+<p>Synopsis:&nbsp;diff&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - di, dif
+<li>Requires - Working copy, repository
+<li>Changes - Nothing
+</ul>
+
+<p>Shows the difference between two revisions (in Unix diff format). When
+invoked with no options, CVS diffs the repository base revisions against
+the (possibly uncommitted) contents of the working copy. The <dfn>base</dfn>
+revisions are the latest revisions of this working copy retrieved from
+the repository; note that there could be even later revisions in the
+repository, if someone else committed changes but this working copy
+hasn't been updated yet. (See also <a href="#rdiff">rdiff</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-D DATE - Diffs against the latest revisions no later than DATE.
+Behaves like -r REV, except uses dates rather than revisions. (See -r
+for details.)
+
+<li>-k MODE - Expands RCS keywords in the diffs according to MODE. (See
+the section <a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> in this chapter
+for possible modes.)
+
+<li>-l - Local. If no files were specified as arguments, this option diffs
+files in the current directory, but does not descend into
+subdirectories.
+
+<li>-R - Recursive. This option is the opposite of -l. This is the
+default behavior, so the only reason to specify -R is to counteract a -l
+in a .cvsrc file.
+
+<li>-r REV or -r REV1 -r REV2 - Diffs against (or between) the specified
+revisions. With one -r option, this diffs revision REV against your
+working copy of that file (so when multiple files are being diffed, REV
+is almost always a tag). With two -r options, it diffs REV1 against
+REV2 for each file (and the working copy is, therefore, irrelevant).
+The two revisions can be in any order - REV1 does not have to be an
+earlier revision than REV2. The output reflects the direction of
+change. With no -r options, it shows the difference between the working
+file and the revision on which it is based.
+
+</ul>
+
+<p>Diff Compatibility Options
+
+<p>In addition to the preceding options, cvs diff also shares a number of
+options with the GNU version of the standard command-line diff program.
+Following is a complete list of these options, along with an explanation
+of a few of the most commonly used ones. (See the GNU diff documentation
+for the others.)
+
+<pre>-0 -1 -2 -3 -4 -5 -6 -7 -8 -9
+ --binary
+ --brief
+ --changed-group-format=ARG
+ -c
+ -C NLINES
+ --context[=LINES]
+ -e --ed
+ -t --expand-tabs
+ -f --forward-ed
+ --horizon-lines=ARG
+ --ifdef=ARG
+ -w --ignore-all-space
+ -B --ignore-blank-lines
+ -i --ignore-case
+ -I REGEXP
+ --ignore-matching-lines=REGEXP
+ -h
+ -b --ignore-space-change
+ -T --initial-tab
+ -L LABEL
+ --label=LABEL
+ --left-column
+ -d --minimal
+ -N --new-file
+ --new-line-format=ARG
+ --old-line-format=ARG
+ --paginate
+ -n --rcs
+ -s --report-identical-files
+ -p
+ --show-c-function
+ -y --side-by-side
+ -F REGEXP
+ --show-function-line=REGEXP
+ -H --speed-large-files
+ --suppress-common-lines
+ -a --text
+ --unchanged-group-format=ARG
+ -u
+ -U NLINES
+ --unified[=LINES]
+ -V ARG
+ -W COLUMNS
+ --width=COLUMNS
+</pre>
+
+<p>Following are the GNU diff options most frequently used with cvs diff.
+
+<ul>
+
+<li>-B - Ignores differences that are merely the insertion or deletion of
+blank lines (lines containing nothing but whitespace characters).
+
+<li>-b - Ignores differences in the amount of whitespace. This option
+treats all whitespace sequences as being equal and ignores whitespace at
+line end. More technically, this option collapses each whitespace
+sequence in the input to a single space and removes any trailing
+whitespace from each line, before taking the diff. (See also -w.)
+
+<li>-c - Shows output in context diff format, defaulting to three lines of
+context per difference (for the sake of the patch program, which
+requires at least two lines of context).
+
+<li>-C NUM - context=NUM - Like -c, but with NUM lines of context.
+
+<li>-i - Compares case insensitively. Treats upper- and lowercase versions
+of a letter as the same.
+
+<li>-u - Shows output in unified diff format.
+
+<li>-w - Ignores all whitespace differences, even when one side of the
+input has whitespace where the other has none. Essentially a stronger
+version of -b.
+
+</ul>
+
+<p><hr>
+Node:<a name="edit">edit</a>,
+Next:<a rel=next href="#editors">editors</a>,
+Previous:<a rel=previous href="#diff">diff</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>edit</h3>
+
+<p>Synopsis:&nbsp;edit&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - None
+<li>Requires - Working copy, repository
+<li>Changes - Permissions in working copy, watchlist in repository
+</ul>
+
+<p>Signals that you are about to begin editing a watched file or files.
+Also adds you as a temporary watcher to the file's watch list (you'll be
+removed when you do cvs unedit). (See also <a href="#watch">watch</a>,
+<a href="#watchers">watchers</a>, <a href="#unedit">unedit</a>, and <a href="#editors">editors</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-a ACTIONS - Specifies for which actions you want to be a temporary
+watcher. ACTIONS should be either edit, unedit, commit, all, or none.
+(If you don't use -a, the temporary watch will be for all actions.)
+
+<li>-l - Local. Signals editing for files in the current working directory
+only.
+
+<li>-R - Recursive (this is the default). Opposite of b; you would only
+need to pass -R to counteract a -l in a .cvsrc file.
+
+</ul>
+
+<p><hr>
+Node:<a name="editors">editors</a>,
+Next:<a rel=next href="#export">export</a>,
+Previous:<a rel=previous href="#edit">edit</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>editors</h3>
+
+<p>Synopsis:&nbsp;editors&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - None
+<li>Requires - Working copy, repository
+<li>Changes - Nothing
+</ul>
+
+<p>Shows who is currently editing a watched file. (See also
+<a href="#watch">watch</a>, <a href="#watchers">watchers</a>, <a href="#edit">edit</a>, and <a href="#unedit">unedit</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-l - Local. Views editors for files in current directory only.
+
+<li>-R - Recursive. Views editors for files in this directory and its
+subdirectories (the default). You may need to pass -R to counteract a
+-l in a .cvsrc file, though.
+
+</ul>
+
+<p><hr>
+Node:<a name="export">export</a>,
+Next:<a rel=next href="#gserver">gserver</a>,
+Previous:<a rel=previous href="#editors">editors</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>export</h3>
+
+<p>Synopsis:&nbsp;export&nbsp;[OPTIONS]&nbsp;PROJECT(S)
+
+<ul>
+<li>Alternate names - exp, ex
+<li>Requires - Repository
+<li>Changes - Current directory
+</ul>
+
+<p>Exports files from the repository to create a project tree that is not a
+working copy (has no CVS/ administrative subdirectories). Useful mainly
+for packaging distributions.
+
+<p>Options:
+
+<ul>
+
+<li>-D DATE - Exports the latest revisions no later than DATE.
+
+<li>-d DIR - Exports into DIR (otherwise, defaults to the module name).
+
+<li>-f - Forces use of head revisions, if a given tag or date would result
+in nothing being found (for use with -D or -r).
+
+<li>-k MODE - Expands RCS keywords according to MODE. (See the section
+<a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> later in this chapter.)
+
+<li>-l - Local. Exports only the top level of the project, no
+subdirectories.
+
+<li>-N - Doesn't "collapse" empty intermediate directories. This option is
+like the -N option to checkout (see <a href="#checkout">checkout</a>).
+
+<li>-n - Does not run a module program as may be specified in
+<code>CVSROOT/modules</code>. (See <a href="#Repository_Administrative_Files">Repository Administrative Files</a>
+later in this chapter for more about this.)
+
+<li>-P - Prunes empty directories (like the -P option to checkout or
+update).
+
+<li>-R - Recursive. Exports all subdirectories of the project (the
+default). The only reason to specify -R is to counteract a -l in a
+<code>.cvsrc</code> file.
+
+<li>-r REV - Exports revision REV. REV is almost certainly a tag name, not
+a numeric revision.
+
+</ul>
+
+<p><hr>
+Node:<a name="gserver">gserver</a>,
+Next:<a rel=next href="#history">history</a>,
+Previous:<a rel=previous href="#export">export</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>gserver</h3>
+
+<p>Synopsis:&nbsp;gserver
+
+<p>This is the GSSAPI (Generic Security Services API) server. This command
+is not normally run directly by users. Instead, it is started up on the
+server side when a user connects from a client with the <code>:gserver:</code>
+access method:
+
+<pre>cvs -d :gserver:floss.red-bean.com:/usr/local/newrepos checkout myproj
+</pre>
+
+<p>GSSAPI provides, among other things, Kerberos Version 5; for Kerberos
+Version 4, use <code>:kserver:</code>.
+
+<p>Setting up and using a GSSAPI library on your machines is beyond the
+scope of this book. (See the node <cite>GSSAPI Authenticated</cite> in the
+Cederqvist manual for some useful hints, however.)
+
+<p>Options: None.
+
+<p><hr>
+Node:<a name="history">history</a>,
+Next:<a rel=next href="#import">import</a>,
+Previous:<a rel=previous href="#gserver">gserver</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>history</h3>
+
+<p>Synopsis:&nbsp;history&nbsp;[OPTIONS]&nbsp;[FILENAME_SUBSTRING(S)]
+
+<ul>
+<li>Alternate names - hi, his
+<li>Requires - Repository, CVSROOT/history
+<li>Changes - Nothing
+</ul>
+
+<p>Shows a history of activity in the repository. Specifically, this
+option shows records of checkouts, commits, rtags, updates, and
+releases. By default, the option shows checkouts (but see the -x
+option). This command won't work if there's no CVSROOT/history file in
+the repository.
+
+<p>The history command differs from other CVS commands in several ways.
+First, it must usually be given options to do anything useful (and some
+of those options mean different things for history than they do
+elsewhere in CVS). Second, instead of taking full file names as
+arguments, it takes one or more substrings to match against file names
+(all records matching at least one of those substrings are retrieved).
+Third, history's output looks a lot like line noise until you learn to
+read it, so I'll explain the output format in a special section, after
+the options. (See also <a href="#log">log</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-a - Shows history for all users (otherwise, defaults to self).
+
+<li>-b STR - Shows data back to record containing string STR in the module
+name, file name, or repository path.
+
+<li>-c - Reports commits.
+
+<li>-D DATE - Shows data since DATE (the usual CVS date formats are
+available).
+
+<li>-e - Everything - reports on all record types.
+
+<li>-f FILE - Reports the most recent event concerning FILE. You can
+specify this option multiple times. This is different from the usual
+meaning of -f in CVS commands: "Force to head revision as a last
+resort."
+
+<li>-l - Shows the record representing the last (as in "most recent") event
+of each project. This is different from the usual meaning of -l in CVS
+commands: "Run locally, do not recurse."
+
+<li>-m MODULE - This provides a full report about MODULE (a project name).
+You can specify this option multiple times.
+
+<li>-n MODULE - Reports the most recent event about MODULE. For example,
+checking out the module is about the module itself, but modifying or
+updating a file inside the module is about that file, not about the
+module. You can specify this option multiple times. This is different
+from the usual meaning of -n in CVS commands: "Don't run a
+CVSROOT/modules program."
+
+<li>-o - Shows checkout records (the default).
+
+<li>-p REPOS - Shows data for a particular directory in the repository.
+You can specify this option multiple times. The meaning of this option
+differs from the usual meaning of -p in CVS commands: "Pipe the data to
+standard output instead of a file."
+
+<p>This option appears to be at least partially broken as of summer 1999.
+
+</p><li>-r REV - Shows records referring to revisions since the revision or tag
+named REV appears in individual RCS files. Each RCS file is searched
+for the revision or tag.
+
+<li>-T - Reports on all tag events.
+
+<li>-t TAG - Shows records since tag TAG was last added to the history
+file. This differs from the -r flag in that it reads only the
+CVSROOT/history file, not the RCS files, and is therefore much faster.
+
+<li>-u USER - Shows events associated with USER. You can specify this
+option multiple times.
+
+<li>-w - Shows records that are associated with the same working directory
+from which you are invoking history.
+
+<li>-X HISTORYFILE - Uses HISTORYFILE instead of CVSROOT/history. This
+option is mainly for debugging and is not officially supported;
+nevertheless, you may find it useful (perhaps for generating
+human-readable reports from old history files you've kept around).
+
+<li>-x TYPES - Reports on events specified in TYPES. Each type is
+represented by a single letter, from the set <code>TOEFWUCGMAR</code>; any
+number of letters can be combined. Here is what they mean:
+
+<ul>
+<li>T - Tag
+<li>O - Checkout
+<li>E - Export
+<li>F - Release
+<li>W - Update (newly obsolete file removed from working copy)
+<li>U - Update (file was checked out over user file)
+<li>C - Update (merge, with conflicts)
+<li>G - Update (merge, no conflicts)
+<li>M - Commit (file was modified)
+<li>A - Commit (file was added)
+<li>R - Commit (file was removed)
+</ul>
+
+<p>The default, if no -x option is given, is to show checkouts (like
+<code>-x&nbsp;O</code>).
+
+</p><li>-z ZONE - Displays times in output as for time zone ZONE. ZONE is an
+abbreviated time zone name, such as UTC, GMT, BST, CDT, CCT, and so on.
+A complete list of time zones is available in the TimezoneTable in the
+file lib/getdate.c in the CVS source distribution.
+
+</ul>
+
+<p>History Output
+
+<p>The output of the history command is a series of lines; each line
+represents one "history event" and starts with a single code letter
+indicating what type of event it is. For example:
+
+<pre>floss$ cvs history -D yesterday -x TMO
+M 08/21 20:19 +0000 jrandom 2.2 baar myproj == &lt;remote&gt;
+M 08/22 04:18 +0000 jrandom 1.2 README myproj == &lt;remote&gt;
+O 08/22 05:15 +0000 jrandom myproj =myproj= ~/src/*
+M 08/22 05:33 +0000 jrandom 2.18 README.txt myproj == ~/src/myproj
+O 08/22 14:25 CDT jrandom myproj =myproj= ~/src/*
+O 08/22 14:26 CDT jrandom [99.08.23.19.26.03] myproj =myproj= ~/src/*
+O 08/22 14:28 CDT jrandom [Exotic_Greetings-branch] myproj =myproj= ~/src/*
+</pre>
+
+<p>The code letters are the same as for the -x option just described.
+Following the code letter is the date of the event (expressed in UTC/GMT
+time, unless the -z option is used), followed by the user responsible
+for the event.
+
+<p>After the user might be a revision number, tag, or date, but only if
+such is appropriate for the event (date or tag will be in square
+brackets and formatted as shown in the preceding example). If you
+commit a file, it shows the new revision number; if you check out with
+-D or -r, the sticky date or tag is shown in square brackets. For a
+plain checkout, nothing extra is shown.
+
+<p>Next comes the name of the file in question, or module name if the event
+is about a module. If the former, the next two things are the
+module/project name and the location of the working copy in the user's
+home directory. If the latter, the next two things are the name of the
+module's checked-out working copy (between two equal signs), followed by
+its location in the user's home directory. (The name of the checked-out
+working copy may differ from the module name if the -d flag is used with
+checkout.)
+
+<p><hr>
+Node:<a name="import">import</a>,
+Next:<a rel=next href="#init">init</a>,
+Previous:<a rel=previous href="#history">history</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>import</h3>
+
+<p>Synopsis:&nbsp;import&nbsp;[OPTIONS]&nbsp;REPOSITORY&nbsp;VENDOR_TAG&nbsp;RELEASE_TAG(S)
+
+<ul>
+<li>Alternate names - im, imp
+<li>Requires - Repository, current directory (the source directory)
+<li>Changes - Repository
+</ul>
+
+<p>Imports new sources into the repository, either creating a new project
+or creating a new vendor revision on a vendor branch of an existing
+project. (See <a href="#Advanced_CVS">Advanced CVS</a> for a basic explanation of vendor
+branches in import, which will help you to understand the following.)
+
+<p>It's normal to use import to add many files or directories at once or to
+create a new project. To add single files, you should use add.
+
+<p>Options:
+
+<ul>
+
+<li>-b BRANCH - Imports to vendor branch BRANCH. (BRANCH is an actual
+branch number, not a tag.) This is rarely used but can be helpful if
+you get sources for the same project from different vendors. A normal
+import command assumes that the sources are to be imported on the
+default vendor branch, which is "1.1.1". Because it is the default, you
+normally don't bother to specify it with -b:
+
+<pre>floss$ cvs import -m "importing from vendor 1" theirproj THEM1 THEM1-0
+</pre>
+
+<p>To import to a vendor branch other than the default, you must specify a
+different branch number explicitly:
+
+<pre>floss$ cvs import -b 1.1.3 -m "from vendor 2" theirproj THEM2 THEM2-0
+</pre>
+
+<p>The 1.1.3 branch can absorb future imports and be merged like any other
+vendor branch. However, you must make sure any future imports that
+specify <code>-b&nbsp;1.1.3</code> also use the same vendor tag (<code>THEM2</code>).
+CVS does not check to make sure that the vendor branch matches the
+vendor tag. However, if they mismatch, odd and unpredictable things
+will happen.
+
+<p>Vendor branches are odd-numbered, the opposite of regular branches.
+
+</p><li>-d - Takes the file's modification time as the time of import instead
+of using the current time. This does not work with client/server CVS.
+
+<li>-I NAME - Gives file names that should be ignored in the import. You
+can use this option multiple times in one import. Wildcard patterns are
+supported: <code>*.foo</code> means ignore everything ending in <code>.foo</code>.
+(See <a href="#cvsignore">cvsignore</a> in <a href="#Repository_Administrative_Files">Repository Administrative Files</a> for
+details about wildcards.)
+
+<p>The following file and directory names are ignored by default:
+
+<pre> .
+ ..
+ .#*
+ #*
+ ,*
+ _$*
+ *~
+ *$
+ *.a
+ *.bak
+ *.BAK
+ *.elc
+ *.exe
+ *.ln
+ *.o
+ *.obj
+ *.olb
+ *.old
+ *.orig
+ *.rej
+ *.so
+ *.Z
+ .del-*
+ .make.state
+ .nse_depinfo
+ core
+ CVS
+ CVS.adm
+ cvslog.*
+ RCS
+ RCSLOG
+ SCCS
+ tags
+ TAGS
+</pre>
+
+<p>You can suppress the ignoring of those file name patterns, as well as
+any specified in <code>.cvsignore</code>, <code>CVSROOT/cvsignore</code>, and the
+<code>$CVSIGNORE</code> environment variable, by using <code>-I&nbsp;!</code>. That
+is,
+
+<pre>floss$ cvs import -I ! -m "importing the universe" proj VENDOR VENDOR_0
+</pre>
+
+<p>imports all files in the current directory tree, even those that would
+otherwise be ignored.
+
+<p>Using a <code>-I&nbsp;!</code> clears whatever ignore list has been created to
+that point, so any -I options that came before it would be nullified,
+but any that come after will still count. Thus,
+
+<pre>floss$ cvs import -I ! -I README.txt -m "some msg" theirproj THEM THEM_0
+</pre>
+
+<p>is not the same as
+
+<pre>floss$ cvs import -I README.txt -I ! -m "some msg" theirproj THEM THEM_0
+</pre>
+
+<p>The former ignores (fails to import) README.txt, whereas the latter
+imports it.
+
+</p><li>-k MODE - Sets the default RCS keyword substitution mode for the
+imported files. (See <a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> later in
+this chapter for a list of valid modes.)
+
+<li>-m MESSAGE - Records MESSAGE as the import log message.
+
+<li>-W SPEC - Specifies filters based on file names that should be in
+effect for the import. You can use this option multiple times. (See
+<a href="#cvswrappers">cvswrappers</a> in <a href="#Repository_Administrative_Files">Repository Administrative Files</a> for details
+about wrapper specs.)
+
+</ul>
+
+<p><hr>
+Node:<a name="init">init</a>,
+Next:<a rel=next href="#kserver">kserver</a>,
+Previous:<a rel=previous href="#import">import</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>init</h3>
+
+<p>Synopsis:&nbsp;init&nbsp;NEW_REPOSITORY
+
+<ul>
+<li>Alternate names - None
+<li>Requires - Location for new repository
+<li>Creates - Repository
+</ul>
+
+<p>Creates a new repository (that is, a root repository in which many
+different projects are stored). You will almost always want to use the
+global -d option with this, as in
+
+<pre>floss$ cvs -d /usr/local/yet_another_repository init
+</pre>
+
+<p>because even if you have a CVSROOT environment variable set, it's
+probably pointing to an existing repository, which would be useless and
+possibly dangerous in the context of this command. (See <a href="#Repository_Administration">Repository Administration</a> for additional steps that you should take after
+initializing a new repository.)
+
+<p>Options: None.
+
+<p><hr>
+Node:<a name="kserver">kserver</a>,
+Next:<a rel=next href="#log">log</a>,
+Previous:<a rel=previous href="#init">init</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>kserver</h3>
+
+<p>Synopsis:&nbsp;kserver
+
+<p>This is the Kerberos server. (If you have Kerberos libraries Version 4
+or below - Version 5 just uses GSSAPI, see <a href="#gserver">gserver</a>.) This
+command is not normally run directly by users but is instead started up
+on the server side when a user connects from a client with the
+<code>:kserver:</code> access method:
+
+<pre>cvs -d :kserver:floss.red-bean.com:/usr/local/newrepos checkout myproj
+</pre>
+
+<p>Setting up and using Kerberos on your machine is beyond the scope of
+this book. (However, see the node <cite>Kerberos Authenticated</cite> in the
+Cederqvist manual for some useful hints.)
+
+<p>Options: None.
+
+<p><hr>
+Node:<a name="log">log</a>,
+Next:<a rel=next href="#login">login</a>,
+Previous:<a rel=previous href="#kserver">kserver</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>log</h3>
+
+<p>Synopsis:&nbsp;log&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - lo, rlog
+<li>Requires - Working copy, repository
+<li>Changes - Nothing
+</ul>
+
+<p>Shows log messages for a project, or for files within a project. The
+output of log is not quite in the same style as the output of other CVS
+commands, because log is based on an older RCS program (rlog). Its
+output format gives a header, containing various pieces of
+non-revision-specific information about the file, followed by the log
+messages (arranged by revision). Each revision shows not merely the
+revision number and log message, but also the author and date of the
+change and the number of lines added or deleted. All times are printed
+in UTC (GMT), not local time.
+
+<p>Because log output is per file, a single commit involving multiple files
+may not immediately appear as a conceptually atomic change. However, if
+you read all of the log messages and dates carefully, you may be able to
+reconstruct what happened. (For information about a tool that can
+reformat multifile log output into a more readable form, see
+<a href="#cvs2cl_--_Generate_GNU-Style_ChangeLogs">cvs2cl - Generate GNU-Style ChangeLogs</a> in <a href="#Third-Party_Tools">Third-Party Tools</a> for details.) (See also <a href="#history">history</a>.)
+
+<p>Options:
+
+<p>As you read over the following filtering options, it may not be
+completely clear how they behave when combined. A precise description
+of log's behavior is that it takes the intersection of the revisions
+selected by -d, -s, and -w, intersected with the union of those selected
+by -b and -r.
+
+<ul>
+
+<li>-b - Prints log information about the default branch only (usually the
+highest branch on the trunk). This is usually done to avoid printing
+the log messages for side branches of development.
+
+<li>-dDATES - Prints log information for only those revisions that match
+the date or date range given in DATES, a semicolon-separated list.
+Dates can be given in any of the usual date formats (see <a href="#Date_Formats">Date Formats</a> earlier in this section) and can be combined into ranges as
+follows:
+
+<ul>
+
+<li>DATE1&lt;DATE2 - Selects revisions created between DATE1 and DATE2. If
+DATE1 is after DATE2, use <code>&gt;</code> instead; otherwise, no log messages
+are retrieved.
+
+<li>&lt;DATE DATE&gt; - All revisions from DATE or earlier.
+
+<li>&gt;DATE DATE&lt; - All revisions from DATE or later.
+
+<li>DATE - Just selects the most recent single revision from DATE or
+earlier.
+
+</ul>
+
+<p>You may use <code>&lt;=</code> and <code>&gt;=</code> instead of <code>&lt;</code> and <code>&gt;</code> to
+indicate an inclusive range (otherwise, ranges are exclusive). Multiple
+ranges should be separated with semicolons, for example
+
+<pre>floss$ cvs log -d"1999-06-01&lt;1999-07-01;1999-08-01&lt;1999-09-01"
+</pre>
+
+<p>selects log messages for revisions committed in June or August of 1999
+(skipping July). There can be no space between -d and its arguments.
+
+</p><li>-h - Prints only the header information for each file, which includes
+the file name, working directory, head revision, default branch, access
+list, locks, symbolic names (tags), and the file's default keyword
+substitution mode. No log messages are printed.
+
+<li>-l - Local. Runs only on files in the current working directory.
+
+<li>-N - Omits the list of symbolic names (tags) from the header. This can
+be helpful when your project has a lot of tags but you're only
+interested in seeing the log messages.
+
+<li>-R - Prints the name of the RCS file in the repository.
+
+<p>This is different from the usual meaning of -R: "recursive". There's no
+way to override a -l for this command, so don't put log -l in your
+.cvsrc.
+
+</p><li>-rREVS - Shows log information for the revisions specified in REVS, a
+comma-separated list. REVS can contain both revision numbers and tags.
+Ranges can be specified like this:
+
+<ul>
+
+<li>REV1:REV2 - Revisions from REV1 to REV2 (they must be on the same
+branch).
+
+<li>:REV - Revisions from the start of REV's branch up to and including
+REV.
+
+<li>REV: - Revisions from REV to the end of REV's branch.
+
+<li>BRANCH - All revisions on that branch, from root to tip.
+
+<li>BRANCH1:BRANCH2 - A range of branches - all revisions on all the
+branches in that range.
+
+<li>BRANCH. - The latest (tip) revision on BRANCH.
+
+</ul>
+
+<p>Finally, a lone -r, with no argument, means select the latest revision
+on the default branch (normally the trunk). There can be no space
+between -r and its argument.
+
+<p>If the argument to -r is a list, it is comma-separated, not
+semicolon-separated like -d.
+
+</p><li>-sSTATES - Selects revisions whose state attribute matches one of the
+states given in STATES, a comma-separated list. There can be no space
+between -s and its argument.
+
+<p>If the argument to -s is a list, it is comma-separated, not semicolon-separated like -d.
+
+</p><li>-t - Like -h, but also includes the file's description (its creation
+message).
+
+<li>-wUSERS - Selects revisions committed by users whose usernames appear
+in the comma-separated list USERS. A lone -w with no USERS means to
+take the username of the person running cvs log.
+
+<p>Remember that when user aliasing is in effect (see the section <a href="#The_Password-Authenticating_Server">The Password-Authenticating Server</a> in <a href="#Repository_Administration">Repository Administration</a>), CVS
+records the CVS username, not the system username, with each commit.
+There can be no space between -w and its argument.
+
+<p>If the argument to -w is a list, it is comma-separated, not
+semicolon-separated like -d.
+
+</ul>
+
+<p><hr>
+Node:<a name="login">login</a>,
+Next:<a rel=next href="#logout">logout</a>,
+Previous:<a rel=previous href="#log">log</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>login</h3>
+
+<p>Synopsis:&nbsp;login
+
+<ul>
+<li>Alternate names - logon, lgn
+<li>Requires - Repository
+<li>Changes - ~/.cvspass file
+</ul>
+
+<p>Contacts a CVS server and confirms authentication information for a
+particular repository. This command does not affect either the working
+copy or the repository; it just confirms a password (for use with the
+:pserver: access method) with a repository and stores the password for
+later use in the .cvspass file in your home directory. Future commands
+accessing the same repository with the same username will not require
+you to rerun login, because the client-side CVS will just consult the
+.cvspass file for the password.
+
+<p>If you use this command, you should specify a repository using the
+pserver access method, like this
+
+<pre>floss$ cvs -d :pserver:jrandom@floss.red-bean.com:/usr/local/newrepos
+</pre>
+
+<p>or by setting the CVSROOT environment variable.
+
+<p>If the password changes on the server side, you have to rerun login.
+
+<p>Options: None.
+
+<p><hr>
+Node:<a name="logout">logout</a>,
+Next:<a rel=next href="#pserver">pserver</a>,
+Previous:<a rel=previous href="#login">login</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>logout</h3>
+
+<p>Synopsis:&nbsp;logout
+
+<ul>
+<li>Alternate names - None
+<li>Requires - ~/.cvspass file
+<li>Changes - ~/.cvspass file
+</ul>
+
+<p>The opposite of login - removes the password for this repository from
+.cvspass.
+
+<p>Options: None.
+
+<p><hr>
+Node:<a name="pserver">pserver</a>,
+Next:<a rel=next href="#rdiff">rdiff</a>,
+Previous:<a rel=previous href="#logout">logout</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>pserver</h3>
+
+<p>Synopsis:&nbsp;pserver
+
+<ul>
+<li>Alternate names - None
+<li>Requires - Repository
+<li>Changes - Nothing
+</ul>
+
+<p>This is the password-authenticating server. This command is not
+normally run directly by users but is started up from
+<code>/etc/inetd.conf</code> on the server side when a user connects from a
+client with the <code>:pserver:</code> access method. (See also the
+<a href="#login">login</a> and <a href="#logout">logout</a> commands, and the file <code>.cvspass</code> in
+the <a href="#Run_Control_Files">Run Control Files</a> section in this chapter. See
+<a href="#Repository_Administration">Repository Administration</a> for details on setting up a
+password-authenticating CVS server.)
+
+<p>Options: None.
+
+<p><hr>
+Node:<a name="rdiff">rdiff</a>,
+Next:<a rel=next href="#release">release</a>,
+Previous:<a rel=previous href="#pserver">pserver</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>rdiff</h3>
+
+<p>Synopsis:&nbsp;rdiff&nbsp;[OPTIONS]&nbsp;PROJECTS
+
+<ul>
+<li>Alternate names - patch, pa
+<li>Requires - Repository
+<li>Changes - Nothing
+</ul>
+
+<p>Like the diff command, except it operates directly in the repository
+and, therefore, requires no working copy. This command is meant for
+obtaining the differences between one release and another of your
+project, in a format suitable as input to the patch program (perhaps so
+you can distribute patch files to users who want to upgrade).
+
+<p>The operation of the patch program is beyond the scope of this book.
+However, note that if the patch file contains diffs for files in
+subdirectories, you may need to use the -p option to patch to get it to
+apply the differences correctly. (See the patch documentation for more
+about this.) (See also <a href="#diff">diff</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-c - Prints output in context diff format (the default).
+
+<li>-D DATE or -D DATE1 -D DATE2 - With one date, this shows the
+differences between the files as of DATE and the head revisions. With
+two dates, it shows the differences between the dates.
+
+<li>-f - Forces the use of head revision if no matching revision is found
+for the -D or -r flag (otherwise, rdiff would just ignore the file).
+
+<li>-l - Local. Won't descend into subdirectories.
+
+<li>-R - Recursive. Descends into subdirectories (the default). You only
+specify this option to counteract a -l in your .cvsrc.
+
+<li>-r REV -r REV1 -r REV2 - With one revision, this shows the differences
+between revision REV of the files and the head revisions. With two, it
+shows the differences between the revisions.
+
+<li>-s - Displays a summary of differences. This shows which files have
+been added, modified, or removed, without showing changes in their
+content. The output looks like this:
+
+<pre>floss$ cvs -Q rdiff -s -D 1999-08-20 myproj
+File myproj/Random.txt is new; current revision 1.4
+File myproj/README.txt changed from revision 2.1 to 2.20
+File myproj/baar is new; current revision 2.3
+</pre>
+
+<li>-t - Shows the diff between the top two revisions of each file. This
+is a handy shortcut for determining the most recent changes to a
+project. This option is incompatible with -D and -r.
+
+<li>-u - Prints output in unidiff format. Older versions of patch can't
+handle unidiff format; therefore, don't use -u if you're trying to
+generate a distributable patch file - use -c instead.
+
+<li>-V (Obsolete) - CVS reports an error if you try to use this option now.
+I've included it here only in case you see some old script trying to use
+it.
+
+</ul>
+
+<p><hr>
+Node:<a name="release">release</a>,
+Next:<a rel=next href="#remove">remove</a>,
+Previous:<a rel=previous href="#rdiff">rdiff</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>release</h3>
+
+<p>Synopsis:&nbsp;release&nbsp;[OPTIONS]&nbsp;DIRECTORY
+
+<ul>
+<li>Alternate names - re, rel
+<li>Requires - Working copy
+<li>Changes - Working copy, CVSROOT/history
+</ul>
+
+<p>Cancels a checkout (indicates that a working copy is no longer in use).
+Unlike most CVS commands that operate on a working copy, this one is not
+invoked from within the working copy but from directly above it (in its
+parent directory). You either have to set your CVSROOT environment
+variable or use the -d global option, as CVS will not be able to find
+out the repository from the working copy.
+
+<p>Using release is never necessary. Because CVS doesn't normally do
+locking, you can just remove your working copy.
+
+<p>However, if you have uncommitted changes in your working copy or you
+want your cessation of work to be noted in the CVSROOT/history file (see
+the history command), you should use release. CVS first checks for any
+uncommitted changes; if there are any, it warns you and prompts for
+continuation. Once the working copy is actually released, that fact is
+recorded in the repository's CVSROOT/history file.
+
+<p>Options:
+
+<ul>
+
+<li>-d - Deletes the working copy if the release succeeds. Without -d, the
+working copy remains on disk after the release.
+
+</ul>
+
+<p>If you created any new directories inside your working copy but did not
+add them to the repository, they are deleted along with the rest of the
+working copy, if you specified the -d flag.
+
+<p><hr>
+Node:<a name="remove">remove</a>,
+Next:<a rel=next href="#rtag">rtag</a>,
+Previous:<a rel=previous href="#release">release</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>remove</h3>
+
+<p>Synopsis:&nbsp;remove&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - rm, delete
+<li>Requires - Working copy
+<li>Changes - Working copy
+</ul>
+
+<p>Removes a file from a project. Normally, the file itself is removed
+from disk when you invoke this command (but see -f). Although this
+command operates recursively by default, it is common to explicitly name
+the files being removed. Note the odd implication of the previous
+sentence: Usually, you run cvs remove on files that don't exist anymore
+in your working copy.
+
+<p>Although the repository is contacted for confirmation, the file is not
+actually removed until a subsequent commit is performed. Even then, the
+RCS file is not really removed from the repository; if it is removed
+from the trunk, it is just moved into an Attic/ subdirectory, where it
+is still available to exist on branches. If it is removed from a
+branch, its location is not changed, but a new revision with state dead
+is added on the branch. (See also <a href="#add">add</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-f - Force. Deletes the file from disk before removing it from CVS.
+This meaning differs from the usual meaning of -f in CVS commands:
+"Force to head revision".
+
+<li>-l - Local. Runs only in current working directory.
+
+<li>-R - Recursive. Descends into subdirectories (the default). This
+option exists only to counteract a -l in .cvsrc.
+
+</ul>
+
+<p><hr>
+Node:<a name="rtag">rtag</a>,
+Next:<a rel=next href="#server">server</a>,
+Previous:<a rel=previous href="#remove">remove</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>rtag</h3>
+
+<p>Synopsis:&nbsp;rtag&nbsp;[OPTIONS]&nbsp;TAG&nbsp;PROJECT(S)
+
+<ul>
+<li>Alternate names - rt, rfreeze
+<li>Requires - Repository
+<li>Changes - Repository
+</ul>
+
+<p>Tags a module directly in the repository (requires no working copy).
+You probably need to have your CVSROOT environment variable set or use
+the -d global option for this to work. (See also <a href="#tag">tag</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-a - Clears the tag from any removed files, because removed files stay
+in the repository for historical purposes but are not considered part of
+the live project anymore. Although it's illegal to tag files with a tag
+name that's already in use, there should be no interference if the name
+is only used in removed files (which, from the current point of view of
+the project, don't exist anymore).
+
+<li>-b - Creates a new branch, with branch name TAG.
+
+<li>-D DATE - Tags the latest revisions no later than DATE.
+
+<li>-d - Deletes the tag. No record is made of this change - the tag
+simply disappears. CVS does not keep a change history for tags.
+
+<li>-F - Forces reassignment of the tag name, if it happens to exist
+already for some other revision in the file.
+
+<li>-f - Forces to head revision if a given tag or date is not found. (See
+-r and -D.)
+
+<li>-l - Local. Runs in the current directory only.
+
+<li>-n - Won't execute a tag program from CVSROOT/modules. (See the section
+<a href="#Repository_Administrative_Files">Repository Administrative Files</a> later in this chapter for
+details about such programs.)
+
+<li>-R - Recursive. Descends into subdirectories (the default). The -R
+option exists only to counteract a -l in .cvsrc.
+
+<li>-r REV - Tags revision REV (which may itself be a tag name).
+
+</ul>
+
+<p><hr>
+Node:<a name="server">server</a>,
+Next:<a rel=next href="#status">status</a>,
+Previous:<a rel=previous href="#rtag">rtag</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>server</h3>
+
+<p>Synopsis:&nbsp;server
+
+<p>Starts up a CVS server. This command is never invoked by users (unless
+they're trying to debug the client/server protocol), so forget I even
+mentioned it.
+
+<p>Options: None.
+
+<p><hr>
+Node:<a name="status">status</a>,
+Next:<a rel=next href="#tag">tag</a>,
+Previous:<a rel=previous href="#server">server</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>status</h3>
+
+<p>Synopsis:&nbsp;status&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - st, stat
+<li>Requires - Working copy
+<li>Changes - Nothing
+</ul>
+
+<p>Shows the status of files in the working copy.
+
+<p>Options:
+
+<ul>
+
+<li>-l - Local. Runs in the current directory only.
+
+<li>-R - Recursive. Descends into subdirectories (the default). The -R
+option exists only to counteract a -l in .cvsrc.
+
+<li>-v - Shows tag information for the file.
+
+</ul>
+
+<p><hr>
+Node:<a name="tag">tag</a>,
+Next:<a rel=next href="#unedit">unedit</a>,
+Previous:<a rel=previous href="#status">status</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>tag</h3>
+
+<p>Synopsis:&nbsp;tag&nbsp;[OPTIONS]&nbsp;TAG&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - ta, freeze
+<li>Requires - Working copy, repository
+<li>Changes - Repository
+</ul>
+
+<p>Attaches a name to a particular revision or collection of revisions for
+a project. Often called "taking a snapshot" of the project. This
+command is also used to create branches in CVS. (See the -b option -
+see also <a href="#rtag">rtag</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-b - Creates a branch named TAG.
+
+<li>-c - Checks that the working copy has no uncommitted changes. If it
+does, the command exits with a warning, and no tag is made.
+
+<li>-D DATE - Tags the latest revisions no later than DATE.
+
+<li>-d - Deletes the tag. No record is made of this change; the tag simply
+disappears. CVS does not keep a change history for tags.
+
+<li>-F - Forces reassignment of the tag name, if it happens to exist
+already for some other revision in the file.
+
+<li>-f - Forces to head revision if a given tag or date is not found. (See
+-r and -D.)
+
+<li>-l - Local. Runs in the current directory only.
+
+<li>-R - Recursive. Descends into subdirectories (the default). The -R
+option exists only to counteract a -l in .cvsrc.
+
+<li>-r REV - Tags revision REV (which may itself be a tag name).
+
+</ul>
+
+<p><hr>
+Node:<a name="unedit">unedit</a>,
+Next:<a rel=next href="#update">update</a>,
+Previous:<a rel=previous href="#tag">tag</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>unedit</h3>
+
+<p>Synopsis:&nbsp;unedit&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - None
+<li>Requires - Working copy, repository
+<li>Changes - edit/watch lists in the repository
+</ul>
+
+<p>Signals to watchers that you are done editing a file. (See also
+<a href="#watch">watch</a>, <a href="#watchers">watchers</a>, <a href="#edit">edit</a>, and <a href="#editors">editors</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-l - Local. Signals editing for files in the current working directory
+only.
+
+<li>-R - Recursive (opposite of -l). Recursive is the default; the only
+reason to pass -R is to counteract a -l in your .cvsrc file.
+
+</ul>
+
+<p><hr>
+Node:<a name="update">update</a>,
+Next:<a rel=next href="#watch">watch</a>,
+Previous:<a rel=previous href="#unedit">unedit</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>update</h3>
+
+<p>Synopsis:&nbsp;update&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - up, upd
+<li>Requires - Working copy, repository
+<li>Changes - Working copy
+</ul>
+
+<p>Merges changes from the repository into your working copy. As a side
+effect, it indicates which files in your working copy are modified (but
+if the -Q global option is passed, these indications won't be printed).
+(See also <a href="#checkout">checkout</a>.)
+
+<p>Options:
+
+<ul>
+
+<li>-A - Clears any sticky tags, sticky dates, or sticky RCS keyword
+expansion modes. This may result in the contents of files changing, if
+the trunk-head revisions are different from the former sticky revisions.
+(Think of -A as being like a fresh checkout of the project trunk.)
+
+<li>-C - Clean out any locally changed files and replace them with the
+latest versions from the repository. This is not necessarily the same
+as reverting the files, since the repository may have changed since the
+last update or checkout. Any local modifications are saved in
+<code>.#file.rev</code>.
+
+<p>Note: this option was implemented in January 2000; if your CVS was
+acquired before then, you'd have to upgrade.
+
+</p><li>-D DATE - Updates to the most recent revisions no later than DATE.
+This option is sticky and implies -P. If the working copy has a sticky
+date, commits are not possible.
+
+<li>-d - Retrieves absent directories - that is, directories that exist in
+the repository but not yet in the working copy. Such directories may
+have been created in the repository after the working copy was checked
+out. Without this option, update only operates on the directories
+present in the working copy; new files are brought down from the
+repository, but new directories are not. (See also -P.)
+
+<li>-f - Forces to head revision if no matching revision is found with the
+-D or -r flags.
+
+<li>-I NAME - Like the -I option of import.
+
+<li>-j REV[:DATE] or -j REV1[:DATE] -j REV2[:DATE] - Joins, or merges, two
+lines of development. Ignoring the optional DATE arguments for the
+moment (we'll get to them later), here's how -j works: If only one -j is
+given, it takes all changes from the common ancestor to REV and merges
+them into the working copy. The <dfn>common ancestor</dfn> is the latest
+revision that is ancestral to both the revisions in the working
+directory and to REV. If two -j options are given, it merges the
+changes from REV1 to REV2 into the working copy.
+
+<p>The special tags HEAD and BASE may be used as arguments to -j; they mean
+the most recent revision in the repository, and the revision on which
+the current working copy file is based, respectively.
+
+<p>As for the optional DATE arguments, if REV is a branch, it is normally
+taken to mean the latest revision on that branch, but you can restrict
+it to the latest revision no later than DATE. The date should be
+separated from the revision by a colon, with no spaces, for instance:
+
+<pre>floss$ cvs update -j ABranch:1999-07-01 -j ABranch:1999-08-01
+</pre>
+
+<p>In this example, different dates on the same branch are used, so the
+effect is to take the changes on that branch from July to August and
+merge them into the working copy. However, note that there is no
+requirement that the branch be the same in both -j options.
+
+</p><li>-k MODE - Does RCS keyword substitution according to MODE. (See the
+section <a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> later in this
+chapter.) The mode remains sticky on the working copy, so it will
+affect future updates (but see -A).
+
+<li>-l - Local. Updates the current directory only.
+
+<li>-P - Prunes empty directories. Any CVS-controlled directory that
+contains no files at the end of the update are removed from the working
+copy. (See also -d.)
+
+<li>-p - Sends file contents to standard output instead of to the files.
+Used mainly for reverting to a previous revision without producing
+sticky tags in the working copy. For example:
+
+<pre>floss$ cvs update -p -r 1.3 README.txt &gt; README.txt
+</pre>
+
+<p>Now README.txt in the working copy has the contents of its past Revision
+1.3, just as if you had hand-edited it into that state.
+
+</p><li>-R - Recursive. Descends into subdirectories to update (the default).
+The only reason you'd specify it is to counteract a -l in .cvsrc.
+
+<li>-r REV - Updates (or downdates, or crossdates) to revision REV. When
+updating a whole working copy, REV is most often a tag (regular or
+branch). However, when updating an individual file, it is just as
+likely to be a revision number as a tag.
+
+<p>This option is sticky. If the files are switched to a nonbranch tag or
+sticky revision, they cannot be committed until the stickiness is
+removed. (See -A.) If REV was a branch tag, however, commits are
+possible. They'll simply commit new revisions on that branch.
+
+</p><li>-WSPEC - Specifies wrapper-style filters to use during the update. You
+can use this option multiple times. (See <a href="#cvswrappers">cvswrappers</a> in
+<a href="#Repository_Administrative_Files">Repository Administrative Files</a> in this chapter for details about
+wrapper specs.) There is no space between -W and its argument.
+
+</ul>
+
+<p><hr>
+Node:<a name="watch">watch</a>,
+Next:<a rel=next href="#watchers">watchers</a>,
+Previous:<a rel=previous href="#update">update</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>watch</h3>
+
+<p>Synopsis:&nbsp;watch&nbsp;on|off|add|remove&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - None
+<li>Requires - Working copy, repository
+<li>Changes - Watch list in repository
+</ul>
+
+<p>Sets a watch on one or more files. Unlike most CVS commands, watch
+requires a further subcommand to do something useful. (See also
+<a href="#watchers">watchers</a>, <a href="#edit">edit</a>, <a href="#editors">editors</a>, and <a href="#unedit">unedit</a>, and
+<a href="#users">users</a>.)
+
+<p>Subcommands:
+
+<ul>
+
+<li>on - Declares that the files are being watched. This means that they
+are created read-only on checkout, and users should do cvs edit to make
+them read-write (and notify any watchers that the file is now being
+edited). Turning on a watch does not add you to the watch list for any
+files. (See <code>watch&nbsp;add</code> and <code>watch&nbsp;remove</code> for that.)
+
+<li>off - Opposite of watch on. Declares that the files are no longer
+being watched.
+
+<li>add - Adds you to the list of watchers for this file. You are notified
+when someone commits or runs cvs edit or cvs unedit (but see the -a
+option).
+
+<li>remove - Opposite of watch add. Removes you from the list of watchers
+for this file.
+
+</ul>
+
+<p>Options (for use with any watch subcommand). All three options have the
+same meanings as for edit:
+
+<ul>
+
+<li>-a ACTIONS
+
+<li>-l
+
+<li>-R
+
+</ul>
+
+<p><hr>
+Node:<a name="watchers">watchers</a>,
+Previous:<a rel=previous href="#watch">watch</a>,
+Up:<a rel=up href="#Commands_And_Options">Commands And Options</a>
+<br>
+
+<h3>watchers</h3>
+
+<p>Synopsis:&nbsp;watchers&nbsp;[OPTIONS]&nbsp;[FILES]
+
+<ul>
+<li>Alternate names - None
+<li>Requires - Working copy, repository
+<li>Changes - Nothing
+</ul>
+
+<p>Shows who's watching what files.
+
+<p>Options - these options mean the same thing here as for <a href="#edit">edit</a>:
+
+<ul>
+
+<li>-l
+
+<li>-R
+
+</ul>
+
+<p><hr>
+Node:<a name="Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a>,
+Next:<a rel=next href="#Repository_Administrative_Files">Repository Administrative Files</a>,
+Previous:<a rel=previous href="#Commands_And_Options">Commands And Options</a>,
+Up:<a rel=up href="#CVS_Reference">CVS Reference</a>
+<br>
+
+<h2>Keyword Substitution (RCS Keywords)</h2>
+
+<p>CVS can perform certain textual substitutions in files, allowing you to
+keep some kinds of information automatically up to date in your files.
+All of the substitutions are triggered by a certain keyword pattern,
+surrounded by dollar signs. For example,
+
+<pre>$Revision$
+</pre>
+
+<p>in a file expands to something like
+
+<pre>$Revision$
+</pre>
+
+<p>and CVS continues to keep the revision string up to date as new
+revisions are committed.
+
+<ul>
+<li><a href="#Controlling_Keyword_Expansion">Controlling Keyword Expansion</a>: How to use keywords in your files.
+<li><a href="#List_Of_Keywords">List Of Keywords</a>: All the keywords.
+</ul>
+
+<p><hr>
+Node:<a name="Controlling_Keyword_Expansion">Controlling Keyword Expansion</a>,
+Next:<a rel=next href="#List_Of_Keywords">List Of Keywords</a>,
+Up:<a rel=up href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a>
+<br>
+
+<h3>Controlling Keyword Expansion</h3>
+
+<p>By default, CVS performs keyword expansion unless you tell it to stop.
+You can permanently suppress keyword expansion for a file with the -k
+option when you add the file to the project, or you can turn it off
+later by invoking admin with -k. The -k option offers several different
+modes of keyword control; usually you want mode o or b, for example:
+
+<pre>floss$ cvs add -ko chapter-9.sgml
+</pre>
+
+<p>This command added <code>chapter-9.sgml</code> to the project with keyword
+expansion turned off. It sets the file's default keyword expansion mode
+to <code>o</code>, which means no substitution. (Actually, the "o" stands for
+"old", meaning to substitute the string with its old value, which is the
+same as substituting it for itself, resulting in no change. I'm sure
+this logic made sense to somebody at the time.)
+
+<p>Each file's default keyword mode is stored in the repository. However,
+each working copy can also have its own local keyword substitution mode
+- accomplished with the -k options to checkout or update. You can also
+have a mode in effect for the duration of just one command, with the -k
+option to diff.
+
+<p>Here are all the possible modes, presented with the -k option prepended
+(as one would type at a command line). Any of these options can be used
+as either the default or local keyword substitution mode for a file:
+
+<ul>
+
+<li>-kkv - Expands to keyword and value. This is the default keyword
+expansion mode, so you don't need to set it for new files. You might
+use it to change a file from another keyword mode, however.
+
+<li>-kkvl - Like -kkv, but includes the locker's name if the revision is
+currently locked. (See the -l option to admin for more on this.)
+
+<li>-kk - Won't expand values in keyword strings, just uses the keyword
+name. For example, with this option,
+
+<pre>$Revision$
+</pre>
+
+<p>and
+
+<pre>$Revision$
+</pre>
+
+<p>would both "expand" (okay, contract) to:
+
+<pre>$Revision$
+</pre>
+
+</p><li>-ko - Reuses the keyword string found in the file (hence "o" for
+"old"), as it was in the working file just before the commit.
+
+<li>-kb - Like -ko, but also suppresses interplatform line-end conversions.
+The "b" stands for "binary"; it is the mode you should use for binary
+files.
+
+<li>-kv - Substitutes the keyword with its value, for example
+
+<pre>$Revision$
+</pre>
+
+<p>might become:
+
+<pre>1.5
+</pre>
+
+<p>Of course, after that's happened once, future substitutions will not
+take place, so this option should be used with care.
+
+</ul>
+
+<p><hr>
+Node:<a name="List_Of_Keywords">List Of Keywords</a>,
+Previous:<a rel=previous href="#Controlling_Keyword_Expansion">Controlling Keyword Expansion</a>,
+Up:<a rel=up href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a>
+<br>
+
+<h3>List Of Keywords</h3>
+
+<p>These are all the dollar-sign-delimited keywords that CVS recognizes.
+Following is a list of the keyword, a brief description, and an example
+of its expanded form:
+
+<ul>
+
+<li>$Author$ - Author of the change:
+
+<pre>$Author$
+</pre>
+
+<li>$Date$ - The date and time of the change, in UTC (GMT):
+
+<pre>$Date$
+</pre>
+
+<li>$Header$ - Various pieces of information thought to be useful: full
+path to the RCS file in the repository, revision, date (in UTC), author,
+state, and locker. (Lockers are rare; although in the following example,
+qsmith has a lock.):
+
+<pre>$Header: /usr/local/newrepos/myproj/hello.c,v 1.1 1999/06/01 \
+03:21:13 jrandom Exp qsmith $
+</pre>
+
+<li>$Id$ - Like $Header$, but without the full path to the RCS file:
+
+<pre>$Id$
+</pre>
+
+<li>$Log$
+<li>Revision 1.1 2002/06/23 14:32:50 llornkcor
+<li>some dev docs
+<li> - The log message of this revision, along with the revision
+number, date, and author. Unlike other keywords, the previous
+expansions are not replaced. Instead, they are pushed down, so that the
+newest expansion appears at the top of an ever-growing stack of $Log$
+newest expansion appears at the top of an ever-growing stack of Revision 1.1 2002/06/23 14:32:50 llornkcor
+newest expansion appears at the top of an ever-growing stack of some dev docs
+newest expansion appears at the top of an ever-growing stack of
+messages:
+
+<pre>$Log$
+<pre>Revision 1.1 2002/06/23 14:32:50 llornkcor
+<pre>some dev docs
+<pre> Revision 1.12 1999/07/19 06:12:43 jrandom
+ say hello in Aramaic
+</pre>
+
+<p> Any text preceding the $Log$
+<p> Any text preceding the Revision 1.1 2002/06/23 14:32:50 llornkcor
+<p> Any text preceding the some dev docs
+<p> Any text preceding the keyword on the same line will be prepended to the downward expansions too; this is so that if you use it in a comment in a program source file, all of the expansion is commented, too.
+
+</p><li>$Locker$ - Name of the person who has a lock on this revision (usually
+no one):
+
+<pre>$Locker$
+</pre>
+
+<li>$Name$ - Name of the sticky tag:
+
+<pre>$Name$
+</pre>
+
+<li>$RCSfile$ - Name of the RCS file in the repository:
+
+<pre>$RCSfile$
+</pre>
+
+<li>$Revision$ - Revision number:
+
+<pre>$Revision$
+</pre>
+
+<li>$Source$ - Full path to the RCS file in the repository:
+
+<pre>$Source$
+</pre>
+
+<li>$State$ - State of this revision:
+
+<pre>$State$
+</pre>
+
+</ul>
+
+<p><hr>
+Node:<a name="Repository_Administrative_Files">Repository Administrative Files</a>,
+Next:<a rel=next href="#Run_Control_Files">Run Control Files</a>,
+Previous:<a rel=previous href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a>,
+Up:<a rel=up href="#CVS_Reference">CVS Reference</a>
+<br>
+
+<h2>Repository Administrative Files</h2>
+
+<p>The repository's administrative files are stored in the CVSROOT
+subdirectory of the repository. These files control various aspects of
+CVS's behavior (in that repository only, of course).
+
+<p>You may also want to refer to the discussion of administrative files in
+<a href="#Repository_Administration">Repository Administration</a>, which includes examples.
+
+<ul>
+<li><a href="#Storage_And_Editing">Storage And Editing</a>: How to make changes to the administrative files.
+<li><a href="#Shared_Syntax">Shared Syntax</a>: Most administrative files share a common syntax.
+<li><a href="#Shared_Variables">Shared Variables</a>: Some administrative files can expand variables.
+<li><a href="#User_Variables">User Variables</a>: How to expand run-time variables set by users.
+<li><a href="#checkoutlist">checkoutlist</a>: The <code>checkoutlist</code> file.
+<li><a href="#commitinfo">commitinfo</a>: The <code>commitinfo</code> file.
+<li><a href="#config">config</a>: The <code>config</code> file.
+<li><a href="#cvsignore">cvsignore</a>: The <code>cvsignore</code> file.
+<li><a href="#cvswrappers">cvswrappers</a>: The <code>cvswrappers</code> file.
+<li><a href="#editinfo">editinfo</a>: The <code>editinfo</code> file.
+<li><a href="#history_file">history file</a>: The <code>history</code> file.
+<li><a href="#loginfo">loginfo</a>: The <code>loginfo</code> file.
+<li><a href="#modules">modules</a>: The <code>modules</code> file.
+<li><a href="#notify">notify</a>: The <code>notify</code> file.
+<li><a href="#passwd">passwd</a>: The <code>passwd</code> file.
+<li><a href="#rcsinfo">rcsinfo</a>: The <code>rcsinfo</code> file.
+<li><a href="#taginfo">taginfo</a>: The <code>taginfo</code> file.
+<li><a href="#users">users</a>: The <code>users</code> file.
+<li><a href="#val-tags">val-tags</a>: The <code>val-tags</code> file.
+<li><a href="#verifymsg">verifymsg</a>: The <code>verifymsg</code> file.
+</ul>
+
+<p><hr>
+Node:<a name="Storage_And_Editing">Storage And Editing</a>,
+Next:<a rel=next href="#Shared_Syntax">Shared Syntax</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>Storage And Editing</h3>
+
+<p>Generally, the administrative files are kept under revision control just
+like any other file in the repository (the exceptions are noted).
+However, unlike other files, checked-out copies of the administrative
+files are stored in the repository, right next to their corresponding
+RCS files in the <code>CVSROOT</code> subdirectory. It is these checked-out
+copies which actually govern CVS's behavior.
+
+<p>The normal way to modify the administrative files is to check out a
+working copy of the CVSROOT module, make your changes, and commit. CVS
+updates the checked-out copies in the repository automatically. (See
+<a href="#checkoutlist">checkoutlist</a>.) In an emergency, however, it is also possible to
+edit the checked-out copies in the repository directly.
+
+<p><hr>
+Node:<a name="Shared_Syntax">Shared Syntax</a>,
+Next:<a rel=next href="#Shared_Variables">Shared Variables</a>,
+Previous:<a rel=previous href="#Storage_And_Editing">Storage And Editing</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>Shared Syntax</h3>
+
+<p>In all of the administrative files, a <code>#</code> at the beginning of a line
+signifies a comment; that line is ignored by CVS. A backslash preceding
+a newline quotes the newline out of existence.
+
+<p>Some of the files (commitinfo, loginfo, taginfo, and rcsinfo) share more
+syntactic conventions as well. In these files, on the left of each line
+is a regular expression (which is matched against a file or directory
+name), and the rest of the line is a program, possibly with arguments,
+which is invoked if something is done to a file matching the regular
+expression. The program is run with its working directory set to the
+top of the repository.
+
+<p>In these files, there are two special regular expressions that may be
+used: ALL and DEFAULT. ALL matches any file or directory, whether or
+not there is some other match for it, and DEFAULT matches only if
+nothing else matched.
+
+<p><hr>
+Node:<a name="Shared_Variables">Shared Variables</a>,
+Next:<a rel=next href="#User_Variables">User Variables</a>,
+Previous:<a rel=previous href="#Shared_Syntax">Shared Syntax</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>Shared Variables</h3>
+
+<p>The info files also allow certain variables to be expanded at runtime.
+To expand a variable, precede it with a dollar sign (and put it in curly
+braces just to be safe). Here are the variables CVS knows about:
+
+<ul>
+
+<li>${CVSROOT} - The top of the repository.
+
+<li>${RCSBIN} - (Obsolete) Don't use this variable. It is only
+applicable in CVS Version 1.9.18 and older. Specifying it now may
+result in an error.
+
+<li>${CVSEDITOR} ${VISUAL} ${EDITOR} - These all expand to the editor
+that CVS is using for a log message.
+
+<li>${USER} - The user running CVS (on the server side).
+
+</ul>
+
+<p><hr>
+Node:<a name="User_Variables">User Variables</a>,
+Next:<a rel=next href="#checkoutlist">checkoutlist</a>,
+Previous:<a rel=previous href="#Shared_Variables">Shared Variables</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>User Variables</h3>
+
+<p>Users can also set their own variables when they run any CVS
+command. (See the -s global option.) These variables can be accessed
+in the <code>*info</code> files by preceding them with an equal sign, as in
+${=VAR}.
+
+<p><hr>
+Node:<a name="checkoutlist">checkoutlist</a>,
+Next:<a rel=next href="#commitinfo">commitinfo</a>,
+Previous:<a rel=previous href="#User_Variables">User Variables</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>checkoutlist</h3>
+
+<p>This contains a list of files for which checked-out copies should be
+kept in the repository. Each line gives the file name and an error
+message for CVS to print if, for some reason, the file cannot be checked
+out in the repository:
+
+<pre>FILENAME ERROR_MESSAGE
+</pre>
+
+<p>Because CVS already knows to keep checked-out copies of the existing
+administrative files, they do not need to be listed in checkoutlist.
+Specifically, the following files never need entries in checkoutlist:
+loginfo, rcsinfo, editinfo, verifymsg, commitinfo, taginfo, ignore,
+checkoutlist, cvswrappers, notify, modules, readers, writers, and
+config.
+
+<p><hr>
+Node:<a name="commitinfo">commitinfo</a>,
+Next:<a rel=next href="#config">config</a>,
+Previous:<a rel=previous href="#checkoutlist">checkoutlist</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>commitinfo</h3>
+
+<p>Specifies programs to run at commit time, based on what's being
+committed. Each line consists of a regular expression followed by a
+command template:
+
+<pre>REGULAR_EXPRESSION PROGRAM [ARGUMENTS]
+</pre>
+
+<p>The PROGRAM is passed additional arguments following any arguments you
+may have written into the template. These additional arguments are the
+full path to the repository, followed by the name of each file about to
+be committed. These files can be examined by PROGRAM; their contents
+are the same as those of the working copy files about to be committed.
+If PROGRAM exits with nonzero status, the commit fails; otherwise, it
+succeeds. (See also <a href="#Shared_Syntax">Shared Syntax</a> earlier in this chapter.)
+
+<p><hr>
+Node:<a name="config">config</a>,
+Next:<a rel=next href="#cvsignore">cvsignore</a>,
+Previous:<a rel=previous href="#commitinfo">commitinfo</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>config</h3>
+
+<p>Controls various global (non-project-specific) repository parameters.
+The syntax of each line is
+
+<pre>ParameterName=yes|no
+</pre>
+
+<p>except for the LockDir parameter, which takes an absolute pathname as
+argument.
+
+<p>The following parameters are supported:
+
+<ul>
+
+<li>RCSBIN (default: <code>=no</code>) - (Obsolete) This option is silently
+accepted for backwards compatibility, but no longer has any effect.
+
+<li>SystemAuth (default: <code>=no</code>) - If <code>yes</code>, CVS pserver
+authentication tries the system user database - usually
+<code>/etc/passwd</code> - if a username is not found in
+<code>CVSROOT/passwd</code>. If <code>no</code>, the user must exist in
+<code>CVSROOT/passwd</code> to gain access via the <code>:pserver:</code> method.
+
+<li>PreservePermissions (default: <code>=no</code>) - If <code>yes</code>, CVS tries to
+preserve permissions and other special file system information (such as
+device numbers and symbolic link targets) for files. You probably don't
+want to do this, as it does not necessarily behave as expected. (See the
+node <cite>Special Files</cite> in the Cederqvist manual for details.)
+
+<li>TopLevelAdmin (default: <code>=no</code>) - If <code>yes</code>, checkouts create a
+<code>CVS/</code> subdirectory next to each working copy tree (in the parent
+directory of the working copy). This can be useful if you will be
+checking out many working copies from the same repository; on the other
+hand, setting it here affects everyone who uses this repository.
+
+<li>LockDir (unset by default) - The argument after the equal sign is a
+path to a directory in which CVS can create lockfiles. If not set,
+lockfiles are created in the repository, in locations corresponding to
+each project's RCS files. This means that users of those projects must
+have file-system-level write access to those repository directories.
+
+</ul>
+
+<p><hr>
+Node:<a name="cvsignore">cvsignore</a>,
+Next:<a rel=next href="#cvswrappers">cvswrappers</a>,
+Previous:<a rel=previous href="#config">config</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>cvsignore</h3>
+
+<p>Ignores certain files when doing updates, imports, or releases. By
+default, CVS already ignores some kinds of files. (For a full list, see
+the -I option to import, earlier in this chapter.) You can add to this
+list by putting additional file names or wildcard patterns in the
+cvsignore file. Each line gives a file name or pattern, for example:
+
+<pre>README.msdos
+*.html
+blah?.out
+</pre>
+
+<p>This causes CVS to ignore any file named <code>README.msdos</code>, any file
+ending in <code>.html</code>, and any file beginning with <code>blah</code> and
+ending with <code>.out</code>. (Technically, you can name multiple files or
+patterns on each line, separated by whitespace, but it is more readable
+to keep them to one per line. The whitespace separation rule does,
+unfortunately, mean that there's no way to specify a space in a file
+name, except to use wildcards.)
+
+<p>A <code>!</code> anywhere in the list cancels all previous entries. (See
+<a href="#_CVSIGNORE">$CVSIGNORE</a> in the section <a href="#Environment_Variables">Environment Variables</a> in
+this chapter for a fuller discussion of ignore processing.)
+
+<p><hr>
+Node:<a name="cvswrappers">cvswrappers</a>,
+Next:<a rel=next href="#editinfo">editinfo</a>,
+Previous:<a rel=previous href="#cvsignore">cvsignore</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>cvswrappers</h3>
+
+<p>Specifies certain filtering behaviors based on file name. Each line has
+a file-globbing pattern (that is, a file name or file wildcards),
+followed by an option indicating the filter type and an argument for the
+option.
+
+<p>Options:
+
+<ul>
+
+<li>-m - Specifies an update method. Possible arguments are MERGE, which
+means to merge changes into working files automatically, and COPY, which
+means don't try to automerge but present the user with both versions of
+the file and let them work it out. MERGE is the default, except for
+binary files (those whose keyword substitution mode is -kb). (See the
+<a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> section in this chapter.)
+Files marked as binary automatically use the COPY method, so there is no
+need to make a -m COPY wrapper for them.
+
+<li>-k - Specifies a keyword substitution mode. All of the usual modes are
+possible. (See the <a href="#Keyword_Substitution__RCS_Keywords_">Keyword Substitution (RCS Keywords)</a> section in
+this chapter for a complete list.)
+
+</ul>
+
+<p>Here is an example cvswrappers file:
+
+<pre>*.blob -m COPY
+*.blink -k o
+</pre>
+
+<p>This cvswrappers file says to not attempt merges on files ending in
+<code>.blob</code> and suppress keyword substitution for files ending in
+<code>.blink</code>. (See also the file <code>.cvswrappers</code> in the
+<a href="#Working_Copy_Files">Working Copy Files</a> section in this chapter.)
+
+<p><hr>
+Node:<a name="editinfo">editinfo</a>,
+Next:<a rel=next href="#history_file">history file</a>,
+Previous:<a rel=previous href="#cvswrappers">cvswrappers</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>editinfo</h3>
+
+<p>This file is obsolete. Very.
+
+<p><hr>
+Node:<a name="history_file">history file</a>,
+Next:<a rel=next href="#loginfo">loginfo</a>,
+Previous:<a rel=previous href="#editinfo">editinfo</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>history file</h3>
+
+<p>Stores an ever-accumulating history of activity in the repository, for
+use by the cvs history command. To disable this feature, simply remove
+the history file. If you don't remove the file, you should probably
+make it world-writeable to avoid permission problems later.
+
+<p>The contents of this file do not modify CVS's behavior in any way
+(except for the output of cvs history, of course).
+
+<p><hr>
+Node:<a name="loginfo">loginfo</a>,
+Next:<a rel=next href="#modules">modules</a>,
+Previous:<a rel=previous href="#history_file">history file</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>loginfo</h3>
+
+<p>Specifies programs to run on the log message for each commit, based on
+what's being committed. Each line consists of a regular expression
+followed by a command template:
+
+<pre>REGULAR_EXPRESSION PROGRAM [ARGUMENTS]
+</pre>
+
+<p>The PROGRAM is passed the log message on its standard input.
+
+<p>Several special codes are available for use in the arguments: <code>%s</code>
+expands to the names of the files being committed, <code>%V</code> expands to
+the old revisions from before the commit, and <code>%v</code> expands to the
+new revisions after the commit. When there are multiple files involved,
+each element of the expansion is separated from the others by
+whitespace. For example, in a commit involving two files, <code>%s</code>
+might expand into <code>hello.c&nbsp;README.txt</code>, and <code>%v</code> into
+<code>1.17&nbsp;1.12</code>.
+
+<p>You may combine codes inside curly braces, in which case, each unit of
+expansion is internally separated by commas and externally separated
+from the other units by whitespace. Continuing the previous example,
+<code>%{sv}</code> expands into <code>hello.c,1.17&nbsp;README.txt,1.12</code>.
+
+<p>If any <code>%</code> expansion is done at all, the expansion is prefixed by
+the path to the project subdirectory (relative to the top of the
+repository). So that last expansion would actually be:
+
+<pre>myproj hello.c,1.17 README.txt,1.12
+</pre>
+
+<p>If PROGRAM exits with nonzero status, the commit fails; otherwise, it
+succeeds. (See also the <a href="#Shared_Syntax">Shared Syntax</a> section in this
+chapter.)
+
+<p><hr>
+Node:<a name="modules">modules</a>,
+Next:<a rel=next href="#notify">notify</a>,
+Previous:<a rel=previous href="#loginfo">loginfo</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>modules</h3>
+
+<p>This maps names to repository directories. The general syntax of each
+line is:
+
+<pre>MODULE&nbsp;[OPTIONS]&nbsp;[&amp;OTHERMODULE...]&nbsp;[DIR]&nbsp;[FILES]
+</pre>
+
+<p>DIR need not be a top-level project directory - it could be a
+subdirectory. If any FILES are specified, the module consists of only
+those files from the directory.
+
+<p>An ampersand followed by a module name means to include the expansion of
+that module's line in place.
+
+<p>Options:
+
+<ul>
+
+<li>-a - This is an <dfn>alias</dfn> module, meaning it expands literally to
+everything after the OPTIONS. In this case, the usual DIR/FILES
+behavior is turned off, and everything after the OPTIONS is treated as
+other modules or repository directories.
+
+<p>If you use the -a option, you may exclude certain directories from other
+modules by putting them after an exclamation point (!). For example
+
+<pre>top_proj -a !myproj/a-subdir !myproj/b-subdir myproj
+</pre>
+
+<p>means that checking out <code>top_proj</code> will get all of <code>myproj</code>
+except <code>a-subdir</code> and <code>b-subdir</code>.
+
+</p><li>-d NAME - Names the working directory NAME instead of the module name.
+
+<li>-e PROGRAM - Runs PROGRAM whenever files in this module are exported.
+
+<li>-i PROGRAM - Runs PROGRAM whenever files in this module are committed.
+The program is given a single argument - the full pathname in the
+repository of the file in question. (See <a href="#commitinfo">commitinfo</a>,
+<a href="#loginfo">loginfo</a>, and <a href="#verifymsg">verifymsg</a> for more sophisticated ways to
+run commit-triggered programs.)
+
+<li>-o PROGRAM - Runs PROGRAM whenever files in this module are checked
+out. The program is given a single argument, the name of the module.
+
+<li>-s STATUS - Declares a status for the module. When the modules file is
+printed (with cvs checkout -s), the modules are sorted by module status
+and then by name. This option has no other effects in CVS, so go wild.
+You can use it to sort anything - status, person responsible for the
+module, or the module's file language, for example.
+
+<li>-t PROGRAM - Runs PROGRAM whenever files in this module are tagged with
+cvs rtag. The program is passed two arguments: the name of the module
+and the tag name. The program is not used for tag, only for rtag. I
+have no idea why this distinction is made. You may find the taginfo
+file more useful if you want to run programs at tag time.
+
+<li>-u PROGRAM - Runs PROGRAM whenever a working copy of the module is
+updated from its top-level directory. The program is given a single
+argument, the full path to the module's repository.
+
+</ul>
+
+<p><hr>
+Node:<a name="notify">notify</a>,
+Next:<a rel=next href="#passwd">passwd</a>,
+Previous:<a rel=previous href="#modules">modules</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>notify</h3>
+
+<p>Controls how the notifications for watched files are performed. (You may
+want to read up on the watch and edit commands, or see the section
+<a href="#Watches__CVS_As_Telephone_">Watches (CVS As Telephone)</a> in <a href="#Advanced_CVS">Advanced CVS</a>.) Each line is
+of the usual form:
+
+<p>REGULAR_EXPRESSION&nbsp;PROGRAM&nbsp;[ARGUMENTS]
+
+<p>A <code>%s</code> in ARGUMENTS is expanded to the name of the user to be
+notified, and the rest of the information regarding the notification is
+passed to PROGRAM on standard input (usually this information is a brief
+message suitable for emailing to the user). (See the section
+<a href="#Shared_Syntax">Shared Syntax</a> earlier in this chapter.)
+
+<p>As shipped with CVS, the notify file has one line
+
+<pre>ALL mail %s -s "CVS notification"
+</pre>
+
+<p>which is often all you need.
+
+<p><hr>
+Node:<a name="passwd">passwd</a>,
+Next:<a rel=next href="#rcsinfo">rcsinfo</a>,
+Previous:<a rel=previous href="#notify">notify</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>passwd</h3>
+
+<p>Provides authentication information for the pserver access method. Each
+line is of the form:
+
+<p>USER:ENCRYPTED_PASSWORD[:SYSTEM_USER]
+
+<p>If no SYSTEM_USER is given, USER is taken as the system username.
+
+<p><hr>
+Node:<a name="rcsinfo">rcsinfo</a>,
+Next:<a rel=next href="#taginfo">taginfo</a>,
+Previous:<a rel=previous href="#passwd">passwd</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>rcsinfo</h3>
+
+<p>Specifies a form that should be filled out for log messages that are
+written with an interactive editor. Each line of rcsinfo looks like:
+
+<p>REGULAR_EXPRESSION&nbsp;FILE_CONTAINING_TEMPLATE
+
+<p>This template is brought to remote working copies at checkout time, so
+if the template file or rcsinfo file changes after checkout, the remote
+copies won't know about it and will continue to use the old template.
+(See also the section <a href="#Shared_Syntax">Shared Syntax</a> in this chapter.)
+
+<p><hr>
+Node:<a name="taginfo">taginfo</a>,
+Next:<a rel=next href="#users">users</a>,
+Previous:<a rel=previous href="#rcsinfo">rcsinfo</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>taginfo</h3>
+
+<p>Runs a program at tag time (usually done to check that the tag name
+matches some pattern). Each line is of the form:
+
+<p>REGULAR_EXPRESSION&nbsp;PROGRAM
+
+<p>The program is handed a set group of arguments. In order, they are the
+tag name, the operation (see below), the repository, and then as many
+file name/revision-number pairs as there are files involved in the tag.
+The file/revision pairs are separated by whitespace, like the rest of
+the arguments.
+
+<p>The operation is one of <code>add</code>, <code>mov</code>, or <code>del</code>
+(<code>mov</code> means the -F option to tag was used).
+
+<p>If PROGRAM exits with nonzero status, the tag operation will not
+succeed. (See also the section <a href="#Shared_Syntax">Shared Syntax</a> in this chapter.)
+
+<p><hr>
+Node:<a name="users">users</a>,
+Next:<a rel=next href="#val-tags">val-tags</a>,
+Previous:<a rel=previous href="#taginfo">taginfo</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>users</h3>
+
+<p>Maps usernames to email addresses. Each line looks like:
+
+<p>USERNAME:EMAIL_ADDRESS
+
+<p>This sends watch notifications to EMAIL_ADDRESS instead of to USERNAME
+at the repository machine. (All this really does is control the
+expansion of %s in the notify file.) If EMAIL_ADDRESS includes
+whitespace, make sure to surround it with quotes.
+
+<p>If user aliasing is being used in the passwd file, the username that
+will be matched is the CVS username (the one on the left), not the
+system username (the one on the right, if any).
+
+<p><hr>
+Node:<a name="val-tags">val-tags</a>,
+Next:<a rel=next href="#verifymsg">verifymsg</a>,
+Previous:<a rel=previous href="#users">users</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>val-tags</h3>
+
+<p>Caches valid tag names for speedier lookups. You should never need to
+edit this file, but you may need to change its permissions, or even
+ownership, if people are having trouble retrieving or creating tags.
+
+<p><hr>
+Node:<a name="verifymsg">verifymsg</a>,
+Previous:<a rel=previous href="#val-tags">val-tags</a>,
+Up:<a rel=up href="#Repository_Administrative_Files">Repository Administrative Files</a>
+<br>
+
+<h3>verifymsg</h3>
+
+<p>Used in conjunction with rcsinfo to verify the format of log messages.
+Each line is of the form:
+
+<p>REGULAR_EXPRESSION&nbsp;PROGRAM&nbsp;[ARGUMENTS]
+
+<p>The full path to the current log message template (see <a href="#rcsinfo">rcsinfo</a>
+earlier in this chapter) is appended after the last argument written in
+the verifymsg file. If PROGRAM exits with nonzero status, the commit
+fails.
+
+<p><hr>
+Node:<a name="Run_Control_Files">Run Control Files</a>,
+Next:<a rel=next href="#Working_Copy_Files">Working Copy Files</a>,
+Previous:<a rel=previous href="#Repository_Administrative_Files">Repository Administrative Files</a>,
+Up:<a rel=up href="#CVS_Reference">CVS Reference</a>
+<br>
+
+<h2>Run Control Files</h2>
+
+<p>There are a few files on the client (working copy) side that affect
+CVS's behavior. In some cases, they are analogs of repository
+administrative files; in other cases, they control behaviors that are
+only appropriate for the client side.
+
+<h3><code>.cvsrc</code></h3>
+
+<p>Specifies options that you want to be used automatically with every CVS
+command. The format of each line is
+
+<p>COMMAND&nbsp;OPTIONS
+
+<p>where each COMMAND is an unabbreviated CVS command, such as checkout or
+update (but not co or up). The OPTIONS are those that you want to
+always be in effect when you run that command. Here is a common
+<code>.cvsrc</code> line:
+
+<pre>update -d -P
+</pre>
+
+<p>To specify global options, simple use cvs as the COMMAND.
+
+<h3><code>.cvsignore</code></h3>
+
+<p>Specifies additional ignore patterns. (See <a href="#cvsignore">cvsignore</a> in the
+<a href="#Repository_Administrative_Files">Repository Administrative Files</a> section in this chapter for the
+syntax.)
+
+<p>You can have a .cvsignore file in your home directory, which will apply
+every time you use CVS. You can also have directory-specific ones in
+each project directory of a working copy (these last only apply to the
+directory where the .cvsignore is located, and not to its
+subdirectories).
+
+<p>(See <a href="#_CVSIGNORE">$CVSIGNORE</a> in the section <a href="#Environment_Variables">Environment Variables</a>
+in this chapter, for a fuller discussion of ignore processing.)
+
+<h3><code>.cvspass</code></h3>
+
+<p>Stores passwords for each repository accessed via the pserver method.
+Each line is of the form:
+
+<p>REPOSITORY&nbsp;LIGHTLY_SCRAMBLED_PASSWORD
+
+<p>The password is essentially stored in cleartext - a very mild
+scrambling is done to prevent accidental compromises (such as the root
+user unintentionally looking inside the file). However, this scrambling
+will not deter any serious-minded person from gaining the password if
+they get access to the file.
+
+<p>The .cvspass file is portable. You can copy it from one machine to
+another and have all of your passwords at the new machine, without ever
+having run cvs login there. (See also the <a href="#login">login</a> and
+<a href="#logout">logout</a> commands.)
+
+<h3><code>.cvswrappers</code></h3>
+
+<p>This is a client side version of the cvswrappers file. (See the
+<a href="#Repository_Administrative_Files">Repository Administrative Files</a> section in this chapter.)
+There can be a <code>.cvswrappers</code> file in your home directory and in
+each directory of a working copy directory, just as with
+<code>.cvsignore</code>.
+
+<p><hr>
+Node:<a name="Working_Copy_Files">Working Copy Files</a>,
+Next:<a rel=next href="#Environment_Variables">Environment Variables</a>,
+Previous:<a rel=previous href="#Run_Control_Files">Run Control Files</a>,
+Up:<a rel=up href="#CVS_Reference">CVS Reference</a>
+<br>
+
+<h2>Working Copy Files</h2>
+
+<p>The CVS/ administrative subdirectories in each working copy contain some
+subset of the following files.
+
+<ul>
+<li>CVS/Base/
+<li>CVS/Baserev
+<li>CVS/Baserev.tmp
+<li>CVS/Checkin.prog
+<li>CVS/Entries
+<li>CVS/Entries.Backup
+<li>CVS/Entries.Log
+<li>CVS/Entries.Static
+<li>CVS/Notify
+<li>CVS/Notify.tmp
+<li>CVS/Repository
+<li>CVS/Root
+<li>CVS/Tag
+<li>CVS/Template
+<li>CVS/Update.prog
+</ul>
+
+<p>Here is what each file or directory does:
+
+<h3><code>CVS/Base/</code>&nbsp;&nbsp;(directory)</h3>
+
+<p>If watches are on, <code>cvs&nbsp;edit</code> stores the original copy of the
+file in this directory. That way, <code>cvs&nbsp;unedit</code> can work even
+if it can't reach the server.
+
+<h3><code>CVS/Baserev</code></h3>
+
+<p>Lists the revision for each file in <code>Base/</code>. Each line looks like
+this:
+
+<pre>FILE/REVISION/EXPANSION
+</pre>
+
+<p>EXPANSION is currently ignored to allow for, well, future expansion.
+
+<h3><code>CVS/Baserev.tmp</code></h3>
+
+<p>This is the temp file for the preceding. (See <code>CVS/Notify.tmp</code> or
+<code>CVS/Entries.Backup</code> later on for further explanation.)
+
+<h3><code>CVS/Checkin.prog</code></h3>
+
+<p>Records the name of the program specified by the -i option in the
+modules file. (See the <a href="#Repository_Administrative_Files">Repository Administrative Files</a> section
+in this chapter.)
+
+<h3><code>CVS/Entries</code></h3>
+
+<p>Stores the revisions for the files in this directory. Each line is of
+the form:
+
+<pre>[CODE_LETTER]/FILE/REVISION/DATE/[KEYWORD_MODE]/[STICKY_OPTION]
+</pre>
+
+<p>If CODE_LETTER is present, it must be <code>D</code> for directory (anything
+else is silently ignored by CVS, to allow for future expansion), and the
+rest of the items on the line are absent.
+
+<p>This file is always present.
+
+<h3><code>CVS/Entries.Backup</code></h3>
+
+<p>This is just a temp file. If you're writing some program to modify the
+<code>Entries</code> file, have it write the new contents to
+<code>Entries.backup</code> and then atomically rename it to <code>Entries</code>.
+
+<h3><code>CVS/Entries.Log</code></h3>
+
+<p>This is basically a patch file to be applied to <code>Entries</code> after
+<code>Entries</code> has been read (this is an efficiency hack, to avoid
+having to rewrite all of <code>Entries</code> for every little change). The
+format is the same as <code>Entries</code>, except that there is an additional
+mandatory code letter at the front of every line: An <code>A</code> means this
+line is to be added to what's in <code>Entries</code>; <code>R</code> means it's to
+be removed from what's in <code>Entries</code>. Any other letters should be
+silently ignored, to allow for future expansion.
+
+<h3><code>CVS/Entries.Static</code></h3>
+
+<p>If this file exists, it means only part of the directory was fetched
+from the repository, and CVS will not create additional files in that
+directory. This condition can usually be cleared by using
+<code>update&nbsp;-d</code>.
+
+<h3><code>CVS/Notify</code></h3>
+
+<p>Stores notifications that have not yet been sent to the server.
+
+<h3><code>CVS/Notify.tmp</code></h3>
+
+<p>Temp file for <code>Notify</code>. The usual procedure for modifying
+<code>Notify</code> is to write out <code>Notify.tmp</code> and then rename it to
+<code>Notify</code>.
+
+<h3><code>CVS/Repository</code></h3>
+
+<p>The path to the project-specific subdirectory in the repository. This
+may be an absolute path, or it may be relative to the path given in
+Root.
+
+<p>This file is always present.
+
+<h3><code>CVS/Root</code></h3>
+
+<p>This is the repository; that is, the value of the <code>$CVSROOT</code>
+environment variable or the argument to the -d global option.
+
+<p>This file is always present.
+
+<h3><code>CVS/Tag</code></h3>
+
+<p>If there is a sticky tag or date on this directory, it is recorded in
+the first line of the file. The first character is a single letter
+indicating the type of tag: <code>T</code>, <code>N</code>, or <code>D</code>, for branch
+tag, nonbranch tag, or date respectively. The rest of the line is the
+tag or date itself.
+
+<h3><code>CVS/Template</code></h3>
+
+<p>Contains a log message template as specified by the rcsinfo file. (See
+<a href="#Repository_Administrative_Files">Repository Administrative Files</a> earlier in this chapter.) It
+is relevant only for remote working copies; working copies on the same
+machine as the repository just read rcsinfo directly.
+
+<h3><code>CVS/Update.prog</code></h3>
+
+<p>Records the name of the program specified by the -u option in the
+modules file. (See the <a href="#Repository_Administrative_Files">Repository Administrative Files</a> section
+in this chapter.)
+
+<p><hr>
+Node:<a name="Environment_Variables">Environment Variables</a>,
+Previous:<a rel=previous href="#Working_Copy_Files">Working Copy Files</a>,
+Up:<a rel=up href="#CVS_Reference">CVS Reference</a>
+<br>
+
+<h2>Environment Variables</h2>
+
+<p>These are all the environment variables that affect CVS.
+
+<ul>
+<li><a href="#_COMSPEC">$COMSPEC</a>:
+<li><a href="#_CVS_CLIENT_LOG">$CVS_CLIENT_LOG</a>:
+<li><a href="#_CVS_CLIENT_PORT">$CVS_CLIENT_PORT</a>:
+<li><a href="#_CVSEDITOR">$CVSEDITOR</a>:
+<li><a href="#_CVSIGNORE">$CVSIGNORE</a>:
+<li><a href="#_CVS_IGNORE_REMOTE_ROOT">$CVS_IGNORE_REMOTE_ROOT</a>:
+<li><a href="#_CVS_PASSFILE">$CVS_PASSFILE</a>:
+<li><a href="#_CVS_RCMD_PORT">$CVS_RCMD_PORT</a>:
+<li><a href="#_CVSREAD">$CVSREAD</a>:
+<li><a href="#_CVSROOT">$CVSROOT</a>:
+<li><a href="#_CVS_RSH">$CVS_RSH</a>:
+<li><a href="#_CVS_SERVER">$CVS_SERVER</a>:
+<li><a href="#_CVS_SERVER_SLEEP">$CVS_SERVER_SLEEP</a>:
+<li><a href="#_CVSUMASK">$CVSUMASK</a>:
+<li><a href="#_CVSWRAPPERS">$CVSWRAPPERS</a>:
+<li><a href="#_EDITOR">$EDITOR</a>:
+<li><a href="#_HOME__HOMEDRIVE___HOMEPATH_">$HOME %HOMEDRIVE% %HOMEPATH%</a>:
+<li><a href="#_PATH">$PATH</a>:
+<li><a href="#_TEMP__TMP__TMPDIR">$TEMP $TMP $TMPDIR</a>:
+<li><a href="#_VISUAL">$VISUAL</a>:
+</ul>
+
+<p><hr>
+Node:<a name="_COMSPEC">$COMSPEC</a>,
+Next:<a rel=next href="#_CVS_CLIENT_LOG">$CVS_CLIENT_LOG</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$COMSPEC</h3>
+
+<p>This is used in OS/2 only; it specifies the name of the command
+interpreter. It defaults to <code>CMD.EXE</code>.
+
+<p><hr>
+Node:<a name="_CVS_CLIENT_LOG">$CVS_CLIENT_LOG</a>,
+Next:<a rel=next href="#_CVS_CLIENT_PORT">$CVS_CLIENT_PORT</a>,
+Previous:<a rel=previous href="#_COMSPEC">$COMSPEC</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_CLIENT_LOG</h3>
+
+<p>Used for debugging the client/server protocol. Set this variable to a
+file name before you start using CVS; all traffic to the server will be
+logged in filename.in, and everything from the server will be logged in
+filename.out.
+
+<p><hr>
+Node:<a name="_CVS_CLIENT_PORT">$CVS_CLIENT_PORT</a>,
+Next:<a rel=next href="#_CVSEDITOR">$CVSEDITOR</a>,
+Previous:<a rel=previous href="#_CVS_CLIENT_LOG">$CVS_CLIENT_LOG</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_CLIENT_PORT</h3>
+
+<p>Used in Kerberos-authenticated client/server access.
+
+<p><hr>
+Node:<a name="_CVSEDITOR">$CVSEDITOR</a>,
+Next:<a rel=next href="#_CVSIGNORE">$CVSIGNORE</a>,
+Previous:<a rel=previous href="#_CVS_CLIENT_PORT">$CVS_CLIENT_PORT</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVSEDITOR</h3>
+
+<p>Specifies the program to use to edit log messages for commits. This
+overrides <code>$EDITOR</code> and <code>$VISUAL</code>.
+
+<p><hr>
+Node:<a name="_CVSIGNORE">$CVSIGNORE</a>,
+Next:<a rel=next href="#_CVS_IGNORE_REMOTE_ROOT">$CVS_IGNORE_REMOTE_ROOT</a>,
+Previous:<a rel=previous href="#_CVSEDITOR">$CVSEDITOR</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVSIGNORE</h3>
+
+<p>A whitespace-separated list of file names and wildcard patterns that CVS
+should ignore. (See also the -I option to the <a href="#import">import</a> command.)
+
+<p>This variable is appended last to the ignore list during a command. The
+list is built up in this order: <code>CVSROOT/cvsignore</code>, the
+<code>.cvsignore</code> file in your home directory, the <code>$CVSIGNORE</code>
+variable, any -I command option, and finally the contents of
+<code>.cvsignore</code> files in the working copy used as CVS works in each
+directory. A <code>!</code> as the ignore specification at any point
+nullifies the entire ignore list built up to that point.
+
+<p><hr>
+Node:<a name="_CVS_IGNORE_REMOTE_ROOT">$CVS_IGNORE_REMOTE_ROOT</a>,
+Next:<a rel=next href="#_CVS_PASSFILE">$CVS_PASSFILE</a>,
+Previous:<a rel=previous href="#_CVSIGNORE">$CVSIGNORE</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_IGNORE_REMOTE_ROOT</h3>
+
+<p>Recently obsolete.
+
+<p><hr>
+Node:<a name="_CVS_PASSFILE">$CVS_PASSFILE</a>,
+Next:<a rel=next href="#_CVS_RCMD_PORT">$CVS_RCMD_PORT</a>,
+Previous:<a rel=previous href="#_CVS_IGNORE_REMOTE_ROOT">$CVS_IGNORE_REMOTE_ROOT</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_PASSFILE</h3>
+
+<p>Tells CVS to use some file other than .cvspass in your home directory.
+(See the file <code>.cvspass</code> in the <a href="#Run_Control_Files">Run Control Files</a> section in
+this chapter.)
+
+<p><hr>
+Node:<a name="_CVS_RCMD_PORT">$CVS_RCMD_PORT</a>,
+Next:<a rel=next href="#_CVSREAD">$CVSREAD</a>,
+Previous:<a rel=previous href="#_CVS_PASSFILE">$CVS_PASSFILE</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_RCMD_PORT</h3>
+
+<p>Specifies the port number to contact the rcmd daemon on the server side.
+(This variable is currently ignored in Unix CVS clients.)
+
+<p><hr>
+Node:<a name="_CVSREAD">$CVSREAD</a>,
+Next:<a rel=next href="#_CVSROOT">$CVSROOT</a>,
+Previous:<a rel=previous href="#_CVS_RCMD_PORT">$CVS_RCMD_PORT</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVSREAD</h3>
+
+<p>Makes working copy files read-only on checkout and update, if possible
+(the default is for them to be read-write). (See also the -r global
+option.)
+
+<p><hr>
+Node:<a name="_CVSROOT">$CVSROOT</a>,
+Next:<a rel=next href="#_CVS_RSH">$CVS_RSH</a>,
+Previous:<a rel=previous href="#_CVSREAD">$CVSREAD</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVSROOT</h3>
+
+<p>This specifies the path to the repository. This is overridden with the
+-d global option and by the ambient repository for a given working copy.
+The path to the repository may be preceded by an access method,
+username, and host, according to the following syntax:
+
+<pre>[[:METHOD:][[USER@]HOST]:]/REPOSITORY_PATH
+</pre>
+
+<p>See the -d global option, in the section <a href="#Global_Options">Global Options</a> near
+the beginning of this chapter, for a list of valid methods.
+
+<p><hr>
+Node:<a name="_CVS_RSH">$CVS_RSH</a>,
+Next:<a rel=next href="#_CVS_SERVER">$CVS_SERVER</a>,
+Previous:<a rel=previous href="#_CVSROOT">$CVSROOT</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_RSH</h3>
+
+<p>Specifies an external program for connecting to the server when using
+the <code>:ext:</code> access method. Defaults to <code>rsh</code>, but <code>ssh</code>
+is a common replacement value.
+
+<p><hr>
+Node:<a name="_CVS_SERVER">$CVS_SERVER</a>,
+Next:<a rel=next href="#_CVS_SERVER_SLEEP">$CVS_SERVER_SLEEP</a>,
+Previous:<a rel=previous href="#_CVS_RSH">$CVS_RSH</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_SERVER</h3>
+
+<p>Program to invoke for CVS on the server side. Defaults to <code>cvs</code>,
+of course.
+
+<p><hr>
+Node:<a name="_CVS_SERVER_SLEEP">$CVS_SERVER_SLEEP</a>,
+Next:<a rel=next href="#_CVSUMASK">$CVSUMASK</a>,
+Previous:<a rel=previous href="#_CVS_SERVER">$CVS_SERVER</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVS_SERVER_SLEEP</h3>
+
+<p>Delays the start of the server child process by the specified number of
+seconds. This is used only for debugging, to allow time for a debugger
+to connect.
+
+<p><hr>
+Node:<a name="_CVSUMASK">$CVSUMASK</a>,
+Next:<a rel=next href="#_CVSWRAPPERS">$CVSWRAPPERS</a>,
+Previous:<a rel=previous href="#_CVS_SERVER_SLEEP">$CVS_SERVER_SLEEP</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVSUMASK</h3>
+
+<p>Permissions for files and directories in the repository. (You probably
+don't want to set this; it doesn't work for client/server anyway.)
+
+<p><hr>
+Node:<a name="_CVSWRAPPERS">$CVSWRAPPERS</a>,
+Next:<a rel=next href="#_EDITOR">$EDITOR</a>,
+Previous:<a rel=previous href="#_CVSUMASK">$CVSUMASK</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$CVSWRAPPERS</h3>
+
+<p>A whitespace-separated list of file names, wildcards, and arguments that
+CVS should use as wrappers. (See <a href="#cvswrappers">cvswrappers</a> in the
+<a href="#Repository_Administrative_Files">Repository Administrative Files</a> section in this chapter for
+more information.)
+
+<p><hr>
+Node:<a name="_EDITOR">$EDITOR</a>,
+Next:<a rel=next href="#_HOME__HOMEDRIVE___HOMEPATH_">$HOME %HOMEDRIVE% %HOMEPATH%</a>,
+Previous:<a rel=previous href="#_CVSWRAPPERS">$CVSWRAPPERS</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$EDITOR</h3>
+
+<p>(See <a href="#_CVSEDITOR">$CVSEDITOR</a>.)
+
+<p><hr>
+Node:<a name="_HOME__HOMEDRIVE___HOMEPATH_">$HOME %HOMEDRIVE% %HOMEPATH%</a>,
+Next:<a rel=next href="#_PATH">$PATH</a>,
+Previous:<a rel=previous href="#_EDITOR">$EDITOR</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$HOME %HOMEDRIVE% %HOMEPATH%</h3>
+
+<p>Where the <code>.cvsrc</code>, <code>.cvspass</code>, and other such files are found
+(under Unix, only <code>$HOME</code> is used). In Windows NT,
+<code>%HOMEDRIVE%</code> and <code>%HOMEPATH%</code> might be set for you; in
+Windows 95, you may need to set them for yourself.
+
+<p>In Windows 95, you may also need to set <code>%HOME%</code>. Make sure not to
+give it a trailing backslash; use set <code>HOME=C:</code> or something
+similar.
+
+<p><hr>
+Node:<a name="_PATH">$PATH</a>,
+Next:<a rel=next href="#_TEMP__TMP__TMPDIR">$TEMP $TMP $TMPDIR</a>,
+Previous:<a rel=previous href="#_HOME__HOMEDRIVE___HOMEPATH_">$HOME %HOMEDRIVE% %HOMEPATH%</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$PATH</h3>
+
+<p>Obsolete.
+
+<p><hr>
+Node:<a name="_TEMP__TMP__TMPDIR">$TEMP $TMP $TMPDIR</a>,
+Next:<a rel=next href="#_VISUAL">$VISUAL</a>,
+Previous:<a rel=previous href="#_PATH">$PATH</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$TEMP $TMP $TMPDIR</h3>
+
+<p>Where temporary files go (the server uses TMPDIR; Windows NT uses TMP).
+Setting this on the client side will not affect the server. Setting
+this on either side will not affect where CVS stores temporary lock
+files. (See <a href="#config">config</a> in the <a href="#Repository_Administrative_Files">Repository Administrative Files</a> section in this chapter for more information.)
+
+<p><hr>
+Node:<a name="_VISUAL">$VISUAL</a>,
+Previous:<a rel=previous href="#_TEMP__TMP__TMPDIR">$TEMP $TMP $TMPDIR</a>,
+Up:<a rel=up href="#Environment_Variables">Environment Variables</a>
+<br>
+
+<h3>$VISUAL</h3>
+
+<p>(See <a href="#_CVSEDITOR">$CVSEDITOR</a>.)
+
+<p><hr>
+Node:<a name="Third-Party_Tools">Third-Party Tools</a>,
+Next:<a rel=next href="#Index">Index</a>,
+Previous:<a rel=previous href="#CVS_Reference">CVS Reference</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>Third-Party Tools</h1>
+
+<p>Many people have written programs to augment CVS. I call these
+<dfn>third-party tools</dfn> because they have their own maintainers,
+separate from the CVS development team. Most of these programs are not
+distributed with CVS, although some are. This chapter covers
+third-party tools that I have found useful, but that are not distributed
+with CVS.
+
+<p>Although there are some very popular and widely used non-command-line or
+non-Unix interfaces to CVS (download sites are listed in <a href="#Repository_Administration">Repository Administration</a>), this chapter does not discuss most of them. Their
+popularity makes it easy to find out more about them from mailing lists
+and newsgroups. One exception to this is the Emacs pcl-cvs interface,
+which is very useful, but sometimes tricky to install.
+
+<ul>
+<li><a href="#pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs -- An Emacs Interface To CVS</a>:
+<li><a href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>:
+<li><a href="#cvs2cl_--_Generate_GNU-Style_ChangeLogs">cvs2cl -- Generate GNU-Style ChangeLogs</a>:
+<li><a href="#cvslock_--_Lock_Repositories_For_Atomicity">cvslock -- Lock Repositories For Atomicity</a>:
+<li><a href="#cvsq_--_Queue_CVS_Commands_For_Later_Connection">cvsq -- Queue CVS Commands For Later Connection</a>:
+<li><a href="#Other_Packages">Other Packages</a>:
+<li><a href="#Writing_Your_Own_Tools">Writing Your Own Tools</a>:
+</ul>
+
+<p><hr>
+Node:<a name="pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs -- An Emacs Interface To CVS</a>,
+Next:<a rel=next href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>,
+Up:<a rel=up href="#Third-Party_Tools">Third-Party Tools</a>
+<br>
+
+<h2>pcl-cvs - An Emacs Interface To CVS</h2>
+
+<p>Depends on: Emacs, Elib
+
+<p>URLs:
+
+<ul>
+<li><a href="ftp://rum.cs.yale.edu/pub/monnier/pcl-cvs/">ftp://rum.cs.yale.edu/pub/monnier/pcl-cvs/</a>
+<li><a href="ftp://ftp.lysator.liu.se/pub/emacs/pcl-cvs-1.05.tar.gz">ftp://ftp.lysator.liu.se/pub/emacs/pcl-cvs-1.05.tar.gz</a>
+<li><a href="ftp://ftp.red-bean.com/pub/kfogel/pcl-cvs-1.05.tar.gz">ftp://ftp.red-bean.com/pub/kfogel/pcl-cvs-1.05.tar.gz</a>
+</ul>
+
+<p>Authors: Per Cederqvist and Stefan Monnier (current maintainer)
+
+<p><code>pcl-cvs</code> is one of two Emacs/CVS interfaces. The other is the
+native VC (Version Control) interface built into Emacs. I prefer
+pcl-cvs because it was written exclusively for CVS and, therefore, works
+smoothly with the CVS way of doing things. VC, on the other hand, was
+designed to work with several different back-end version control systems
+- RCS and SCCS, as well as CVS - and is not really "tuned" for CVS.
+For example, VC presents a file-based rather than a directory-based
+interface to revision control.
+
+<p>The advantages of pcl-cvs are strong enough that many people choose to
+download and install it rather than use VC. Unfortunately, pcl-cvs has
+two disadvantages: It can be a bit tricky to install (much of this
+section is devoted to overcoming possible installation hurdles), and its
+recent releases are a bit unstable.
+
+<p>The latter problem is likely to be temporary, but it does raise the
+question of which version to use. Stefan Monnier has just recently
+taken over the pcl-cvs maintainership; the latest release, 2.9.6
+(available from the first URL in the preceding list), was a bit bumpy
+when I tried it. No doubt the problems will be smoothed out soon, but
+in the meantime, you might want to use an older version. Because I've
+been using Version 1.05 daily for a long time now and it's performed
+quite well, I'm going to document that version here. Fortunately, the
+installation procedures don't change much from version to version. If
+you decide to use pcl-cvs, I suggest that you check Monnier's download
+site for a version newer than 2.9.6; if there is one, try it out before
+regressing all the way to 1.05.
+
+<p>You'll notice that two URLs are given for Version 1.05. The first is
+Per Cederqvist's site, where he still makes available an old archive of
+pcl-cvs. However, since I'm not sure how much longer his archive will
+stay around, I'm also making the 1.05 distribution available from
+ftp.red-bean.com.
+
+<p>Although the rest of these instructions use examples from a Version 1.05
+distribution, they should apply to later versions as well.
+
+<ul>
+<li><a href="#Installing_pcl-cvs">Installing pcl-cvs</a>:
+<li><a href="#Using_pcl-cvs">Using pcl-cvs</a>:
+<li><a href="#Error_Handling_In_pcl-cvs">Error Handling In pcl-cvs</a>:
+<li><a href="#The_Future_Of_pcl-cvs">The Future Of pcl-cvs</a>:
+</ul>
+
+<p><hr>
+Node:<a name="Installing_pcl-cvs">Installing pcl-cvs</a>,
+Next:<a rel=next href="#Using_pcl-cvs">Using pcl-cvs</a>,
+Up:<a rel=up href="#pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs -- An Emacs Interface To CVS</a>
+<br>
+
+<h3>Installing pcl-cvs</h3>
+
+<p>If you don't normally deal with Emacs installation and site-maintenance
+issues, the pcl-cvs installation procedure may seem a bit daunting. A
+little background on how Emacs works may help.
+
+<p>Most higher-level Emacs features are written in a language called "Emacs
+Lisp" (Emacs itself is essentially an interpreter for this language).
+People add new features to Emacs by distributing files of Emacs Lisp
+code. <code>pcl-cvs</code> is written in this language, and it depends on a
+library of useful, generic Emacs Lisp functions called <dfn>Elib</dfn> (also
+written in part by Per Cederqvist, but distributed separately from
+pcl-cvs).
+
+<p>Elib is not included in the regular Emacs distribution (at least not FSF
+Emacs; I don't know about XEmacs), so you may have to download and
+install it yourself before you can use pcl-cvs. You can get it from
+<a href="ftp://ftp.lysator.liu.se/pub/emacs/elib-1.0.tar.gz">ftp://ftp.lysator.liu.se/pub/emacs/elib-1.0.tar.gz</a>. Installation
+instructions are contained within the package.
+
+<p>Once Elib is installed, you're ready to build and install pcl-cvs.
+These instructions applies both to Version 1.05 and the 2.x series
+(although you should check the NEWS and INSTALL files in newer
+distributions to see what's changed).
+
+<p>First, unpack pcl-cvs (I'm using Version 1.05, but it could just as
+easily have been 2.9.6)
+
+<pre>floss$ zcat pcl-cvs-1.05.tar.gz | tar xvf -
+pcl-cvs-1.05/
+pcl-cvs-1.05/README
+pcl-cvs-1.05/NEWS
+pcl-cvs-1.05/INSTALL
+pcl-cvs-1.05/ChangeLog
+pcl-cvs-1.05/pcl-cvs.el
+pcl-cvs-1.05/pcl-cvs.texinfo
+pcl-cvs-1.05/compile-all.el
+pcl-cvs-1.05/pcl-cvs-lucid.el
+pcl-cvs-1.05/pcl-cvs-startup.el
+pcl-cvs-1.05/pcl-cvs.info
+pcl-cvs-1.05/Makefile
+pcl-cvs-1.05/texinfo.tex
+</pre>
+
+<p>and go into the source tree's top level:
+
+<pre>floss$ cd pcl-cvs-1.05/
+</pre>
+
+<p>A Makefile is supplied there. According to the instructions in the
+INSTALL file, you're supposed to edit a few paths at the top of the
+Makefile and then run:
+
+<pre>floss$ make install
+</pre>
+
+<p>If that works, great. However, this sometimes results in an error (the
+pcl-cvs code itself is very portable, but its installation procedures
+sometimes are not). Do this if you get an error:
+
+<pre>floss$ make clean
+floss$ make
+</pre>
+
+<p>If all goes well, these commands accomplish a significant part of the
+installation by byte-compiling all of the Emacs Lisp files.
+(Byte-compiling converts a file of human-readable Emacs Lisp code - an
+.el file - into a more compact and efficient representation - an .elc
+file. Emacs can load and run an .elc file with better performance than
+it can a plain .el file.)
+
+<p>I'll proceed as though the byte-compilation stage has succeeded. If the
+byte compilation does not appear to succeed, don't worry: The .elc files
+are a luxury, not a necessity. They improve performance slightly, but
+you can run pcl-cvs from the raw .el files with no problem.
+
+<p>If the make install failed, the next step is to get the Emacs Lisp
+(whether .el or .elc) into a directory where Emacs can load it
+automatically. Emacs has a designated directory on the system for
+locally installed Lisp. To find this directory - it will have a file
+named <code>default.el</code> in it - check the following locations, in this
+order:
+
+<ol type=1 start=1>
+</p><li>/usr/share/emacs/site-lisp/
+<li>/usr/local/share/emacs/site-lisp/
+<li>/usr/lib/emacs/site-lisp/
+<li>/usr/local/lib/emacs/site-lisp/
+</ol>
+
+<p>Once you've found your site-lisp directory, copy all of the Lisp files
+to it (you may have to be root to do this):
+
+<pre>floss# cp -f *.el *.elc /usr/share/emacs/site-lisp/
+</pre>
+
+<p>The last step is to tell Emacs about the entry points to pcl-cvs (the
+main one being the function cvs-update), so it will know to load the
+pcl-cvs code on demand. Because Emacs always reads the default.el file
+when it starts up, that's where you need to list the pcl-cvs entry
+points.
+
+<p>Fortunately, pcl-cvs provides the necessary content for default.el.
+Simply put the contents of pcl-cvs-startup.el into default.el (or
+perhaps into your .emacs, if you're just installing this for yourself)
+and restart your Emacs.
+
+<p>You may also want to copy the .info files into your info tree and add
+pcl-cvs to the table of contents in the dir file.
+
+<p><hr>
+Node:<a name="Using_pcl-cvs">Using pcl-cvs</a>,
+Next:<a rel=next href="#Error_Handling_In_pcl-cvs">Error Handling In pcl-cvs</a>,
+Previous:<a rel=previous href="#Installing_pcl-cvs">Installing pcl-cvs</a>,
+Up:<a rel=up href="#pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs -- An Emacs Interface To CVS</a>
+<br>
+
+<h3>Using pcl-cvs</h3>
+
+<p>Once installed, pcl-cvs is very easy to use. You just run the function
+cvs-update, and pcl-cvs brings up a buffer showing what files in your
+working copy have been modified or updated. From there, you can commit,
+do diffs, and so on.
+
+<p>Because cvs-update is the main entry point, I suggest that you bind it
+to a convenient key sequence before going any further. I have it bound
+to <kbd>Ctrl+c v</kbd> in my .emacs:
+
+<pre>(global-set-key "\C-cv" 'cvs-update)
+</pre>
+
+<p>Otherwise, you can run it by typing <kbd>M-x cvs-update</kbd> (also known as
+<kbd>Esc-x cvs-update</kbd>).
+
+<p>When invoked, cvs-update runs cvs update as if in the directory of the
+file in the current buffer - just as if you typed cvs update on the
+command line in that directory. Here's an example of what you might see
+inside Emacs:
+
+<pre>PCL-CVS release 1.05 from CVS release $Name$.
+Copyright (C) 1992, 1993 Per Cederqvist
+Pcl-cvs comes with absolutely no warranty; for details consult the manual.
+This is free software, and you are welcome to redistribute it under certain
+conditions; again, consult the TeXinfo manual for details.
+ Modified ci README.txt
+ Modified ci fish.c
+---------- End ----
+</pre>
+
+<p>Two files have been locally modified (some versions of pcl-cvs show the
+subdirectories where the files are located). The next logical action is
+to commit one or both of the files, which is what the ci on each line
+means. To commit one of them, go to its line and type <kbd>c</kbd>. You are
+brought to a log message buffer, where you can type a log message as
+long as you want (real log message editing is the major advantage of
+pcl-cvs over the command line). Type <kbd>Ctrl+c Ctrl+c</kbd> when done to
+complete the commit.
+
+<p>If you want to commit multiple files at once, sharing a log message,
+first use m to mark the files that you intend to commit. An asterisk
+appears next to each file as you mark it:
+
+<pre>PCL-CVS release 1.05 from CVS release $Name$.
+Copyright (C) 1992, 1993 Per Cederqvist
+Pcl-cvs comes with absolutely no warranty; for details consult the manual.
+This is free software, and you are welcome to redistribute it under certain
+conditions; again, consult the TeXinfo manual for details.
+* Modified ci README.txt
+* Modified ci fish.c
+---------- End ----
+</pre>
+
+<p>Now when you type c anywhere, it applies to all (and only) the marked
+files. Write the log message and commit them with <kbd>Ctrl+c Ctrl+c</kbd>
+as before.
+
+<p>You can also type <kbd>d</kbd> to run cvs diff on a file (or on marked files)
+and <kbd>f</kbd> to bring a file into Emacs for editing. Other commands are
+available; type <kbd>Ctrl+h</kbd> m in the update buffer to see what else you
+can do.
+
+<p><hr>
+Node:<a name="Error_Handling_In_pcl-cvs">Error Handling In pcl-cvs</a>,
+Next:<a rel=next href="#The_Future_Of_pcl-cvs">The Future Of pcl-cvs</a>,
+Previous:<a rel=previous href="#Using_pcl-cvs">Using pcl-cvs</a>,
+Up:<a rel=up href="#pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs -- An Emacs Interface To CVS</a>
+<br>
+
+<h3>Error Handling In pcl-cvs</h3>
+
+<p>The pcl-cvs program has historically had an odd way of dealing with
+error and informational messages from CVS (although this may be
+corrected in the latest versions). When it encounters a message from
+CVS that it doesn't know about, it gets hysterical and throws you into a
+mail buffer, ready to send a pregenerated bug report to the author of
+pcl-cvs. Unfortunately, among the CVS messages that pcl-cvs may not
+know about are the ones associated with conflicting merges, which,
+although not common, certainly do occur from time to time.
+
+<p>If pcl-cvs suddenly dumps you into a mail buffer, don't panic. Read
+over the contents of the buffer carefully - the offending CVS output
+should be in there somewhere. If it looks like a merge, you can just
+get rid of the mail buffer and rerun cvs-update. It should now succeed,
+because CVS won't output any merge messages (because the merge has
+already taken place).
+
+<p>(Update: this problem appears to have been fixed in more recent versions
+of pcl-cvs, so very probably you can ignore this entire warning.)
+
+<p><hr>
+Node:<a name="The_Future_Of_pcl-cvs">The Future Of pcl-cvs</a>,
+Previous:<a rel=previous href="#Error_Handling_In_pcl-cvs">Error Handling In pcl-cvs</a>,
+Up:<a rel=up href="#pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs -- An Emacs Interface To CVS</a>
+<br>
+
+<h3>The Future Of pcl-cvs</h3>
+
+<p>Although I may be giving you the impression that pcl-cvs is barely
+maintained and a risky investment, the instability appears to be
+temporary. Stefan Monnier is a responsive maintainer (I contacted him
+several times during the writing of this chapter, and he always answered
+right away; he is already making headway on some of the bugs in Version
+2.9.6). Very likely by the time this is published, you will be able to
+download Version 2.9.7 or later with confidence.
+
+<p>In fact, I just now got an encouraging email on this topic from Greg
+Woods, a former maintainer of pcl-cvs, reprinted here with his
+permission:
+
+<pre>From: woods@most.weird.com (Greg A. Woods)
+Subject: Re: pcl-cvs maintenance status, stability of recent "release"s?
+To: kfogel@red-bean.com
+Date: Sun, 29 Aug 1999 18:59:19 -0400 (EDT)
+
+[...]
+I've been using Stefan's releases for some time now, and indeed I have
+abandoned my own branch of it.
+
+He's done a lot of really good work on PCL-CVS and except for a few odd
+quirks in the 2.9.6 version I'm using daily now it is quite usable (and
+is approximately infinitely more usable with modern CVS than the one
+that was in the CVS distribution! ;-).
+
+I've added a pcl-cvs.README file to my FTP site to point out that the
+files there are indeed quite old (at least in Internet time! ;-) and to
+give a pointer to Stefan's FTP site too.
+
+[...]
+</pre>
+
+<p>In a later email, Greg said that the FSF is considering including
+pcl-cvs in their next release of Emacs (20.5), which would render most
+of the preceding installation advice obsolete. Sigh. It's hard to keep
+up with free software, sometimes.
+
+<p><hr>
+Node:<a name="cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>,
+Next:<a rel=next href="#cvs2cl_--_Generate_GNU-Style_ChangeLogs">cvs2cl -- Generate GNU-Style ChangeLogs</a>,
+Previous:<a rel=previous href="#pcl-cvs_--_An_Emacs_Interface_To_CVS">pcl-cvs -- An Emacs Interface To CVS</a>,
+Up:<a rel=up href="#Third-Party_Tools">Third-Party Tools</a>
+<br>
+
+<h2>cvsutils - General Utilities For Use With CVS</h2>
+
+<p>Depends on: Perl
+
+<p>URLs:
+
+<ul>
+<li><a href="http://www.red-bean.com/cvsutils">http://www.red-bean.com/cvsutils</a>
+</ul>
+
+<p>Authors: Tom Tromey (original author) and Pavel Roskin (current maintainer)
+
+<p>The suite of small programs called <code>cvsutils</code> generally (although
+not always) performs <dfn>offline</dfn> operations in the CVS working copy.
+Offline operations are those that can be done without contacting the
+repository, while still leaving the working copy in a consistent state
+for the next time the repository is contacted. Offline behavior can be
+extremely handy when your network connection to the repository is slow
+or unreliable.
+
+<p>The cvsutils programs are listed below in approximate order of
+usefulness (according to my opinion), with the more useful ones coming
+first. Coincidentally, this also arranges them by safety. Safety is an
+issue because some of these utilities can, in their normal course of
+operation, cause you to lose local modifications or files from your
+working copy. Therefore, read the descriptions carefully before using
+these utilities.
+
+<p>This documentation is accurate as of Version 0.1.4. Be sure to read the
+README file in any later versions for more up-to-date information.
+
+<ul>
+<li><a href="#cvsu">cvsu</a>:
+<li><a href="#cvsdo">cvsdo</a>:
+<li><a href="#cvschroot">cvschroot</a>:
+<li><a href="#cvsrmadm">cvsrmadm</a>:
+<li><a href="#cvspurge">cvspurge</a>:
+<li><a href="#cvsdiscard">cvsdiscard</a>:
+<li><a href="#cvsco">cvsco</a>:
+<li><a href="#cvsdate">cvsdate</a>:
+</ul>
+
+<p><hr>
+Node:<a name="cvsu">cvsu</a>,
+Next:<a rel=next href="#cvsdo">cvsdo</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvsu</h3>
+
+<p>Danger level: None
+
+<p>Contacts repository: No
+
+<p>This does an offline cvs update by comparing the timestamps of files on
+disk with their timestamps recorded in CVS/Entries. You can thus tell
+which files have been locally modified and which files are not known to
+be under CVS control. Unlike <code>cvs&nbsp;update</code>, cvsu does not bring
+down changes from the repository.
+
+<p>Although it can take various options, cvsu is most commonly invoked
+without any options:
+
+<pre>floss$ cvsu
+? ./bar
+? ./chapter-10.html
+M ./chapter-10.sgml
+D ./out
+? ./safe.sh
+D ./tools
+</pre>
+
+<p>The left-side codes are like the output of cvs update, except that
+<code>D</code> means directory. This example shows that chapter-10.sgml has
+been modified locally. What the example doesn't show is that cvsu ran
+instantly, whereas a normal cvs update would have required half a minute
+or so over my slow modem line. Run
+
+<pre>floss$ cvsu --help
+</pre>
+
+<p>to see a list of options.
+
+<p><hr>
+Node:<a name="cvsdo">cvsdo</a>,
+Next:<a rel=next href="#cvschroot">cvschroot</a>,
+Previous:<a rel=previous href="#cvsu">cvsu</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvsdo</h3>
+
+<p>Danger level: Low to none
+
+<p>Contacts repository: No
+
+<p>This can simulate the working copy effects of cvs add and cvs remove,
+but without contacting the repository. Of course, you'd still have to
+commit the changes to make them take effect in the repository, but at
+least the add and remove commands themselves can be sped up this way.
+Here's how to use it
+
+<pre>floss$ cvsdo add FILENAME
+</pre>
+
+<p>or
+
+<pre>floss$ cvsdo remove FILENAME
+</pre>
+
+<p>To see a list of further options, run:
+
+<pre>floss$ cvsdo --help
+</pre>
+
+<p><hr>
+Node:<a name="cvschroot">cvschroot</a>,
+Next:<a rel=next href="#cvsrmadm">cvsrmadm</a>,
+Previous:<a rel=previous href="#cvsdo">cvsdo</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvschroot</h3>
+
+<p>Danger level: Low
+
+<p>Contacts repository: No
+
+<p>This deals with a repository move by tweaking the working copy to point
+to the new repository. This is useful when a repository is copied en
+masse to a new location. When that happens, none of the revisions are
+affected, but the CVS/Root (and possibly the CVS/Repository) file of
+every working copy must be updated to point to the new location. Using
+cvschroot is a lot faster than checking out a new copy. Another
+advantage is that it doesn't lose your local changes.
+
+<p>Usage:
+
+<pre>floss$ cvschroot NEW_REPOS
+</pre>
+
+<p>For example:
+
+<pre>floss$ cvschroot :pserver:newuser@newhost.wherever.com:/home/cvs/myproj
+</pre>
+
+<p><hr>
+Node:<a name="cvsrmadm">cvsrmadm</a>,
+Next:<a rel=next href="#cvspurge">cvspurge</a>,
+Previous:<a rel=previous href="#cvschroot">cvschroot</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvsrmadm</h3>
+
+<p>Danger level: Low to medium
+
+<p>Contacts repository: No
+
+<p>This removes all of the CVS/ administrative subdirectories in your
+working copy, leaving behind a tree similar to that created by cvs
+export.
+
+<p>Although you won't lose any local changes by using cvsrmadm, your
+working copy will no longer be a working copy.
+
+<p>Use with caution.
+
+<p><hr>
+Node:<a name="cvspurge">cvspurge</a>,
+Next:<a rel=next href="#cvsdiscard">cvsdiscard</a>,
+Previous:<a rel=previous href="#cvsrmadm">cvsrmadm</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvspurge</h3>
+
+<p>Danger level: Medium
+
+<p>Contacts repository: No
+
+<p>This removes all non-CVS-controlled files in your working copy. It does
+not undo any local changes to CVS-controlled files.
+
+<p>Use with caution.
+
+<p><hr>
+Node:<a name="cvsdiscard">cvsdiscard</a>,
+Next:<a rel=next href="#cvsco">cvsco</a>,
+Previous:<a rel=previous href="#cvspurge">cvspurge</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvsdiscard</h3>
+
+<p>Danger level: Medium to high
+
+<p>Contacts repository: Maybe
+
+<p>This is the complement of cvspurge. Instead of removing unknown files
+but keeping your local changes, cvsdiscard undoes any local changes
+(replacing those files with fresh copies from the repository), but keeps
+unknown files.
+
+<p>Use with extreme caution.
+
+<p><hr>
+Node:<a name="cvsco">cvsco</a>,
+Next:<a rel=next href="#cvsdate">cvsdate</a>,
+Previous:<a rel=previous href="#cvsdiscard">cvsdiscard</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvsco</h3>
+
+<p>Danger level: High
+
+<p>Contacts repository: Maybe
+
+<p>This is the union of cvspurge and cvsdiscard. It undoes any local
+changes and removes unknown files from the working copy.
+
+<p>Use with truly paranoid caution.
+
+<p><hr>
+Node:<a name="cvsdate">cvsdate</a>,
+Previous:<a rel=previous href="#cvsco">cvsco</a>,
+Up:<a rel=up href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>
+<br>
+
+<h3>cvsdate</h3>
+
+<p>This script is apparently incomplete and possibly may never be finished.
+(See the README file for details.)
+
+<p><hr>
+Node:<a name="cvs2cl_--_Generate_GNU-Style_ChangeLogs">cvs2cl -- Generate GNU-Style ChangeLogs</a>,
+Next:<a rel=next href="#cvslock_--_Lock_Repositories_For_Atomicity">cvslock -- Lock Repositories For Atomicity</a>,
+Previous:<a rel=previous href="#cvsutils_--_General_Utilities_For_Use_With_CVS">cvsutils -- General Utilities For Use With CVS</a>,
+Up:<a rel=up href="#Third-Party_Tools">Third-Party Tools</a>
+<br>
+
+<h2>cvs2cl - Generate GNU-Style ChangeLogs</h2>
+
+<p>Depends on: Perl
+
+<p>URL: <a href="http://www.red-bean.com/~kfogel/cvs2cl.shtml">http://www.red-bean.com/~kfogel/cvs2cl.shtml</a>
+
+<p>cvs2cl.pl condenses and reformats the output of cvs log to create a
+GNU-style ChangeLog file for your project. ChangeLogs are
+chronologically organized documents showing the change history of a
+project, with a format designed specifically for human-readability (see
+the following examples).
+
+<p>The problem with the <code>cvs&nbsp;log</code> command is that it presents its
+output on a per-file basis, with no acknowledgement that the same log
+message, appearing at roughly the same time in different files, implies
+that those revisions were all part of a single commit. Thus, reading
+over log output to get an overview of project development is a hopeless
+task - you can really only see the history of one file at a time.
+
+<p>In the ChangeLog produced by cvs2cl.pl, identical log messages are
+unified, so that a single commit involving a group of files shows up as
+one entry. For example:
+
+<pre>floss$ cvs2cl.pl -r
+cvs log: Logging .
+cvs log: Logging a-subdir
+cvs log: Logging a-subdir/subsubdir
+cvs log: Logging b-subdir
+floss$ cat ChangeLog
+...
+1999-08-29 05:44 jrandom
+
+ * README (1.6), hello.c (2.1), a-subdir/whatever.c (2.1),
+ a-subdir/subsubdir/fish.c (2.1): Committing from pcl-cvs 2.9, just
+ for kicks.
+
+1999-08-23 22:48 jrandom
+
+ * README (1.5): [no log message]
+
+1999-08-22 19:34 jrandom
+
+ * README (1.4): trivial change
+...
+floss$
+</pre>
+
+<p>The first entry shows that four files were committed at once, with the
+log message, "Committing from pcl-cvs 2.9, just for kicks.". (The -r
+option was used to show the revision number of each file associated with
+that log message.)
+
+<p>Like CVS itself, cvs2cl.pl takes the current directory as an implied
+argument but acts on individual files if given file name arguments.
+Following are a few of the most commonly used options.
+
+<ul>
+
+<li>
+<code>h</code>, <code>--help</code>
+
+<p>Show usage (including a complete list of options).
+
+</p><li>
+<code>-r</code>, <code>--revisions</code>
+
+<p>Show revision numbers in output. If used in conjunction with -b,
+branches are shown as BRANCHNAME.N, where N is the revision on the
+branch.
+
+</p><li>
+<code>-t</code>, <code>--tags</code>
+
+<p>Show tags (symbolic names) for revisions that have them.
+
+</p><li>
+<code>-b</code>, <code>--branches</code>
+
+<p>Show the branch name for revisions on that branch. (See also -r.)
+
+</p><li>
+<code>-g&nbsp;OPTS</code>, <code>--global-opts&nbsp;OPTS</code>
+
+<p>Pass OPTS as global arguments to cvs. Internally, cvs2cl.pl invokes cvs
+to get the raw log data; thus, OPTS are passed right after the cvs in
+that invocation. For example, to achieve quiet behavior and
+compression, you can do this:
+
+<pre>floss$ cvs2cl.pl -g "-Q -z3"
+</pre>
+
+</p><li>
+<code>-l&nbsp;OPTS</code>, <code>--log-opts&nbsp;OPTS</code>
+
+<p>Similar to -g, except that OPTS are passed as command options instead of
+global options. To generate a ChangeLog showing only commits that
+happened between July 26 and August 15, you can do this:
+
+<pre>floss$ cvs2cl.pl -l "'-d1999-07-26&lt;1999-08-15'"
+</pre>
+
+<p>Notice the double-layered quoting - this is necessary in Unix because
+the shell that invokes cvs log (inside cvs2cl.pl) interprets the
+<code>&lt;</code> as a shell redirection symbol. Therefore, the quotes have to
+be passed as part of the argument, making it necessary to surround the
+whole thing with an additional set of quotes.
+
+</p><li>
+<code>-d</code>, <code>--distributed</code>
+
+<p>Put an individual ChangeLog in each subdirectory, covering only commits
+in that subdirectory (as opposed to building one ChangeLog that covers
+the directory where cvs2cl.pl was invoked and all subdirectories
+underneath it).
+
+</ul>
+
+<p><hr>
+Node:<a name="cvsq_--_Queue_CVS_Commands_For_Later_Connection">cvsq -- Queue CVS Commands For Later Connection</a>,
+Next:<a rel=next href="#Other_Packages">Other Packages</a>,
+Previous:<a rel=previous href="#cvslock_--_Lock_Repositories_For_Atomicity">cvslock -- Lock Repositories For Atomicity</a>,
+Up:<a rel=up href="#Third-Party_Tools">Third-Party Tools</a>
+<br>
+
+<h2>cvsq - Queue CVS Commands For Later Connection</h2>
+
+<p>Depends on: Bash
+
+<p>URL: <a href="http://www.volny.cz/v.slavik/lt/cvsq.html">http://www.volny.cz/v.slavik/lt/cvsq.html</a>
+
+<p>Vaclav Slavik &lt;v.slavik@volny.cz&gt;, the author of cvsq, has this to say
+about it:
+
+<p>cvsq stands for "cvs queued" and it is a small bash script that wraps
+around Cyclic's CVS. It makes working with CVS repository a bit easier
+for people connected via dial-up, because it can queue CVS commands and
+pass them to "real cvs" later.
+
+<p>For example, you can commit files immediately after editing them, when being
+offline, so you don't forget about them:
+
+<pre> cvsq commit -m "change 1" file1.c
+ cvsq commit -m "change 2" file2.c
+ cvsq commit -m "change 3" file3.c
+</pre>
+
+<p>And then, when you go online, you simply type
+
+<pre> cvsq upload
+</pre>
+
+<p>and all changes will be commited into the repository. If uploading of a
+particular file fails, it won't be lost - instead, you'll see error
+message and the file will stay in cvsq queue.
+
+<p>You can use cvsq even for commands that make no sense when offline - in
+that case, the command is immediately passed to cvs and not queued. For
+example, you can call cvsq update and it won't be put into the queue but
+executed immediately. In fact, you can start using cvsq as a
+replacement for cvs.
+
+<p>cvsq is in public domain.
+
+<p><hr>
+Node:<a name="cvslock_--_Lock_Repositories_For_Atomicity">cvslock -- Lock Repositories For Atomicity</a>,
+Next:<a rel=next href="#cvsq_--_Queue_CVS_Commands_For_Later_Connection">cvsq -- Queue CVS Commands For Later Connection</a>,
+Previous:<a rel=previous href="#cvs2cl_--_Generate_GNU-Style_ChangeLogs">cvs2cl -- Generate GNU-Style ChangeLogs</a>,
+Up:<a rel=up href="#Third-Party_Tools">Third-Party Tools</a>
+<br>
+
+<h2>cvslock - Lock Repositories For Atomicity</h2>
+
+<p>Depends on: C compiler for installation; nothing for runtime
+
+<p>URL: <a href="ftp://riemann.iam.uni-bonn.de/pub/users/roessler/cvslock/">ftp://riemann.iam.uni-bonn.de/pub/users/roessler/cvslock/</a>
+
+<p>This program locks a CVS repository (either for reading or writing) in
+the same way that CVS does, so that CVS will honor the locks. This can
+be useful when, for example, you need to make a copy of the whole
+repository and want to avoid catching parts of commits or other people's
+lockfiles.
+
+<p>The cvslock distribution is packaged extremely well and can be installed
+according to the usual GNU procedures. Here's a transcript of an
+install session:
+
+<pre>floss$ zcat cvslock-0.1.tar.gz | tar xvf -
+cvslock-0.1/
+cvslock-0.1/Makefile.in
+cvslock-0.1/README
+cvslock-0.1/COPYING
+cvslock-0.1/Makefile.am
+cvslock-0.1/acconfig.h
+cvslock-0.1/aclocal.m4
+cvslock-0.1/config.h.in
+cvslock-0.1/configure
+cvslock-0.1/configure.in
+cvslock-0.1/install-sh
+cvslock-0.1/missing
+cvslock-0.1/mkinstalldirs
+cvslock-0.1/stamp-h.in
+cvslock-0.1/cvslock.c
+cvslock-0.1/cvslock.1
+cvslock-0.1/snprintf.c
+cvslock-0.1/cvslssh
+cvslock-0.1/VERSION
+floss$ cd cvslock-0.1
+floss$ ./configure
+ ...
+floss$ make
+gcc -DHAVE_CONFIG_H -I. -I. -I. -g -O2 -c cvslock.c
+gcc -g -O2 -o cvslock cvslock.o
+floss$ make install
+ ...
+floss$
+</pre>
+
+<p>(Note that you may have to do the make install step as root).
+
+<p>Now, cvslock is installed as /usr/local/bin/cvslock. When you invoke
+it, you can specify the repository with -d or via the $CVSROOT
+environment variable, just as with CVS itself (the following examples
+use -d). Its only required argument is the name of the directory to
+lock, relative to the top of the repository. That directory and all of
+its subdirectories will be locked. In this example, there are no
+subdirectories, so only one lockfile is created:
+
+<pre>floss$ ls /usr/local/newrepos/myproj/b-subdir/
+random.c,v
+floss$ cvslock -d /usr/local/newrepos myproj/b-subdir
+floss$ ls /usr/local/newrepos/myproj/b-subdir/
+#cvs.rfl.cvslock.floss.27378 random.c,v
+floss$ cvslock -u -p 27378 -d /usr/local/newrepos myproj/b-subdir
+floss$ ls /usr/local/newrepos/myproj/b-subdir/
+random.c,v
+floss$
+</pre>
+
+<p>Notice that when I cleared the lock (-u for <code>unlock</code>), I had to
+specify <code>-p&nbsp;27378</code>. That's because cvslock uses Unix process
+IDs when creating lockfile names to ensure that its locks are unique.
+When you unlock, you have to tell cvslock which lock instance to remove,
+even if there's only one instance present. Thus, the -p flag tells
+cvslock which previous instance of itself it's cleaning up after (you
+can use -p with or without -u, though).
+
+<p>If you're going to be working in the repository for a while, doing
+various operations directly in the file system, you can use the -s
+option to have cvslock start up a new shell for you. It then consults
+the <code>$SHELL</code> environment variable in your current shell to
+determine which shell to use:
+
+<pre>floss$ cvslock -s -d /usr/local/newrepos myproj
+</pre>
+
+<p>The locks remain present until you exit the shell, at which time they
+are automatically removed. You can also use the -c option to execute a
+command while the repository is locked. Just as with -s, the locks are
+put in place before the command starts and removed when it's finished.
+In the following example, we lock the repository just long enough to
+display a listing of all of the lockfiles:
+
+<pre>floss$ cvslock -c 'find . -name "*cvslock*" ' -d /usr/local/newrepos myproj
+cvslock: '/usr/local/newrepos/myproj' locked successfully.
+cvslock: Starting 'find . -name "*cvslock*" -print'...
+./a-subdir/subsubdir/#cvs.rfl.cvslock.floss.27452
+./a-subdir/#cvs.rfl.cvslock.floss.27452
+./b-subdir/#cvs.rfl.cvslock.floss.27452
+./#cvs.rfl.cvslock.floss.27452
+floss$ find /usr/local/newrepos/myproj -name "*cvslock*" -print
+floss$
+</pre>
+
+<p>The command (the argument to the -c option) is run with the specified
+repository directory as its working directory.
+
+<p>By default, cvslock creates read-locks. You can tell it to use
+write-locks instead by passing the -W option. (You can pass -R to
+specify read-locks, but that's the default anyway.) Always remove any
+locks when you're finished, so that other users' CVS processes don't
+wait needlessly.
+
+<p>Note that cvslock must be run on the machine where the repository
+resides - you cannot specify a remote repository. (For more
+information, run <code>man&nbsp;cvslock</code>, which is a manual page
+installed when you ran <code>make&nbsp;install</code>.)
+
+<p><hr>
+Node:<a name="Other_Packages">Other Packages</a>,
+Next:<a rel=next href="#Writing_Your_Own_Tools">Writing Your Own Tools</a>,
+Previous:<a rel=previous href="#cvsq_--_Queue_CVS_Commands_For_Later_Connection">cvsq -- Queue CVS Commands For Later Connection</a>,
+Up:<a rel=up href="#Third-Party_Tools">Third-Party Tools</a>
+<br>
+
+<h2>Other Packages</h2>
+
+<p>Many other third-party packages are available for CVS. Following are
+pointers to some of these.
+
+<h2>CVSUp (Part Of The FreeBSD Project)</h2>
+
+<p>CVSUp is an efficient generic mirroring tool with special built-in
+support for mirroring CVS repositories. The FreeBSD operating system
+uses it to distribute changes from their master repository, so users can
+keep up to date conveniently.
+
+<p>For more information on CVSUp in general, check out
+<a href="http://www.polstra.com/projects/freeware/CVSup/">http://www.polstra.com/projects/freeware/CVSup/</a>.
+
+<p>For its use in FreeBSD in particular, see
+<a href="http://www.freebsd.org/handbook/synching.html#CVSUP">http://www.freebsd.org/handbook/synching.html#CVSUP</a>.
+
+<h2>CVSWeb: A Web Interface To CVS Repositories</h2>
+
+<p>CVSWeb provides a Web interface to browsing CVS repositories. A more
+accurate name might be "RCSWeb", because what it actually does is allow
+you to browse revisions directly in a repository, viewing log messages
+and diffs. Although I've never found it to be a particularly compelling
+interface myself, I have to admit that it is intuitive enough and a lot
+of sites use it.
+
+<p>Although the software was originally written by Bill Fenner, the version
+most actively under development right now seems to be Henner Zeller's,
+at <a href="http://linux.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi/">http://linux.fh-heilbronn.de/~zeller/cgi/cvsweb.cgi/</a>.
+
+<p>You may also want to visit Fenner's original site at
+<a href="http://www.freebsd.org/~fenner/cvsweb/">http://www.freebsd.org/~fenner/cvsweb/</a> and possibly Cyclic
+Software's summary of the CVSWeb scene at
+<a href="http://www.cyclic.com/cyclic-pages/web-cvsweb.html">http://www.cyclic.com/cyclic-pages/web-cvsweb.html</a>.
+
+<p>Finally, if you'd like to see CVSWeb in action, a good example can be
+browsed at <a href="http://sourceware.cygnus.com/cgi-bin/cvsweb.cgi/">http://sourceware.cygnus.com/cgi-bin/cvsweb.cgi/</a>.
+
+<h2>The CVS contrib/ Directory</h2>
+
+<p>As mentioned in <a href="#Repository_Administration">Repository Administration</a>, a number of third-party
+tools are shipped with CVS and are collected in the contrib/ directory.
+Although I'm not aware of any formal rule for determining which tools
+are distributed with CVS, an effort may be in process to gather most of
+the widely used third-party tools and put them in contrib/ so people
+know where to find them. Until that happens, the best way to find such
+tools is to look in contrib/, look at various CVS Web sites, and ask on
+the mailing list.
+
+<p><hr>
+Node:<a name="Writing_Your_Own_Tools">Writing Your Own Tools</a>,
+Previous:<a rel=previous href="#Other_Packages">Other Packages</a>,
+Up:<a rel=up href="#Third-Party_Tools">Third-Party Tools</a>
+<br>
+
+<h2>Writing Your Own Tools</h2>
+
+<p>CVS can at times seem like a bewildering collection of improvised
+standards. There's RCS format, various output formats (history,
+annotate, log, update, and so on), several repository administrative
+file formats, working copy administrative file formats, the
+client/server protocol, the lockfile protocol.... (Are you numb yet? I
+could keep going, you know.)
+
+<p>Fortunately, these standards remain fairly consistent from release to
+release - so if you're trying to write a tool to work with CVS, you at
+least don't have to worry about hitting a moving target. For every
+internal standard, there are usually a few people on the
+<a href="mailto:info-cvs@gnu.org">info-cvs@gnu.org</a> mailing list who know it extremely well
+(several of them helped me out during the writing of this book). There
+is also the documentation that comes with the CVS distribution
+(especially doc/cvs.texinfo, doc/cvsclient.texi, and doc/RCSFILES).
+Finally, there is the CVS source code itself, the last word on any
+question of implementation or behavior.
+
+<p>With all of this at your disposal, there's no reason to hesitate. If
+you can think of some utility that would make your life with CVS easier,
+go ahead and write it - chances are other people have been wanting it,
+too. Unlike a change to CVS itself, a small, standalone external
+utility can get wide distribution very quickly, resulting in quicker
+feedback for its author and faster bug fixes for all of the users.
+
+<p><hr>
+Node:<a name="Index">Index</a>,
+Next:<a rel=next href="#GNU_General_Public_License">GNU General Public License</a>,
+Previous:<a rel=previous href="#Third-Party_Tools">Third-Party Tools</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>Index</h1>
+
+<p>Sorry, the index is still in progress.
+
+<p>Since the online format is searchable anyway, I decided the
+incompleteness of the index need not delay the release of the chapters.
+I hope to have the index finished reasonably soon. Volunteer indexers
+are certainly welcome, too - please email
+<a href="mailto:bug-cvsbook@red-bean.com">bug-cvsbook@red-bean.com</a> if you're interested.
+
+<p><hr>
+Node:<a name="GNU_General_Public_License">GNU General Public License</a>,
+Next:<a rel=next href="#GNU_Free_Documentation_License">GNU Free Documentation License</a>,
+Previous:<a rel=previous href="#Index">Index</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>GNU General Public License</h1>
+
+<pre>GNU General Public License
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure
+the software is free for all its users. This General Public License applies
+to most of the Free Software Foundation's software and to any other program
+whose authors commit to using it. (Some other Free Software Foundation
+software is covered by the GNU Library General Public License instead.) You
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom
+to distribute copies of free software (and charge for this service if you
+wish), that you receive source code or can get it if you want it, that you
+can change the software or use pieces of it in new free programs; and that
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or
+for a fee, you must give the recipients all the rights that you have. You
+must make sure that they, too, receive or can get the source code. And you
+must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software. If
+the software is modified by someone else and passed on, we want its
+recipients to know that what they have is not the original, so that any
+problems introduced by others will not reflect on the original authors'
+reputations.
+
+Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program
+proprietary. To prevent this, we have made it clear that any patent must be
+licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms
+of this General Public License. The "Program", below, refers to any such
+program or work, and a "work based on the Program" means either the Program
+or any derivative work under copyright law: that is to say, a work
+containing the Program or a portion of it, either verbatim or with
+modifications and/or translated into another language. (Hereinafter,
+translation is included without limitation in the term "modification".) Each
+licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running the Program
+is not restricted, and the output from the Program is covered only if its
+contents constitute a work based on the Program (independent of having been
+made by running the Program). Whether that is true depends on what the
+Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source code
+as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this
+License and to the absence of any warranty; and give any other recipients of
+the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it,
+thus forming a work based on the Program, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ * a) You must cause the modified files to carry prominent notices stating
+ that you changed the files and the date of any change.
+
+ * b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any part
+ thereof, to be licensed as a whole at no charge to all third parties
+ under the terms of this License.
+
+ * c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the most ordinary way, to print or display an announcement including
+ an appropriate copyright notice and a notice that there is no warranty
+ (or else, saying that you provide a warranty) and that users may
+ redistribute the program under these conditions, and telling the user
+ how to view a copy of this License. (Exception: if the Program itself
+ is interactive but does not normally print such an announcement, your
+ work based on the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be
+reasonably considered independent and separate works in themselves, then
+this License, and its terms, do not apply to those sections when you
+distribute them as separate works. But when you distribute the same sections
+as part of a whole which is a work based on the Program, the distribution of
+the whole must be on the terms of this License, whose permissions for other
+licensees extend to the entire whole, and thus to each and every part
+regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your
+rights to work written entirely by you; rather, the intent is to exercise
+the right to control the distribution of derivative or collective works
+based on the Program.
+
+In addition, mere aggregation of another work not based on the Program with
+the Program (or with a work based on the Program) on a volume of a storage
+or distribution medium does not bring the other work under the scope of this
+License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1
+and 2 above provided that you also do one of the following:
+
+ * a) Accompany it with the complete corresponding machine-readable source
+ code, which must be distributed under the terms of Sections 1 and 2
+ above on a medium customarily used for software interchange; or,
+
+ * b) Accompany it with a written offer, valid for at least three years,
+ to give any third party, for a charge no more than your cost of
+ physically performing source distribution, a complete machine-readable
+ copy of the corresponding source code, to be distributed under the
+ terms of Sections 1 and 2 above on a medium customarily used for
+ software interchange; or,
+
+ * c) Accompany it with the information you received as to the offer to
+ distribute corresponding source code. (This alternative is allowed only
+ for noncommercial distribution and only if you received the program in
+ object code or executable form with such an offer, in accord with
+ Subsection b above.)
+
+The source code for a work means the preferred form of the work for making
+modifications to it. For an executable work, complete source code means all
+the source code for all modules it contains, plus any associated interface
+definition files, plus the scripts used to control compilation and
+installation of the executable. However, as a special exception, the source
+code distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel,
+and so on) of the operating system on which the executable runs, unless that
+component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to
+copy from a designated place, then offering equivalent access to copy the
+source code from the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the source along with
+the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy,
+modify, sublicense or distribute the Program is void, and will automatically
+terminate your rights under this License. However, parties who have received
+copies, or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed
+it. However, nothing else grants you permission to modify or distribute the
+Program or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Program (or any work based on the Program), you indicate your acceptance of
+this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these terms
+and conditions. You may not impose any further restrictions on the
+recipients' exercise of the rights granted herein. You are not responsible
+for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute so
+as to satisfy simultaneously your obligations under this License and any
+other pertinent obligations, then as a consequence you may not distribute
+the Program at all. For example, if a patent license would not permit
+royalty-free redistribution of the Program by all those who receive copies
+directly or indirectly through you, then the only way you could satisfy both
+it and this License would be to refrain entirely from distribution of the
+Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents
+or other property right claims or to contest validity of any such claims;
+this section has the sole purpose of protecting the integrity of the free
+software distribution system, which is implemented by public license
+practices. Many people have made generous contributions to the wide range of
+software distributed through that system in reliance on consistent
+application of that system; it is up to the author/donor to decide if he or
+she is willing to distribute software through any other system and a
+licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original
+copyright holder who places the Program under this License may add an
+explicit geographical distribution limitation excluding those countries, so
+that distribution is permitted only in or among countries not thus excluded.
+In such case, this License incorporates the limitation as if written in the
+body of this License.
+
+9. The Free Software Foundation may publish revised and/or new versions of
+the General Public License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
+THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO
+THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM
+PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO
+LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR
+THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest possible
+use to the public, the best way to achieve this is to make it free software
+which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey the
+exclusion of warranty; and each file should have at least the "copyright"
+line and a pointer to where the full notice is found.
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy name of author
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this when
+it starts in an interactive mode:
+
+Gnomovision version 69, Copyright (C) yyyy name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'. This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c'
+for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may be
+called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+Yoyodyne, Inc., hereby disclaims all copyright
+interest in the program `Gnomovision'
+(which makes passes at compilers) written
+by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General Public
+License instead of this License.
+
+</pre>
+
+<p><hr>
+Node:<a name="GNU_Free_Documentation_License">GNU Free Documentation License</a>,
+Previous:<a rel=previous href="#GNU_General_Public_License">GNU General Public License</a>,
+Up:<a rel=up href="#Top">Top</a>
+<br>
+
+<h1>GNU Free Documentation License</h1>
+
+<pre>GNU Free Documentation License
+
+Version 1.1, March 2000
+
+Copyright (C) 2000 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other written
+document "free" in the sense of freedom: to assure everyone the effective
+freedom to copy and redistribute it, with or without modifying it, either
+commercially or noncommercially. Secondarily, this License preserves for the
+author and publisher a way to get credit for their work, while not being
+considered responsible for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative works of
+the document must themselves be free in the same sense. It complements the
+GNU General Public License, which is a copyleft license designed for free
+software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free program
+should come with manuals providing the same freedoms that the software does.
+But this License is not limited to software manuals; it can be used for any
+textual work, regardless of subject matter or whether it is published as a
+printed book. We recommend this License principally for works whose purpose
+is instruction or reference.
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work that contains a notice
+placed by the copyright holder saying it can be distributed under the terms
+of this License. The "Document", below, refers to any such manual or work.
+Any member of the public is a licensee, and is addressed as "you".
+
+A "Modified Version" of the Document means any work containing the Document
+or a portion of it, either copied verbatim, or with modifications and/or
+translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of the
+Document that deals exclusively with the relationship of the publishers or
+authors of the Document to the Document's overall subject (or to related
+matters) and contains nothing that could fall directly within that overall
+subject. (For example, if the Document is in part a textbook of mathematics,
+a Secondary Section may not explain any mathematics.) The relationship could
+be a matter of historical connection with the subject or with related
+matters, or of legal, commercial, philosophical, ethical or political
+position regarding them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles are
+designated, as being those of Invariant Sections, in the notice that says
+that the Document is released under this License.
+
+The "Cover Texts" are certain short passages of text that are listed, as
+Front-Cover Texts or Back-Cover Texts, in the notice that says that the
+Document is released under this License.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the general
+public, whose contents can be viewed and edited directly and
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or for
+automatic translation to a variety of formats suitable for input to text
+formatters. A copy made in an otherwise Transparent file format whose markup
+has been designed to thwart or discourage subsequent modification by readers
+is not Transparent. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain ASCII
+without markup, Texinfo input format, LaTeX input format, SGML or XML using
+a publicly available DTD, and standard-conforming simple HTML designed for
+human modification. Opaque formats include PostScript, PDF, proprietary
+formats that can be read and edited only by proprietary word processors,
+SGML or XML for which the DTD and/or processing tools are not generally
+available, and the machine-generated HTML produced by some word processors
+for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself, plus such
+following pages as are needed to hold, legibly, the material this License
+requires to appear in the title page. For works in formats which do not have
+any title page as such, "Title Page" means the text near the most prominent
+appearance of the work's title, preceding the beginning of the body of the
+text.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either commercially
+or noncommercially, provided that this License, the copyright notices, and
+the license notice saying this License applies to the Document are
+reproduced in all copies, and that you add no other conditions whatsoever to
+those of this License. You may not use technical measures to obstruct or
+control the reading or further copying of the copies you make or distribute.
+However, you may accept compensation in exchange for copies. If you
+distribute a large enough number of copies you must also follow the
+conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and you
+may publicly display copies.
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies of the Document numbering more than 100, and
+the Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover Texts:
+Front-Cover Texts on the front cover, and Back-Cover Texts on the back
+cover. Both covers must also clearly and legibly identify you as the
+publisher of these copies. The front cover must present the full title with
+all words of the title equally prominent and visible. You may add other
+material on the covers in addition. Copying with changes limited to the
+covers, as long as they preserve the title of the Document and satisfy these
+conditions, can be treated as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit legibly,
+you should put the first ones listed (as many as fit reasonably) on the
+actual cover, and continue the rest onto adjacent pages.
+
+If you publish or distribute Opaque copies of the Document numbering more
+than 100, you must either include a machine-readable Transparent copy along
+with each Opaque copy, or state in or with each Opaque copy a
+publicly-accessible computer-network location containing a complete
+Transparent copy of the Document, free of added material, which the general
+network-using public has access to download anonymously at no charge using
+public-standard network protocols. If you use the latter option, you must
+take reasonably prudent steps, when you begin distribution of Opaque copies
+in quantity, to ensure that this Transparent copy will remain thus
+accessible at the stated location until at least one year after the last
+time you distribute an Opaque copy (directly or through your agents or
+retailers) of that edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give them
+a chance to provide you with an updated version of the Document.
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under the
+conditions of sections 2 and 3 above, provided that you release the Modified
+Version under precisely this License, with the Modified Version filling the
+role of the Document, thus licensing distribution and modification of the
+Modified Version to whoever possesses a copy of it. In addition, you must do
+these things in the Modified Version:
+
+ * A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions (which
+ should, if there were any, be listed in the History section of the
+ Document). You may use the same title as a previous version if the
+ original publisher of that version gives permission.
+ * B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has less than five).
+ * C. State on the Title page the name of the publisher of the Modified
+ Version, as the publisher.
+ * D. Preserve all the copyright notices of the Document.
+ * E. Add an appropriate copyright notice for your modifications adjacent
+ to the other copyright notices.
+ * F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+ * G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+ * H. Include an unaltered copy of this License.
+ * I. Preserve the section entitled "History", and its title, and add to
+ it an item stating at least the title, year, new authors, and publisher
+ of the Modified Version as given on the Title Page. If there is no
+ section entitled "History" in the Document, create one stating the
+ title, year, authors, and publisher of the Document as given on its
+ Title Page, then add an item describing the Modified Version as stated
+ in the previous sentence.
+ * J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise the
+ network locations given in the Document for previous versions it was
+ based on. These may be placed in the "History" section. You may omit a
+ network location for a work that was published at least four years
+ before the Document itself, or if the original publisher of the version
+ it refers to gives permission.
+ * K. In any section entitled "Acknowledgements" or "Dedications",
+ preserve the section's title, and preserve in the section all the
+ substance and tone of each of the contributor acknowledgements and/or
+ dedications given therein.
+ * L. Preserve all the Invariant Sections of the Document, unaltered in
+ their text and in their titles. Section numbers or the equivalent are
+ not considered part of the section titles.
+ * M. Delete any section entitled "Endorsements". Such a section may not
+ be included in the Modified Version.
+ * N. Do not retitle any existing section as "Endorsements" or to conflict
+ in title with any Invariant Section.
+
+If the Modified Version includes new front-matter sections or appendices
+that qualify as Secondary Sections and contain no material copied from the
+Document, you may at your option designate some or all of these sections as
+invariant. To do this, add their titles to the list of Invariant Sections in
+the Modified Version's license notice. These titles must be distinct from
+any other section titles.
+
+You may add a section entitled "Endorsements", provided it contains nothing
+but endorsements of your Modified Version by various parties--for example,
+statements of peer review or that the text has been approved by an
+organization as the authoritative definition of a standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list of
+Cover Texts in the Modified Version. Only one passage of Front-Cover Text
+and one of Back-Cover Text may be added by (or through arrangements made by)
+any one entity. If the Document already includes a cover text for the same
+cover, previously added by you or by arrangement made by the same entity you
+are acting on behalf of, you may not add another; but you may replace the
+old one, on explicit permission from the previous publisher that added the
+old one.
+
+The author(s) and publisher(s) of the Document do not by this License give
+permission to use their names for publicity for or to assert or imply
+endorsement of any Modified Version.
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified versions,
+provided that you include in the combination all of the Invariant Sections
+of all of the original documents, unmodified, and list them all as Invariant
+Sections of your combined work in its license notice.
+
+The combined work need only contain one copy of this License, and multiple
+identical Invariant Sections may be replaced with a single copy. If there
+are multiple Invariant Sections with the same name but different contents,
+make the title of each such section unique by adding at the end of it, in
+parentheses, the name of the original author or publisher of that section if
+known, or else a unique number. Make the same adjustment to the section
+titles in the list of Invariant Sections in the license notice of the
+combined work.
+
+In the combination, you must combine any sections entitled "History" in the
+various original documents, forming one section entitled "History"; likewise
+combine any sections entitled "Acknowledgements", and any sections entitled
+"Dedications". You must delete all sections entitled "Endorsements."
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in the
+collection, provided that you follow the rules of this License for verbatim
+copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute it
+individually under this License, provided you insert a copy of this License
+into the extracted document, and follow this License in all other respects
+regarding verbatim copying of that document.
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate and
+independent documents or works, in or on a volume of a storage or
+distribution medium, does not as a whole count as a Modified Version of the
+Document, provided no compilation copyright is claimed for the compilation.
+Such a compilation is called an "aggregate", and this License does not apply
+to the other self-contained works thus compiled with the Document, on
+account of their being thus compiled, if they are not themselves derivative
+works of the Document. If the Cover Text requirement of section 3 is
+applicable to these copies of the Document, then if the Document is less
+than one quarter of the entire aggregate, the Document's Cover Texts may be
+placed on covers that surround only the Document within the aggregate.
+Otherwise they must appear on covers around the whole aggregate.
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may distribute
+translations of the Document under the terms of section 4. Replacing
+Invariant Sections with translations requires special permission from their
+copyright holders, but you may include translations of some or all Invariant
+Sections in addition to the original versions of these Invariant Sections.
+You may include a translation of this License provided that you also include
+the original English version of this License. In case of a disagreement
+between the translation and the original English version of this License,
+the original English version will prevail.
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except as
+expressly provided for under this License. Any other attempt to copy,
+modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However, parties who
+have received copies, or rights, from you under this License will not have
+their licenses terminated so long as such parties remain in full compliance.
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the GNU
+Free Documentation License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to
+address new problems or concerns. See http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number. If the
+Document specifies that a particular numbered version of this License "or
+any later version" applies to it, you have the option of following the terms
+and conditions either of that specified version or of any later version that
+has been published (not as a draft) by the Free Software Foundation. If the
+Document does not specify a version number of this License, you may choose
+any version ever published (not as a draft) by the Free Software Foundation.
+
+How to use this License for your documents
+
+To use this License in a document you have written, include a copy of the
+License in the document and put the following copyright and license notices
+just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.1
+ or any later version published by the Free Software Foundation;
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have no Invariant Sections, write "with no Invariant Sections"
+instead of saying which ones are invariant. If you have no Front-Cover
+Texts, write "no Front-Cover Texts" instead of "Front-Cover Texts being
+LIST"; likewise for Back-Cover Texts.
+
+If your document contains nontrivial examples of program code, we recommend
+releasing these examples in parallel under your choice of free software
+license, such as the GNU General Public License, to permit their use in free
+software.
+
+</pre>
+
+</body></html>
+
diff --git a/development/tmake_ref.html b/development/tmake_ref.html
new file mode 100644
index 0000000..4bf82b3
--- a/dev/null
+++ b/development/tmake_ref.html
@@ -0,0 +1,478 @@
+<!doctype HTML public "-//W3C//DTD HTML 3.2//EN">
+<html><head><title>
+Reference Manual - tmake
+</title></head><body bgcolor="#ffffff">
+<p><h1 align=center>Reference Manual - tmake</h1>
+
+<hr>
+<h2>Project Variable Reference</h2>
+
+<h4><a name="ALL_DEPS"></a>ALL_DEPS</h4>
+Specifies additional dependencies for the makefile target "all:".<p>
+
+
+<h4><a name="CLEAN_FILES"></a>CLEAN_FILES</h4>
+Specifies additional files to be removed for "make clean".<p>
+Example:<pre>
+ CLEAN_FILES = core *~
+</pre>
+
+
+<h4><a name="CONFIG"></a>CONFIG</h4>
+Sets the make configuration. It tells the tmake templates what compiler
+options to use and which extra libraries to link in.<p>
+These options control the compilation flags:
+<p>
+<table border="0">
+ <tr>
+ <td>&nbsp;</td>
+ <td>release</td>
+ <td>&nbsp;</td>
+ <td>Compile with optimization enabled, ignored if
+ "debug" is specified.</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>debug</td>
+ <td>&nbsp;</td>
+ <td>Compile with debug options enabled.</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>warn_on</td>
+ <td>&nbsp;</td>
+ <td>The compiler should emit more warnings than normally, ignored if
+ "warn_off" is specified.</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>warn_off</td>
+ <td>&nbsp;</td>
+ <td>The compiler should emit no warnings or as few as possible.</td>
+ </tr>
+</table>
+
+<p>
+These options defines the application/library type:
+<p>
+<table border="0">
+ <tr>
+ <td>&nbsp;</td>
+ <td>qt</td>
+ <td>&nbsp;</td>
+ <td>The target is a Qt application/library and requires Qt header
+ files/library.</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>opengl</td>
+ <td>&nbsp;</td>
+ <td>The target requires the OpenGL (or Mesa) headers/libraries.</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>x11</td>
+ <td>&nbsp;</td>
+ <td>The target is a X11 application (app.t only).</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>windows</td>
+ <td>&nbsp;</td>
+ <td>The target is a Win32 window application (app.t only).</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>console</td>
+ <td>&nbsp;</td>
+ <td>The target is a Win32 console application (app.t only).</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>dll</td>
+ <td>&nbsp;</td>
+ <td>The target is a shared object/DLL (app.t only).</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>staticlib</td>
+ <td>&nbsp;</td>
+ <td>The target is a static library (lib.t only).</td>
+ </tr>
+ <tr>
+ <td>&nbsp;</td>
+ <td>thread</td>
+ <td>&nbsp;</td>
+ <td>The target is a multi-threaded application/library.</td>
+ </tr>
+</table>
+
+
+<h4><a name="DEFINES"></a>DEFINES</h4>
+Specifies C/C++ macros (-D compiler option). On Windows you need
+to let DEFINES contain "QT_DLL" if you are building a Qt program
+which should link with the Qt DLL.
+
+
+<h4><a name="DEF_FILE"></a>DEF_FILE</h4>
+Win32/app.t only: Specifies a .def file.
+
+
+<h4><a name="DESTDIR"></a>DESTDIR</h4>
+Specifies where to put the target file.
+Example:<pre>
+ DESTDIR = ../../lib
+</pre>
+You must create this directory before running make.
+
+
+<h4><a name="DISTFILES"></a>DISTFILES</h4>
+Adds other files to the distribution archive ("dist target").
+The source files and project file are always included in the
+distribution archive.
+Example:<pre>
+ DISTFILES = CHANGES README
+</pre>
+
+
+<h4><a name="HEADERS"></a>HEADERS</h4>
+Defines the header files of the project.
+
+
+<h4><a name="INCPATH"></a>INCPATH</h4>
+This variable is generated from <code>INCLUDEPATH</code>. The ';' or ':'
+separators have been replaced by ' ' (single space). This makes it
+easier to split. qtapp.t and other templates expand
+<code>INCPATH</code> to set -I options for the C++ compiler.
+
+
+<h4><a name="INCLUDEPATH"></a>INCLUDEPATH</h4>
+This variable specifies the #include directories. It can be set in the
+project file, or by the <a href="#AddIncludePath">AddIncludePath()</a>
+function.<p>
+Example:<pre>
+ INCLUDEPATH = c:\msdev\include d:\stl\include
+</pre>
+Use ';' or space as the directory separator.
+
+
+<h4><a name="LIBS"></a>LIBS</h4>
+Defines additional libraries to be linked in when creating an application
+or a shared library. You probably want to use a platform qualifier since
+libraries are specified differently on Unix and Win32.<p>
+Example:<pre>
+ unix:LIBS = -lXext -lm
+ win32:LIBS = ole32.lib
+</pre>
+
+
+<h4><a name="MOC_DIR"></a>MOC_DIR</h4>
+Specifies where to put the temporary moc output files. By default they
+are stored in the directory where the moc input files are.
+<p>
+Example:<pre>
+ MOC_DIR = tmp
+</pre>
+You must create this directory before running make.
+<p>
+See also: <a href="#OBJECTS_DIR">OBJECTS_DIR</a>.
+
+
+<h4><a name="OBJECTS"></a>OBJECTS</h4>
+This varialble is generated from <code>SOURCES</code> by the StdInit() function.
+The extension of each source file has been replaced by .o (Unix) or .obj
+(Win32).<p>
+Example:<pre>
+ SOURCES = a.x b.y
+</pre>
+Then <code>OBJECTS</code> become "a.o b.o" on Unix and "a.obj b.obj" on
+Win32.
+
+
+<h4><a name="OBJECTS_DIR"></a>OBJECTS_DIR</h4>
+Specifies where to put object files. By default they are stored in
+the directory where the source files are.<p>
+Example:<pre>
+ OBJECTS_DIR = tmp
+</pre>
+You must create this directory before running make.
+<p>
+See also: <a href="#MOC_DIR">MOC_DIR</a>.
+
+
+<h4><a name="OBJMOC"></a>OBJMOC</h4>
+This variable is generated by the <a href="#StdInit">StdInit()</a> function if
+<code>$moc_aware</code> is true. <code>OBJMOC</code> contains the name of
+all intermediate moc object files.<p>
+Example:<pre>
+ HEADERS = demo.h
+ SOURCES = demo.cpp main.cpp
+</pre>
+If <tt>demo.h</tt> and <tt>main.cpp</tt> define classes that use signals
+and slots (i.e. the <code>Q_OBJECT</code> "keyword" is found in these two
+files), <code>OBJMOC</code> becomes:<pre>
+ OBJMOC = moc_demo.obj
+</pre>
+See also: <a href="#SRCMOC">SRCMOC</a>.
+
+
+<h4><a name="PROJECT"></a>PROJECT</h4>
+This is the name of the project. It defaults to the name of the project
+file, excluding the .pro extension.
+
+
+<h4><a name="RC_FILE"></a>RC_FILE</h4>
+Win32/app.t only: Specifies a .rc file. Cannot be used with the RES_FILE
+variable.
+
+
+<h4><a name="RES_FILE"></a>RES_FILE</h4>
+Win32/app.t only: Specifies a .res file. You can either specify a
+.rc file or one or more .res files.
+
+
+<h4><a name="SOURCES"></a>SOURCES</h4>
+Defines the source files of the project.
+
+
+<h4><a name="SRCMOC"></a>SRCMOC</h4>
+This variable is generated by the <a href="#StdInit">StdInit()</a> function if
+<code>CONFIG</code> contains "qt". <code>SRCMOC</code> contains the name of
+all intermediate moc files.<p>
+Example:<pre>
+ HEADERS = demo.h
+ SOURCES = demo.cpp main.cpp
+</pre>
+If <tt>demo.h</tt> and <tt>main.cpp</tt> define classes that use signals
+and slots (i.e. the <code>Q_OBJECT</code> "keyword" is found in these two
+files), <code>SRCMOC</code> becomes:<pre>
+ SRCMOC = moc_demo.cpp main.moc
+</pre>
+See also: <a href="#OBJMOC">OBJMOC</a>.
+
+
+<h4><a name="TARGET"></a>TARGET</h4>
+Sets the makefile target, i.e. what program to build.
+
+
+<h4><a name="TEMPLATE"></a>TEMPLATE</h4>
+Sets the default template. This can be overridden by the tmake -t
+<a href="tmake.html#usage">option</a>.
+
+
+<h4><a name="TMAKE_CC"></a>TMAKE_CC</h4>
+Contains the name of the compiler.
+
+
+<h4><a name="TMAKE_CFLAGS"></a>TMAKE_CFLAGS</h4>
+Contains the default compiler flags.
+
+
+<h4><a name="TMAKE_FILEVARS"></a>TMAKE_FILEVARS</h4>
+Tells tmake which variables contain file names. This is because tmake
+on Windows replace the directory separator / with \.
+
+
+<hr>
+<h2>Function Reference</h2>
+This section contains a brief description of some important
+tmake functions used by the templates.
+
+
+<h3><a name="AddIncludePath"></a>AddIncludePath(path)</h3>
+Adds <em>path</em> to the include path variable,
+<a href="#INCLUDEPATH">INCLUDEPATH</a>. The include path is used
+for two purposes:<ol>
+<li>Searching files when generating include dependencies.
+<li>Setting -I options for the C/C++ compiler.
+</ol>
+<p>
+Example:<pre>
+ #$ AddIncludePath('$QTDIR/include;/local/include');
+</pre>
+
+
+<h3>BuildMocObj(objects,sources)</h3>
+Creates build rules for moc source files. Generates
+include dependencies.<p>
+Example:<pre>
+ #$ BuildMocObj($project{"OBJMOC"},$project{"SRCMOC"});
+</pre>Output:<pre>
+ moc_hello.o: moc_hello.cpp \
+ hello.h \
+ ...
+</pre>
+
+<h3>BuildMocSrc(files)</h3>
+Creates moc source files from C++ files containing classes that
+define signals and slots. For a header file <tt>x.h</tt>, the
+generated moc file is called <tt>moc_x.h</tt>. For a source file
+<tt>y.cpp</tt>, the generates moc file is called <tt>y.moc</tt> and
+should be #include'd by <tt>y.cpp</tt>.<p>
+Example:<pre>
+ #$ BuildMocSrc($project{"HEADERS"});
+ #$ BuildMocSrc($project{"SOURCES"});
+</pre>Output:<pre>
+ moc_hello.cpp: hello.h
+ $(MOC) hello.h -o moc_hello.cpp
+</pre>
+
+
+<h3>BuildObj(objects,sources)</h3>
+Creates build rules for source files. Generates
+include dependencies.<p>
+Example:<pre>
+ #$ BuildObj($project{"OBJECTS"},$project{"SOURCES"});
+</pre>Output:<pre>
+ hello.o: hello.cpp \
+ hello.h \
+ ...
+
+ main.o: main.cpp \
+ hello.h \
+ ...
+</pre>
+
+
+<h3>Config(string)</h3>
+Returns true if the <code>CONFIG</code> variable contains the given string.
+<p>Example:<pre>
+ #$ if ( Config("release") { }
+</pre>
+
+
+<h3>DisableOutput()</h3>
+Call this function to force tmake to generate no output until
+EnableOutput() is called.
+<p>Example:<pre>
+ #$ Config("debug") && DisableOutput();
+ Anything here is skipped if CONFIG contains "debug".
+ #$ Config("debug") && EnableOutput();
+</pre>
+
+
+<h3>EnableOutput()</h3>
+Enables tmake output after DisableOutput() was called.
+
+
+<h3>Expand(var)</h3>
+Expands a project variable. Equivalent to <code>$text = $project{$var}</code>.
+<p>Example:<pre>
+ VERSION = #$ Expand("VERSION");
+</pre>Output:<pre>
+ VERSION = 1.1
+</pre>
+
+<h3>ExpandGlue(var,prepend,glue,append)</h3>
+Expands a $project{} variable, splits on whitespace
+and joins with $glue. $prepend is put at the start
+of the string and $append is put at the end of the
+string. The resulting string ($text) becomes "" if
+the project variable is empty or not defined.<p>
+Example:<pre>
+ clear:
+ #$ ExpandGlue("OBJECTS","-del","\n\t-del ","");
+</pre>Output (Windows NT):<pre>
+ clear:
+ -del hello.obj
+ -del main.obj
+</pre>
+
+
+<h3>ExpandList(var)</h3>
+This function is suitable for expanding lists of files.
+Equivalent with <code>ExpandGlue($var,""," \\\n\t\t","")</code>.<p>
+Example:<pre>
+ OBJECTS = #$ ExpandList("OBJECTS");
+</pre>Output:<pre>
+ OBJECTS = hello.o \
+ main.o
+</pre>
+
+
+<h3>ExpandPath(var,prepend,glue,append)</h3>
+Similar to ExpandGlue, except that it splits the items on a semicolon
+instead of space (if the variable contains at least one semicolon).
+
+
+<h3>IncludeTemplate(file)</h3>
+Includes a template file. The ".t" extension is optional.<p>
+Example:<pre>
+ #$ IncludeTemplate("mytemplate");
+</pre>
+
+
+<h3>Now()</h3>
+Sets $text to the current date and time.<p>
+Example:<pre>
+ # Generated at #$ Now()
+</pre>Output:<pre>
+ # Generated at 12:58, 1996/11/19
+</pre>
+
+
+<h3>Project(strings)</h3>
+This is a powerful function for setting and reading project
+variables. Returns the resulting project variables (joined with space
+between).
+<p>Examples:<pre>
+# Get a project variable:
+ $s = Project("TEMPLATE"); -> $s = "TEMPLATE"
+
+# Set a project variable:
+ Project("TEMPLATE = lib"); -> TEMPLATE = lib
+ Project("CONFIG =";) -> CONFIG empty
+
+# Append to a project variable:
+ Project("CONFIG = qt"); -> CONFIG = qt
+ Project("CONFIG += debug"); -> CONFIG = qt debug
+
+# Append to a project variable if it does not contain the value already:
+ Project("CONFIG = qt release"); -> CONFIG = qt release
+ Project("CONFIG *= qt"); -> CONFIG = qt release
+ Project("CONFIG *= opengl"); -> CONFIG = qt release opengl
+
+# Subtract from a project variable:
+ Project("THINGS = abc xyz"); -> THINGS = abc xyz
+ Project("THINGS -= abc"); -> THINGS = xyz
+
+# Search/replace on a project variable:
+ Project("CONFIG = tq opengl"); -> CONFIG = tq opengl
+ Project("CONFIG /= s/tq/qt/"); -> CONFIG = qt opengl
+
+# The operations can be performed on several project variables at a time.
+
+ Project("TEMPLATE = app", "CONFIG *= opengl", "THINGS += klm");
+</pre>
+
+
+<h3><a name="ScanProject"></a>ScanProject(file)</h3>
+Scans a project file and stores the project variables and values in the
+global associative <code>%project</code> array.
+
+
+<h3><a name="StdInit"></a>StdInit()</h3>
+Standard initialization of tmake. StdInit() should be
+called from one of the first lines in the template.<p>
+
+This function creates some new project variables:<ul>
+<li><code><a href="#OBJECTS">OBJECTS</a></code>
+ - Object files corresponding to
+ <code><a href="#SOURCES">SOURCES</a></code>.
+<li><code><a href="#SRCMOC">SRCMOC</a></code> - moc source files.
+<li><code><a href="#OBJMOC">OBJMOC</a></code> - moc object files.
+</ul>
+
+The moc-related variables are created only if <code>CONFIG</code> contains "qt"
+
+
+<h3>Substitute(string)</h3>
+This function takes a string and substitutes any occurrence of $$var
+with the actual content of the variable. Returns the substituted string.
+Also sets $text.
+<p>
+Important: Use single quotes around the string, otherwise perl will expand
+any $vars it finds.
+<p>Example:<pre>
+ Substitute('Project name: $$PROJECT, uses template $$TEMPLATE');
+</pre>