author | llornkcor <llornkcor> | 2002-06-23 14:32:50 (UTC) |
---|---|---|
committer | llornkcor <llornkcor> | 2002-06-23 14:32:50 (UTC) |
commit | 8672a04720e7421e7f41bbf49364bcc1df910bb2 (patch) (side-by-side diff) | |
tree | 2da9fe69cffd302f0b13fa6a4b03f5fb97ef4b63 /development | |
parent | ce9178fb13908eca5b7835e785fc0914a5022615 (diff) | |
download | opie-8672a04720e7421e7f41bbf49364bcc1df910bb2.zip opie-8672a04720e7421e7f41bbf49364bcc1df910bb2.tar.gz opie-8672a04720e7421e7f41bbf49364bcc1df910bb2.tar.bz2 |
some dev docs
-rw-r--r-- | development/cvsbook.html | 15663 | ||||
-rw-r--r-- | development/tmake_ref.html | 478 |
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 © 1999, 2000 Karl Fogel <kfogel@red-bean.com> + +<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> (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> set HOME=C: +C:\WINDOWS> 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> +</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> 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 <stdio.h> + +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 +> 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 +> 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 ">" 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 & 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 <stdio.h> +! +! 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 <stdio.h> +! +! 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 <stdio.h> +! +! 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 <-- 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 <-- 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 <-- 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 <-- 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 --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 <stdio.h> + +void +main () +{ + printf ("Hello, world!\n"); +<<<<<<< hello.c + printf ("this change will conflict\n"); +======= + printf ("between hello and goodbye\n"); +>>>>>>> 1.3 + printf ("Goodbye, world!\n"); +} +</pre> + +<p>Conflicts are always shown delimited by conflict markers, in the +following format: + +<pre><<<<<<< (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 +>>>>>>> (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 <stdio.h> + +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 <- 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 <- 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 <- 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 <stdio.h> + +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 <stdio.h> + +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 <stdio.h> + +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 ">" does): + +<pre>paste$ cvs -Q update -p -r 1.3 hello.c > 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 <- 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 <-- 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 <- 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 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 <- 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-------> + \ 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-------> + 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 <- 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) + .---------------->---------------. + / | + / | + / | + / | + / V (<------ point of merge) + ====*===================================================================> + (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 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 <- 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 <- 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 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) <--- (these are branch numbers) + / \ + 1.5.2.1 1.5.4.1 + | | + 1.5.2.2 1.5.4.2 + | | + (etc) (...) <--- (collapsed 34 revisions for brevity) + | + 1.5.4.37 + / + / + (1.5.4.37.2) <--- (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 <- 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 <- 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 <stdio.h> +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 <stdio.h +void main () +{ +<<<<<<< random.c + printf ("A random number.\n"); +======= + printf ("A random number.\n"); + printf ("Get the joke?\n"); +>>>>>>> 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 -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>* 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 <repository-location></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 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><USERNAME>:<ENCRYPTED_PASSWORD>:<OPTIONAL_SYSTEM_USERNAME> +</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 <stdio.h> + +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 <stdio.h> + +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 <-- 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 <stdio.h> + +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 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 <-- 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 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 <-- 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 > 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 <-- 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 &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 ------> name(s) of the file(s) being committed +%V ------> revision number(s) before the commit +%v ------> 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" => tag, "mov" => tag -F, "del" => 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 <-- 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 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 watch add...</code>, <code>cvs watch 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 +<REPOS> 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 <-- 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 <-- checkoutlist +new revision: 1.2; previous revision: 1.1 +done +Checking in users; +/usr/local/newrepos/CVSROOT/users,v <-- 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 <quentinsmith@farawayplace.com>" +</pre> + +<p>or + +<pre>qsmith:'Quentin Q. Smith <quentinsmith@farawayplace.com>' +</pre> + +<p>However, this will not work: + +<pre>qsmith:"Quentin Q. Smith" <quentinsmith@farawayplace.com> +</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: +# +# [<whitespace>]<filename><whitespace><error message><end-of-line> +# +# 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 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 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 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 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 <-- 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 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>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>edit+unedit+commit +floss$ cvs watch add README.txt +floss$ cat /usr/local/newrepos/myproj/CVS/fileattr +Fhello.c _watchers=jrandom>edit+unedit+commit +FREADME.txt _watchers=jrandom>edit+unedit+commit +floss$ cvs watch on hello.c +floss$ cat /usr/local/newrepos/myproj/CVS/fileattr +Fhello.c _watchers=jrandom>edit+unedit+commit;_watched= +FREADME.txt _watchers=jrandom>edit+unedit+commit +floss$ cvs watch remove hello.c +floss$ cat /usr/local/newrepos/myproj/CVS/fileattr +Fhello.c _watched= +FREADME.txt _watchers=jrandom>edit+unedit+commit +floss$ cvs watch off hello.c +floss$ cat /usr/local/newrepos/myproj/CVS/fileattr +FREADME.txt _watchers=jrandom>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>Tue Jul 20 04:53:23 1999 GMT+floss\ ++/home/qsmith/myproj;_watchers=qsmith>tedit+tunedit+tcommit +FREADME.txt _watchers=jrandom>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 & 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 <peter.ross@miscrit.be>; 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 -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 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 <REPOS></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 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 <stdio.h> +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 +< printf ("Hello, world!\n"); +-- +> 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 <stdio.h> +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 <stdio.h> +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 <stdio.h> +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 <stdio.h> +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 <stdio.h> +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 <stdio.h> +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 <stdio.h> +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$ ==> date of last commit, expands to ==> +$Date$ + +$Id$ ==> filename, revision, date, and author; expands to ==> +$Id$ + +$Revision$ ==> exactly what you think it is, expands to ==> +$Revision$ + +$Source$ ==> path to corresponding repository file, expands to ==> +$Source$ + +$Log$ +Revision 1.1 2002/06/23 14:32:50 llornkcor +some dev docs + ==> accumulating log messages for the file, expands to ==> +$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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 <-- 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 + ... +<<<<<<< README.txt +key $Revision$ +======= +key $Revision$ +>>>>>>> 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 <-- digest.c +new revision: 1.2; previous revision: 1.1 +done +Checking in src/main.c; +/usr/local/newrepos/theirproj/src/main.c,v <-- 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 () + { ++ <<<<<<< digest.c + printf ("gurgle, slorp\n"); ++ ======= ++ printf ("mild gurgle\n"); ++ >>>>>>> 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 +< printf ("gurgle, slorp\n"); +-- +> 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 <-- digest.c +new revision: 1.3; previous revision: 1.2 +done +Checking in src/main.c; +/usr/local/newrepos/theirproj/src/main.c,v <-- 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 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 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 update -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 update -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 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 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 [&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 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> 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> 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> [COMMAND] or <code>-H</code> [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 -n 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> 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> 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> or <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> 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: add [OPTIONS] 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: admin [OPTIONS] [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 admin -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: annotate [OPTIONS] [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: checkout [OPTIONS] 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 REV[:DATE] or -j REV1[:DATE] -j 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: commit [OPTIONS] [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: diff [OPTIONS] [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: edit [OPTIONS] [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: editors [OPTIONS] [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: export [OPTIONS] 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: 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: history [OPTIONS] [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 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 == <remote> +M 08/22 04:18 +0000 jrandom 1.2 README myproj == <remote> +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: import [OPTIONS] REPOSITORY VENDOR_TAG 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 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 !</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 !</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: init 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: 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: log [OPTIONS] [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<DATE2 - Selects revisions created between DATE1 and DATE2. If +DATE1 is after DATE2, use <code>></code> instead; otherwise, no log messages +are retrieved. + +<li><DATE DATE> - All revisions from DATE or earlier. + +<li>>DATE DATE< - 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><=</code> and <code>>=</code> instead of <code><</code> and <code>></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<1999-07-01;1999-08-01<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: 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: 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: 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: rdiff [OPTIONS] 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: release [OPTIONS] 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: remove [OPTIONS] [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: rtag [OPTIONS] TAG 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: 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: status [OPTIONS] [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: tag [OPTIONS] TAG [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: unedit [OPTIONS] [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: update [OPTIONS] [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 > 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: watch on|off|add|remove [OPTIONS] [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 add</code> and <code>watch 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: watchers [OPTIONS] [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 README.txt</code>, and <code>%v</code> into +<code>1.17 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 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 [OPTIONS] [&OTHERMODULE...] [DIR] [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 PROGRAM [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 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 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 PROGRAM [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 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 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> (directory)</h3> + +<p>If watches are on, <code>cvs edit</code> stores the original copy of the +file in this directory. That way, <code>cvs 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 -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 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 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 OPTS</code>, <code>--global-opts 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 OPTS</code>, <code>--log-opts 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<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><</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 <v.slavik@volny.cz>, 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 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 cvslock</code>, which is a manual page +installed when you ran <code>make 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> </td> + <td>release</td> + <td> </td> + <td>Compile with optimization enabled, ignored if + "debug" is specified.</td> + </tr> + <tr> + <td> </td> + <td>debug</td> + <td> </td> + <td>Compile with debug options enabled.</td> + </tr> + <tr> + <td> </td> + <td>warn_on</td> + <td> </td> + <td>The compiler should emit more warnings than normally, ignored if + "warn_off" is specified.</td> + </tr> + <tr> + <td> </td> + <td>warn_off</td> + <td> </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> </td> + <td>qt</td> + <td> </td> + <td>The target is a Qt application/library and requires Qt header + files/library.</td> + </tr> + <tr> + <td> </td> + <td>opengl</td> + <td> </td> + <td>The target requires the OpenGL (or Mesa) headers/libraries.</td> + </tr> + <tr> + <td> </td> + <td>x11</td> + <td> </td> + <td>The target is a X11 application (app.t only).</td> + </tr> + <tr> + <td> </td> + <td>windows</td> + <td> </td> + <td>The target is a Win32 window application (app.t only).</td> + </tr> + <tr> + <td> </td> + <td>console</td> + <td> </td> + <td>The target is a Win32 console application (app.t only).</td> + </tr> + <tr> + <td> </td> + <td>dll</td> + <td> </td> + <td>The target is a shared object/DLL (app.t only).</td> + </tr> + <tr> + <td> </td> + <td>staticlib</td> + <td> </td> + <td>The target is a static library (lib.t only).</td> + </tr> + <tr> + <td> </td> + <td>thread</td> + <td> </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> |