![]() |
![]()
| ![]() |
![]()
NAMEcvslines - a CVS wizard to help manage parallel development SYNOPSIScvslines [status] [-l|-R] file|dir ... cvslines checkout [-d dir] line module | -t module cvslines commit [-n] [-l|-R]
[-x|-X] [-b] [-o] [-i] [-q]
DESCRIPTIONcvslines is, in effect, a "wizard" helper for use with the standard cvs(1) command. cvslines helps users of cvs modules representing multiple parallel "lines of development" to manage the task of merging changes from one such line into others at commit time, as appropriate. These lines of development (hereafter referred to simply as "lines") typically represent different releases of a software system. (These are often thought of as "branches". However, cvslines reserves the term "branch" to refer to the more precise definitions as they are used in rcs(1) and cvs). OPTIONScvslines supports the following options:
THE cvslines.config FILETo inform cvslines about the set of lines that are under its management, each cvs module under cvslines control has one (or more) cvslines.config file(s), in the module's top-level repository directory(s). The cvslines.config file is typically set up by your cvs administrator; most other users can safely skip this section. If a cvs module is defined to include multiple files and/or directories, then the cvslines.config file should be replicated in the root of each directory specified. E.g., for a $CVSROOT/CVSROOT/modules entry of
You would need a single cvslines.config file
For a module defined as
you would need to replicate the cvslines.config file as
(For convenience of administration, you could make the multiple cvslines.config files be links to the same file). For example, for a module "tmod", this would be "$CVSROOT/tmod/cvslines.config". The cvslines.config file has the following format
THE $CVSROOT/commitinfo ENTRIESIn order to tell cvs that a given module should have commits controlled via the "cvslines commit" command (rather than directly via the normal "cvs commit" command), cvslines uses a pair of entries in the $CVSROOT/commitinfo file, for example
This causes cvs to execute the cvslines_check command for each directory containing files to be committed when changes to files in the "tmod" module are committed. THE cvslines checkout COMMANDThe "cvslines checkout" command can be used to make cvslines translate the specified line name into the correct cvs branch tag for checking out a tree for a given line of development. The translated name is supplied in a "cvs checkout" command, which is displayed and then automatically executed for you. E.g.:
You can use "cvslines checkout -t module" to get a list of the line names known for a specified module:
THE cvslines status COMMANDThe "cvslines status" command (which is what you get by default if you just type "cvslines" without naming a subcommand) reports on the status of each line of development for each cvs-controlled file, as specified by the named files and/or directories. The file and directory arguments work just like they do in cvs: a directory name will cause all files in the directory to be reported (with directory recursion), and a file name will only do the named file. The "-l" option can be used to inhibit directory recursion, or the "-R" option to explicitly enable it. For each file it reports on, "cvslines status" will show, for each line under cvslines control (as specified in the cvslines.config file for the module), the line name, the cvs branch specification, the actual numeric value represented by this specification, and the current RCS revision for the line. For example:
(The ">>" tags show that these lines are the ones represented by the working tree from within which cvslines was invoked.) For lines that do not currently include the file, the spec rev will be shown as "head" or "none", for lines specified as "head" or with a branch tag, respectively. The value for "cur rev" for either will be shown as "none":
If multiple "lines groups" are defined (See the "LINES GROUPS" section, below), then (by default) "cvslines status" will indicate lines that are not members of the same lines group as the current working tree's, with an "xx" tag before the line names:
THE cvslines commit COMMAND - EXAMPLEThis section explains in broad terms how "cvslines commit" works. For a more detailed discussion, including how newly added files are handled and other special cases, please see the next section. To employ cvslines for a module, commits of changes to files in the module should be done via "cvslines commit", instead of the usual "cvs commit" command. In order to help remind users of this convention, attempts to commit files with "cvs commit" for a module under cvslines control will result in a message like:
To actually do the commit, you use "cvslines commit". You can name individual files and/or directories (which are treated recursively by default), just as you would with the ordinary cvs commit command. The "-l" option inhibits directory recursion. You can force cvslines to allow you to do a direct cvs commit by running "cvs commit" with the variable $CVSLINES_NOCHECK set in the environment. "cvslines commit" operates in two phases. In the first ("planning") phase, it asks you, for each file, whether the changes being committed should also be applied to the other lines of development that contain the file. Based on your answers, cvslines decides on the proper cvs actions to take. In the second ("execution") phase, cvslines helps you to execute the plans created in the first phase, supplying you with the command lines required and allowing you to execute them. Here's an example, in which a single file is being committed. First, cvslines presents a summary of the current status of the file, with a line for each line of development in the module under cvslines control. The line prefixed with ">>" is the one represented by the file in the working directory. Other lines that contain the file are prefixed with either "u?" or "m?", indicating that the change would be applied with an update or a merge, should it also need to be applied to that line of development. (I.e., lines prefixed with "u?" have not yet diverged with respect to the one represented by the file in the working directory). The tag "a?" is used to indicate that a file being added by a commit might be applicable to another line.
Next, cvslines asks whether, for each of the other lines of development, you wish to also apply the changes to that line, and then proposes an "Action plan" based on the responses:
The action plans show, for each line that wants to get the changes, how they will be applied, and the RCS revision number that would result. In the example above, the user wants the changes to go into all of the lines containing the file. cvslines has decided that this will require two commits, one to create revision 1.3 (which will update the R1.1 and R1.2 lines), and one (based on a merge) to create revision 1.1.1.2.1 (which will update the R1.0 line). If the user agrees to the action plan, cvslines will move into the execution phase. (In this example, there was only one file being committed, so the execution phase for "file2" follows the planning phase directly. Had there been other files involved in the commit, their planning phases would be performed prior to the execution phases for any of them). By default, cvslines displays each action it will take, and waits for the user to type a Return for confirmation before proceeding. You can disable these confirmation prompts either by running "cvslines commit" with the -x option, or by placing the line "$Noaskexec=1; 1;" in your ~/.cvslinesrc file. However, it's recommended that you go ahead and allow the confirmations, as it will help you to understand more about how cvslines uses cvs. Continuing our example, cvslines begins to execute the plan for "file2":
(The user presses Return in order to tell cvslines to proceed)
(The user enters the CVS log message in the usual manner)
(The user is placed into $EDITOR to resolve merge conflicts)
In the example above, the steps taken to include the changes in the R1.0 line demonstrate how cvslines handles merging. In this case, the CVS merge facility detected merge conflicts, which must be resolved by the user before committing the file. In such cases, cvslines allows the user to either edit the file and proceed, or to "skip" the commit, in which case a copy of the partially merged file will be saved for later attention, and further actions relying on that revision will be skipped. For example, has the user chosen "skip" in the example above:
THE cvslines commit COMMAND - BRANCH TAG UPDATESThis section documents, in greater detail, how cvslines handles particular cases that can arise in carrying out the action plans it has generated. In general, cvslines will try to avoid actions that would result in the creation of new RCS branches where the tip of the branch doesn't really differ from the tip of its parent branch. This can occur with cvs-controlled modules, for example, when a release branch has been declared (by branch-tagging the files), and a change is applied in a branched working directory. Normally, this will result in the creation of a new RCS branch, since (as far as cvs knows), the change represents a change that should be applied to the branch, only. This is fine, if indeed the same change needn't be carried forward into the new version of the software (on the parent RCS branch). But, if the change is also desired on the parent branch, it will need to be checked in separately there, too. This results in two distinct RCS revisions that are actually identical. (Except perhaps, in their RCS ident information expansions). Furthermore, this consigns all such future changes (that need to go onto both branches) to needing a pair of check-ins, one for each branch. cvslines avoids this situation, where possible, by using the strategy of checking in the changes to the tip of the existing RCS branch, and simply updating the branch tag in the branched line of development. This could also be done manually, of course, if the user remembers to think about it beforehand, and knows the right set of cvs commands to use. cvslines helps out by reminding the user about the situation, and, based on the user's desire about applying the change to both branches, by supplying the necessary cvs commands in order to make the commit go onto the parent branch and to update the branch tags. cvslines can handle the situation described above equally well from a working directory corresponding to either line of development. THE cvslines commit COMMAND - MERGESIn other cases, when the revisions on the tips of different lines have previously diverged, cvslines can still help out with the mechanics of merging a set of changes and checking them in appropriately. It does this using a "cvs update -jrev1 -jrev2" command, which in turn uses the rcsmerge(1) command. When merge conflicts are detected, the user is given the opportunity to either edit the conflicts out of the file, and continue with the check-in, or to save away a copy of the file containing the conflicts, to be dealt with later. cvslines will properly handle cases where changes are merged onto the tip of an existing RCS branch, and/or lines that exist as branch tags attached to such a branch. THE cvslines commit COMMAND - ADDED FILEScvslines can also help when new files are being added to a module. As for commits of changes modifying existing files, cvslines asks the user whether newly added files being committed into the module should also be included in the other lines of development, and arranges to do the right things, based on the user's answers. For example...
(The user enters the CVS log message in the usual manner)
Note that cvslines had to go through some slight contortions in order to convince cvs to add the file as a new revision on the main trunk, rather than initially onto a branch, as a "normal" cvs commit would do in this situation. The result is, nonetheless, what was desired; the file now exists in both lines of development, and remains undiverged. THE cvslines commit COMMAND - NEWLY IMPORTED FILESThere is one case where cvslines will actually move a branch tag from a second-level RCS branch back onto the trunk. This happens for files that have not been modified with any check-ins since being added to a module for the first time with "cvs import". Here's what such a file looks like:
This is the state that a file is in following a cvs import, and two subsequent branch taggings (but before any changes have ever been checked in.) Note that, as far as CVS is concerned, the branched revisions are branched off of the "vendor's release" (at revision 1.1.1.1), not off of the head revision (1.1). But, in reality, of course, no divergence has taken place. In order to prevent actual branching, a cvslines commit to a file in this state will treat the file as if branches were off of the trunk. It alerts you to this by placing a "*" character next to the "spec rev" reported for such a line:
(The user enters the CVS log message in the usual manner)
As shown above, when you choose to update such a branch, the branch tag gets moved onto the new revision checked in on the trunk, properly re-uniting the (as yet undiverged) branches with the trunk. MULTIPLE head LINEScvslines can also help to detect the time at which a new line should be declared for a module (i.e., by branching tagging the entire module). To use it this way, you can have multiple line names sharing the specifier "head". When a user committing a change to any line specified by "head" declines to include the change in all such lines, then cvslines balks, and recommends that the module actually be branched. When using such multiple "head" lines, cvslines needs a way to know, when in a working tree representing one of the "head" lines, which one it's in. (There's no way to infer this from normal cvs administrative files as there is for trees representing branch lines). "cvslines status" will simply show all lines set to "head" as being the current line:
When it can't resolve the line name in this situation, "cvslines commit" will report:
In order to handle this and allow the commit to proceed, cvslines will look for either
In the event that a user attempts a commit, specifying that the changes are not wanted on all of the lines that share the head of the trunk, then cvslines will recommend:
THE $HOME/.cvslinesrc filecvslines users can alter the default behavior of cvslines to some extent by creating entries in a file name ".cvslinesrc" in their home directories. Currently, the following defaults can be changed:
The last line of the .cvslinesrc file must be "1;". If you've flipped one of the above defaults in your $HOME/.cvslinesrc, then the alternate behavior can usually be requested by using one of the other associated option letters. For example, if you have the following $HOME/.cvslinesrc file:
then, for you, the default will be not to use the "[press Return to]" prompts. If you do want the prompts for a particular invocation, you can say "cvslines commit -X ...". LINES GROUPSSometimes, an organization may wish to reserve certain lines of development for projects as being logically separate from others. That is, some group may need to work on one or more lines of development where the norm is to rarely merge updates onto other lines. cvslines helps to support this model by using a feature called "lines groups". Lines groups are defined by designating line group names in the cvslines.config file. Every line is a member of exactly one lines group. By default (i.e., if the lgroup field for a line in the cvslines.config file is empty), then line is a member of the default lines group (""). "cvslines commit" will only ask whether a change should be committed to other lines in the same lines group as the one for the working tree in which cvslines commit is invoked. Normally, cvsline status will show the status for all lines. (It does, however, indicate lines outside of the current working tree's lines group with an "xx" tag). The -o option restricts it to showing the status only for lines in the same group as that of the working tree from which it is invoked. Similarly, when summarizing a file's status, "cvslines commit" normally indicates lines that are outside of the current working tree's lines group with an "xx"-tagged entry. The -o option eliminates the display of lines from other lines groups. The -a option may be used to turn off the lines groups feature altogether. This can be useful when, working within a tree representing one of multiple lines groups, you wish to propagate a change to lines outside of the group. CVSLINES AND REMOTE CVScvslines will work properly in "remote cvs" mode, using the "ext" method. Currently, cvslines does not support remote cvs with authentication. CVSLINES HACKERYOccassionally, you may want to do a commit specifically to some other line than the one represented by the tree you are working in. (I.e., a commit only to that line, instead of the working tree's line plus some other(s)). This situation often arises when you've deferred the reconcilation of merge conflicts discovered during a previous cvslines commit. To do this, you can use the following trick, which allows you to change the "current" line of development for a single file within a tree originally checked out from another. In this example, assume that the tree we're working in is using the line of development on the head of the RCS trunk, and suppose that we want to resolve merge conflicts detected during an attempt to merge changes to "fileX" into the R1_1_BRANCH version, and which we chose not to resolve during that commit. (cvslines has therefore saved the partially merged file as "fileX-conflicts-R1_1_BRANCH").
CVSLINES ACTION CATALOGThese are the actions that cvslines may propose for a given line:
STRUCTUREcvslines is written in perl. In order to minimize the perl compilation times for the "status", "check" and "commit" subcommands, the code is broken up into a common module, and three subcommand-specific modules that are "require"ed as needed. These must all exist in the same directory. Also, a symbolic link "cvslines_check -> cvslines" needs to exist. This allows cvslines to be invoked by the standard CVS commitinfo file hook, to run the "check" subcommand. BUGScvslines currently doesn't do "cvs remove"s. You have to make sure they happen in all applicable lines "by hand". FILES$CVSROOT/CVSROOT/commitinfo $CVSROOT/module/cvslines.config /usr/local/bin/cvslines /usr/local/bin/cvslines-status /usr/local/bin/cvslines-commit /usr/local/bin/cvslines-check /usr/local/bin/cvslines_check $HOME/.cvslinesrc $Id: cvslines.1,v 1.2 2002/04/19 13:26:39 irockel Exp $
|