-------------------------------------------------------------------------------
CVS is Copyright (C) 1986-2006 The Free Software Foundation, Inc.
CVS 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 1, or (at your option)
any later version.
More details are available in the COPYING file but, in simplified
terms, this means that any distributed modifications you make to
this software must also be released under the GNU General Public
License.
CVS 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.
-------------------------------------------------------------------------------
This file contains a CVS FAQ. Until 1995 it was maintained by David
Grubbs. It was out of date and not being maintained, but it had a
certain following and in 1997 Pascal Molli decided to start
maintaining it with the FAQ-O-Matic package which allows any
contributor with a web browser to help maintain it. The following
text is (mostly automatically) extracted from the FAQ-O-Matic. The
odds are good that the file that you are currently reading is out of
date with respect to the online FAQ-O-Matic, which is part of Pascal
Molli's CVS web site at http://www.loria.fr/~molli/cvs-index.html
(currently under "Documentation"). The online version is also
somewhat better in terms of things like tables of contents (at least
until someone can write some code to extract data from a FAQ-O-Matic
and insert things like tables of contents).
The answers which are dated "6/13/1997" below are really from the 1995
FAQ, for the most part. Many of them are out of date. The current FAQ may
be found at . If you have
some time, you are encouraged to export that FAQ as text and import it here.
If you don't have such time, take the answers in this file with at least a few
grains of salt.
Since August, 2005, many of the existing CVS resources have been centralized on
& .
Category: /, all questions
Category: /
" [INLINE] "
1. About FAQ-O-Matic
This is FAQ-O-Matic, a quick-and-dirty Perl hack (aren't they all?) by
Jon Howell.
It seems like most FAQ maintainers make a valiant initial effort, then get
a life and don't have time to keep their FAQs up to date. Also, I often
find out a solution to a problem, and feel like I could write a single
FAQ answer on it in a few minutes, but where to post it?
Thus the FAQ-O-Matic was born. FAQ-O-Matic is a couple sleazy Perl scripts
that allow people to submit FAQ answers to this database, so it can stay
current, with just a tiny bit of work on any one person's part.
Yes, a bad guy could come along and wipe out all the FAQ entries. Please don't.
But to give the good guys some measure of comfort, each submission is stored
in an RCS file, so if someone does tamper, we can recover the database.
Guidelines for submissions:
1. Please _try to be fairly unbiased in matters of opinion._ Mailing lists are
the place to start flame wars (just kidding :v), but definitely not here.
2. Please _use HTML only conservatively_ in your entries. Links are appropriate
,
but put the URL in the plaintext also so it's useable on printed versions of
the FAQ. Inline images pointing off this site are inappropriate, as is much
fancy formatting. This is meant to be bandwidth-light and dumb-browser-friendly
.
3. If you feel there's a place for a _new category, or a reorganization of
existing questions_, don't hesitate to mail me (molli@loria.fr).
Category changes need to be done from my end.
4. Please _leave an email address_ at the bottom of your submission so that oth
ers
can drop you a note.
5. _If you only have a question_, not an answer, you should probably post
it to a mailing list, not here. If there are frequently asked questions to whic
h
the answer is not forthcoming on mailing lists (or perhaps there's no
useful answer yet other than "no one knows"), then it's appropriate to
post here, in hopes that someone will see it and know the answer.
6. Please refrain from crude or inconsiderate language. Please don't use
this as a forum for advertising. However, mention of worthy commercial
products is certainly appropriate (even if you sell said product). Just
don't overdo it. :v)
Last modified: _6/13/1997_
2. Adding a new category ?
just send me a mail at
molli@loria.fr
Last modified: _6/13/1997_
Category: /Advanced_Topics_/
" Advanced Topics "
Category: /Advanced_Topics_/Branching_and_Mergin/
" + Branching and Merging"
1. What is a branch?
Unfortunately, the word "branch" is an overloaded technical
term. It is used in too many different ways in three
categories. It might help to understand some of the issues by
going through the categories:
How Humans use the word "branch":
Most development starts with everyone working on the same
software, making changes and heading toward a single goal. This
is called something like "Main Line Development". Note that
though many people do main line development on CVS's "Main
Branch", that is a choice, not a requirement.
After a release or when one or more developers want to go off
and work on some project for a while, the Software Engineers
assigned to deal with large software issues generate a "Branch
in Development" to support the release or project. (Keep in
mind that a programmer is no more a Software Engineer than a
carpenter is a Civil Engineer.)
Essentially, the word "branch" implies a way to allow
simultaneous development on the same files by multiple people.
The above terms are human-oriented. They refer to actions that
people would like to take. They do *not* imply any particular
implementation or set of procedures. Branches in development
can be supported in many different ways.
How CVS uses the word "branch":
CVS uses the word "branch" in a number of ways. The two most
important are:
- The vendor branch holds releases from (normally) an outside
software vendor. It is implemented using a specific RCS branch
(i.e. 1.1.1).
- The "Main Branch", which normally holds your "Main Line
Development", but is defined as the collection of revisions you
get when you "checkout" something fresh, or when you use the
'-A' option to "update".
Important Note: The CVS "Main Branch" is *not* the same as the
RCS concept with the same name. If you are using Vendor
Branches, files you have never changed are on three branches at
the same time:
- The RCS 1.1.1 branch.
- The CVS Vendor branch.
- The CVS "Main Branch".
The concepts overlap, but they are not equivalent.
In referring to CVS, "branch" can be used in four other ways:
- A CVS working directory satisfies the definition of "branch"
for a single developer -- you are on a private "virtual branch"
that does not appear in any of the RCS files or the CVS control
files.
- The CVS "default branch" is the Repository source for the
collection of files in your working directory. It is *not* the
same as the RCS "default branch". Normally the CVS default
branch is the same as the CVS Main branch. If you use the "-r
" option to the "checkout" command, you will record
a "sticky" tag that changes your default branch to the one you
checked out.
- A "magic" branch can be a branch that hasn't happened yet. It
is implemented by a special tag you can check out that is not
attached to a real RCS branch. When you commit a file to a
magic branch, the branch becomes real (i.e. a physical RCS
branch).
- And, of course, CVS uses "branch" to indicate a
human-oriented "branch in development".
How RCS uses the word "branch":
- The RCS "Main Branch" (Synonym: "The Trunk") contains a
series of two-part revision numbers separated by a single '.'
(e.g. 1.2). It is treated specially and is the initial default
branch. (The default default?)
- The RCS "Default" branch starts out attached to the RCS "Main
Branch". For RCS purposes, it can be changed to point to any
branch. Within CVS, you *must*not* alter the RCS default
branch. It is used to support the CVS idea of a "Main Branch"
and it must either point to the RCS Main Branch, or the Vendor
Branch (1.1.1) if you haven't made any changes to the file
since you executed "import".
Last modified: _6/13/1997_
2. Why (or when) would I want to create a branch?
Remember that you can think of your working directory as a "branch for
one". You can consider yourself to be on a branch all the time because
you can work without interfering with others until your project (big
or small) is done.
The four major situations when you should create a branch:
When you expect to take a long time or make a large set of changes
that the merging process will be difficult. Both "long" and "large"
are defined in your own environment.
When you want to be able to "commit" and "tag" your work repeatedly
without affecting others.
If you ever think you need Source Control for your own work, but don't
want your changes to affect others, create a private branch. (Put your
username in the branch tag, to make it obvious that it is private.)
When you need to share code among a group of developers, but not the
whole development organization working on the files.
Rather than trying to share a working directory, you can move onto a
branch and share your work with others by "committing" your work onto
the branch. Developers not working on the branch won't see your work
unless they switch to your branch or explicitly merge your branch into
theirs.
When you need to make minor changes to a released system.
Normally a "release" is labeled by a branch tag, allowing later work
on the released files. If the release is labeled by a non-branch tag,
it is easy to add a branch tag to a previously tagged module with the
"rtag" command. If the release is not tagged, you made a mistake.
Recovery requires identifying all revisions involved in the release
and adding a tag to them.
Last modified: _6/13/1997_
3. How do I create and checkout a branch?
Suggested technique:
Attach a non-branch tag to all the revisions you want to branch
from. (i.e. the branch point revisions)
When you decide you really need a branch, attach a branch tag to the
same revisions marked by the non-branch tag.
"Checkout" or "update" your working directory onto the branch.
Suggested procedure when using modules:
cvs rtag module
cvs rtag -b -r
cvs checkout -r module
Suggested procedure when using your working directory, which
contains the revisions of your working files you want to branch from:
cvs tag
cvs rtag -b -r
cvs update -r
In each procedure above, Step #1 applies a non-branch tag to all the
branch point revisions in the module/directory. Though this is not
strictly necessary, if you don't add a non-branch tag to the revisions
you branch from, you won't be able to refer to the branch point in the
future.
Between steps 1 & 2 you may commit changes. The result would be same
because "rtag -r " applies to the same
revision that is attached to. You can use this technique to
avoid attaching *any* branch tags until you need them.
Step B.2 has two corollaries:
If you plan to create the branch tag before committing anything in
your working directory, you can use "cvs tag -b " instead
of the "rtag" command.
The can be a relative path to a directory from which your
working directory was checked out.
If you have trouble figuring out what to use (or pathname to
use in its place), you can aim it at whatever parent directories you
believe will cover all your work.
If you are sure the is not being used anywhere else, you
can even aim it at the whole Repository ($CVSROOT), if you have to. It
might take some extra time, but assuming that your is a unique
string and you don't use the '-f' option to "rtag -r", "rtag" will
only add a to files in which it actually *finds* the earlier
.
In each procedure above, Step #3 may occur any time after step 2.
Unless you explicitly remove them with "tag -d", a is permanent.
The is an unusual creature. It labels a branch in a way
that allows you to "checkout" the branch, to "commit" files to the end
of the branch and to refer to the end of the branch. It does not label
the base of the branch (the branch point).
There are two obvious ways to choose the and
names. But keep in mind that the is typed by
any developer who wants to work on the branch -- you should make it
mean something to them.
Style #1 presumes that the simple version string refers to a set of
designed, documented or promised features, not to a specific set of
files. In this case, you tag the branch with the generic Version
string and assume that whenever you refer to "Version", you want the
"latest" set of files associated with that Version, including all
patches. (You can substitute whatever you like for "bp_", as long as
your is some modification of the .)
Matching
bp_V1_3 V1_3
bp_Release2-3-5 Release2-3-5
bp_Production4_5 Release4_5
Style #2 presumes that the simple version string refers to the
specific set of files used to construct the first release of
"version". In this case, you tag the branch-point revisions with the
generic Version string and assume that whenever you refer to this
Version, you want the original set of released revisions. To get the
latest patched revisions of the release, you refer to the branch tag
"latest_". (You can substitute what ever you like
for "latest_", as long as your is some modification of
the .)
Matching
V1_3 latest_V1_3
Release2-3-5 latest_Release2-3-5
Release4_5 latest_Production4_5
In both styles you can find out what you had to change since the
original release of this Version by typing:
cvs diff -r -r
For Style 1, this is:
cvs diff -r bp_ -r
For Style 2, this is:
cvs diff -r -r latest_
Notes on "being on a branch":
- "update -r " tells CVS to attach a "sticky tag" to working
directory (in ./CVS/Tag) and the checked-out files (on each line of
./CVS/Entries).
- A "sticky" (including a ) causes most CVS commands
to act as if "-r " were on the command line.
- A "sticky" indicates that the working directory (and
working files) are "on the branch".
Last modified: _6/13/1997_
4. Once created, how do I manage a branch?
The most important thing you should know about managing a branch is
that the creation of a branch is not a lightweight act. When you
create a branch, you must also create a set of procedures to keep
track of it.
Specifically, you must:
- Remember that the branch exists. (This is non-trivial if you create
a lot of them.)
- Plan when to merge it back into the main line of development.
- Schedule the order that multiple branch merges are to be done.
- If you ever intend to merge branches into each other, instead of
limiting merges of branch work back into the "main line", you must
keep careful track of which parts of which branches have merged into
which other branches.
The simplest way to deal with branches is to limit their number,
"collapse" them back into the main line as quickly as is reasonable
and forget them. If a group wants to continue working, tell them to
create another branch off the fully merged main line.
Remember that CVS is just a tool. Over time, it will probably handle
branching better, requiring less careful attendance. But no matter how
good it becomes, the whole idea of "branching" is a complicated
management problem. Don't take it lightly.
Last modified: _6/13/1997_
5. Are there any extra issues in managing multiple branches?
If you plan to split from the "main line" and merge back after a time,
the only problem will be scheduling the order of branch merges. As
each branch is merged, the main line must be rebuilt and tested.
Merging multiple branches (i.e. "lines of development") before
building and testing creates more problems than you are ready for.
If you plan to collapse some branches into others, then move the
combined branches back into the main line, you have to be careful with
the revisions and tags you hand to your "update -j" command, but it
shouldn't be much trouble.
If you plan to allow every branch to incrementally take the work done
on other branches, you are creating an almost insurmountable
bookkeeping problem. Every developer will say "Hey, I can handle
taking just this little bit," but for the system as a whole it is
disaster. Try it once and see. If you are forced into this situation,
you will need to keep track of the beginning and end points of every
merge ever done. Good Luck.
Last modified: _6/13/1997_
6. How do I merge a whole branch back into the trunk?
If you don't have a working directory, you can checkout and merge in
one command:
cvs checkout -j
cd
If you already have a working directory:
cd
cvs update <== Optional, to bring it up to date.
cvs update -j
CVS will print lines beginning with
'U' for files that you hadn't changed, but the branch did.
'M' for files that you changed and the branch didn't
*and* for files that you both changed that were merged
without overlaps. (This overload is unfortunate.)
'C' for files that you both changed in a way that conflicts
with each other.
You need to go edit all the 'C' files and clean up the conflicts. Then
you must commit them.
Last modified: _6/13/1997_
7. How do I merge changes from the trunk into my branch or between
branches?
The idea is similar to the above, but since CVS doesn't treat the main
branch like other branches, you'll have to be more careful. There are
5 different ways to look at the problem.
The way to merge *all* changes made on the trunk into a working
branch is to move to the branch you want via "checkout -r" or "update
-r":
cvs update -r {optional files}
Then merge the changes from the trunk into your working branch using
the pseudo-tag named "HEAD":
cvs up -j HEAD {optional files}
You will get everything from the branch point of the branch named
up to the HEAD of the main branch. This is still kind of
strange. If the file is on a branch, HEAD should be the latest thing
on the branch, not the HEAD of MAIN. But that's not the way CVS
(currently) works.
If you run "cvs up -j HEAD" again after adding more revisions to the
trunk, you may get overlaps for the text you have already merged. It
depends on your version of your RCS "merge" command (actually the "co
-j" option, which depends on the version of "diff3" you configured RCS
to use).
You can merge the difference between any two using two "-j"
options on "update" or "checkout".
Identify the two tags on the branch you want to merge from.
cvs update -j -j {optional files}
This step assumes you were careful about tagging milestones. You can
use this technique for any two on the same branch, even the
trunk. It is also possible to use tags on different branches, but
you'll have to ponder the meaning of the difference between those two
tags.
In place of one of the , you can use a to refer to
the latest revision on that branch. See 4C.11 and 4C.3 for info on
branch points.
Merges can also be performed by handing RCS revisions to the '-j'
options, but since revision numbers aren't the same in all files,
merging by number is normally limited to one file. Sets of files with
the exact same trees of branches and revision numbers would work too,
but that's a rare situation.
To "take" revisions from other branches instead of merging them, see
4C.19 for an idea.
A way to gain the effect of merging the main to the branch is to
merge the branch into the main using the normal
cvs update -A {optional files}
cvs update -j {optional files}
cvs commit
cvs tag -F -b {optional files}
See part B of 4D.5
Other oddities.
This also works, but is probably not officially supported:
cvs update -j N {optional files}
where N is a number. This will merge all the changes from the branch
point up to the highest revision on the main branch starting with N.
For example, if your highest trunk revision is 1.52, you can use this
to grab revisions from the trunk:
cvs update -j 1 {optional files}
Another example: Say you have a branch point at rev 1.2 for a branch
named "BR1" and trunk revisions 1.3, 1.4, 2.1, 2.2, 2.3, 3.1, 3.2.
Then:
cvs update -j 1 {optional files}
will merge the changes from 1.2 to 1.4
cvs update -j 2 {optional files}
will merge the changes from 1.2 to 2.3
cvs update -j 3 {optional files}
will merge the changes from 1.2 to 3.2, which in this example, is
equivalent to the use of "-j HEAD" in part A above.
The intuitive (at least to me):
cvs up -j MAIN (or TRUNK) {optional files}
doesn't work. If the trunk (i.e. "main branch") had an implicit branch
named "MAIN", you could use:
cvs up -j MAIN:10/26 -j MAIN:now {optional files}
and refer to date-stamped revisions on the trunk using the
: support that works on other branches.
You might also think you could place an explicit tag on branch 1 (or
higher) (e.g. MAINHACK:1) and use it in place of the implicit "MAIN",
but I haven't found the right combination.
[[If you find working techniques, I'll add them here.]]
Last modified: _6/13/1997_
8. How do I merge onto the Main Branch a file that exists only on a branch
other than the Main Branch? (i.e. it is in the Attic)
For how such a file can exist, see 3A.2 and 3A.3.
For how to avoid creating such a file, see 3A.5.
Though you might think that the "update -j" command could perform the
"merge" of a file from the side branch to the Main Branch, it isn't
(yet) smart enough. Unfortunately, there is no single CVS command to
do this -- it takes three steps:
To move something onto the Main Branch from the Attic, you have to
physically move the file from the Attic to the main Repository
directory associated with your working directory.
It is exactly like resurrecting a removed file. See 3L.4
I use something like this: (csh-like syntax)
set repos = `cat ./CVS/Repository` mv $repos/Attic/filename,v
$repos/filename,v
(If you use relative paths in your Repository files, that first line
becomes: set repos = $CVSROOT/`cat ./CVS/Repository`)
Now that the file is physically in the right place within the
Repository, "update -A" will make it appear in your working directory
on the Main Branch. Do that now.
You now have a choice. The act of physically moving the file has
fused together the branch and the Main Branch for this
file. You can continue that way, making changes along the RCS Main
Branch which CVS will (for this type of file only) treat as both the
Main Branch and the branch.
The other choice, which I would suggest, is to re-tag the file with
, restoring a normal-looking magic branch tag to the file:
cvs tag -F -b
After you have done the above, you can run "update -A" or "update -r
" to resume whatever you were doing before you started
this procedure.
Caveat: The final result is a file whose revision tree doesn't look
like it was ever on any branch but the Main Branch until the above
"tag -F -b" command was executed. CVS and RCS have no way of saving
the history of the actions you have just performed.
Last modified: _6/13/1997_
9. How do I know what branch I'm (working) on?
Type:
cvs status
and look at the "Sticky Tag" field for each file. If:
The *same* tag is on *every* file in your working tree, *and*
That tag matches the contents of the ./CVS/Tag file, *and*
That tag is a branch tag,
then you know what branch you are working on. You can get sticky Tag
information directly from the ./CVS/Entries file instead of "cvs
status".
If all the sticky Tags don't agree, then your directory is temporarily
inconsistent. This is a feature allowing you to make changes (or
perform merges) to individual files on multiple branches without
checking out the whole directory.
The sticky Tag on each file in the ./CVS/Entries file (as displayed by
the "status" command) indicates what branch the working file is on.
New files are added to the Tag stored in ./CVS/Tag.
To force your entire working directory onto the same branch, type:
cvs update -r
Last modified: _6/13/1997_
10. Do I really have to know the name of the branch I'm working on?
If a developer can't be relied on to know what branch of development
to work on, then either the developer's manager isn't planning
branches properly or the developer has serious problems.
I have found that one of the hardest concepts to get across to
developers (and some managers) is that "a branch in development" (as
opposed to the use of RCS branches to support some other scheme) is a
heavyweight act. Every time you create a real branch in development,
you must spawn a set of managerial procedures and a schedule by which
you plan to merge each branch into each other branch. Unless you plan
to keep it simple and collapse (by merging and forgetting) branches
quickly, they are not to be created lightly.
In other words, if you don't regularly attend group meetings in which
the branch to be worked on is a major topic of discussion, then the
group is not managing branches properly.
We created a couple major branches a few months ago and even the
customer service people refer to the "XYZ branch" as a shorthand for
"continuing development on the XYZ project".
Last modified: _6/13/1997_
11. How do I refer to the revision where I branched so I can see what
changed since the Branch Point on another branch?
Given the current format, there is no direct way to refer
to the branch point, which is more useful in many ways than referring
to the branch, which always refers to the latest revision on the
branch.
When CVS adds a branch tag, it attaches an RCS symbol to a
non-existent revision number containing the revision number of the
branch point as a prefix. (See Section 3O, on the "tag" command.) RCS
can't use the CVS magic branch tag and many of the CVS commands can't
refer to it.
To be certain of your ability to refer to a branch point, you must
create a "branch point" tag at the same time as the Branch tag. See
4C.3.
Last modified: _6/13/1997_
12. Why didn't the command "cvs admin -bBRANCH1 *" create a branch?
Because your command creates an RCS branch, not a CVS branch. See the
above discussion on branches. RCS branches are used to support CVS
branches, but they are not the same. You can't act as if you have
direct control over the RCS files.
The "admin" command was placed there as a convenience to allow you to
execute raw "rcs" commands on the Repository, taking advantage of
CVS's ability to find the files in the Repository.
But you have to remember that you are using RCS commands on a CVS
Repository, which is not generally safe unless you know exactly what
CVS depends on.
For one thing, CVS insists on control of the default branch. It is set
either to the Main branch or the Vendor branch depending on whether
you have changed the Vendor's code. If you change the default branch,
you are monkeying with the internals and you will get unexpected
results.
To set your "default CVS branch" to BRANCH1, you must use "checkout"
or "update" with the "-r BRANCH1" option. Then you have changed CVS's
idea of your "default branch", which has little to do with RCS's
default branch.
Last modified: _6/13/1997_
13. Is it possible to set the "default CVS branch" for everyone?
No. It doesn't work that way.
When using CVS, all administrative information (such as what branch
you checked out) is stored in CVS sub-directories, local to the user.
There is no global state, other than the description and logging files
in the $CVSROOT/CVSROOT directory.
You tell "checkout" or "update" what branch you want to check out via
the "-r " option. The default is CVS's "Main Branch".
I don't see a problem in *designing* a new way to indicate what branch
you get by default, instead of the main one, but that's not how it
currently works.
Last modified: _6/13/1997_
14. How do I perform a large merge?
Large merges require a bit more planning to be able to track what has
happened in the inevitable cases where something goes wrong. No tool
can force a "merge" to make perfect sense.
Though you can handle the details in many different ways, the two ends
of the spectrum of merge techniques are: gonzo and paranoid.
The gonzo method assumes that you know everything about your sources
so that recovery from failures is "just a matter of typing." You
created the branch this way:
cvs checkout
cd
cvs tag -b
cvs update -r
>>> Edit away.
cvs commit <<== Onto branch
Now you want to merge your branch back into the Main branch, you are
certain you can make it work, or at least detect all the failures, so
you dive in and hack away: (For simplicity, we will assume you are
collapsing (i.e. merging and forgetting) a side-branch into the Main
branch from your single working directory.)
cvs update -A
cvs update -j
>>> Edit the 'C' files and remove the overlaps.
>>> Edit some more to make it all compile and work.
cvs commit
Looks simple. For more details on the output from the "update -j"
command, see 3P.2 and 4C.6.
Note: You could also checkout a whole new working directory and
perform the merge at the same time by replacing the two
update commands with these two commands:
cvs checkout -j
cd
The paranoid way is more difficult, but it can catch all sorts of
problems. You created the branch this way:
cvs checkout
cd
cvs tag
cvs tag -b
cvs update -r
>>> Edit away.
cvs commit <<== Onto branch
The extra tag command places a non-branch tag on the Branch Point, an
act that makes it easier to do "diffs" later. Now we decide to perform
the merge:
cvs tag
cvs update -A
*1* cvs diff -r -r
>>> *1* shows all the changes on the branch.
*2* cvs diff -r -r HEAD
>>> *2* shows the changes on the trunk since branching.
cvs tag
cvs update -j
>>> Edit the 'C' files and remove the overlaps.
*3* cvs diff
>>> Verify that *3* matches *1*, except for line numbers.
cvs commit
cvs tag
>>> Edit some more to make it all compile and work.
cvs commit
cvs tag
The reason *3* and *1* match so closely is that they are the
differences between two pairs of starting points and ending points
after the same data was inserted. If they are significantly different,
you will want to figure out why.
NOTE: You will have to tell everyone to stay the hell out of the
Repository while you do this. If they commit something while you are
in the middle of a merge, your job will be much more difficult. If
they "update" at the wrong time, their work will be randomized until
you finish. It's better to call a halt.
See 3H.13 for some more information about dealing with merges after
import. The last part of the procedure is applicable to any large
merge.
Last modified: _6/13/1997_
15. Is a Vendor merge any different from a branch merge?
No. In most ways, a Vendor branch is exactly the same as any other
branch. In a Vendor merge, the data is append to the branch by the
"import" command, rather than by hand-editing, but the merge process
is the same.
See the "import" command in section 3H.
Last modified: _6/13/1997_
16. How do I go back to a previous version of the code on a branch?
You can avoid digging into RCS revision numbers (executing "update
-r (rev)" on each file) by trying one of these:
Use non-branch tags as you normally would. Non-branch tags
attach to specific revisions, so a "tag (tag)" command would
mark the revisions you have in your working directory, which
are on your branch. If you need to retrieve them, use "update
-r (non-branch-tag)"
Doing this overrides the sticky (branch-tag) attached to your
working directory with a non-branch tag, which means you won't
be able to commit until you again move forward to the end of
the branch with "update -r (branch-tag)".
Use the "update -r (branch-tag):(date)" trick.
This is almost like using the '-D' option, but it looks for
revisions extant on (date) only along the given branch.
As in #1, you can't commit to this kind of working area,
because it has a sticky date referring to revisions in the
middle of a branch.
[comment from the audience: You are dreaming..
this does not work.. try it, you get
No such tag: "MYTAG:May 1"
or similar. I wish it did because I need it. julian@whistle.com]
You can branch a branch.
If you add a branch tag to file in a working directory that was
checked out on a branch, you will branch the branch. This
works just fine, though you'll have to play some games to merge
everything back together again. You'll also create 6-part
revision numbers. (They'll be 8-part revision numbers if you
branch a branch that started out with some unmodified files on
the Vendor branch. Think about it. How does revision
1.2.4.2.4.2.2.1 grab you?)
(fixed formatting, kingdon@cyclic.com)
Last modified: _9/8/1997_
17. Once I've found the files I want, how do I start changing them? I keep
getting warnings about sticky tags.
What you probably did was type "cvs update -r " where is a
non-branch tag. "update" created a sticky tag for a specific revision,
not a branch. To start working right there, you have to create a
branch to work on.
You have two choices.
You can do it in place and keep working:
cvs tag -b <<== To tag the current files.
cvs update -r <<== To move onto the branch.
You can do it "externally" and create a new working directory:
cvs rtag -b -r
cvs checkout -r
can be a relative path within the Repository.
in the above is the non-branch tag you placed earlier
that caused the error in your question. Be warned that
if is not set on all the files (or all the right
revisions) you won't get exactly what you wanted.
Last modified: _6/13/1997_
18. Why do I get the latest files on the branch when I tried to "update -r
"?
If "update -r " always retrieves the latest files on a branch,
then is really a . A branch tag is supposed to be
used to grab a branch to work on. Since you can't modify a file in the
middle of a branch, checking out a will give you the
latest revision on the branch.
If you want to "checkout" a specific collection of revisions, you must
use a "non-branch" tag. See the first part of 4C.16.
Last modified: _6/13/1997_
19. How can I avoid a merge? I just want to move the latest revision on my
working branch directly onto the trunk.
There is no direct way to do this using CVS, though the technique is
not difficult using shell commands. Here's one way:
Move your working directory to the Main Branch.
cvs update -A
Use "update -p" to grab the latest revision on the branch and write
it over your working files. Make sure you don't have an modified files
-- you will lose them. The following is in "csh" syntax. Change the
wildcard to grab the files you want
foreach i (Makefile *.cc *.hh)
cvs update -p -r $i > $i
end
Commit all the working files onto the Main Branch.
cvs commit -m 'Moved branch onto MAIN'
You should experiment with the above before blasting everything.
Last modified: _6/13/1997_
20. How to I avoid merge collisions in the RCS $\Log$ data?
In short, you can't. The RCS $\Log$ keyword is handled differently
from all other RCS keywords.
On the info-cvs mailing list, there is a periodic discussion that goes
something like this:
Question: How do I deal with $\Log$? Answer1: You can't do much with
it. Here's how it works. . . Answer2: I've found a limited way to use
it. . . Answer3: Get rid of it. $\Log$ is an abomination.
I tend to lean toward answer #3. There are only two sets of people who
would ever have access to logs stored within sources files, developers
and source customers.
For developers:
Log entries within sources files are notoriously incomplete, rushed,
poorly phrased and in many cases incorrect, making them useless for
debugging or file maintenance. I remember a maxim from "Software
Tools" (I believe): "Read the code, not the comments." No managerial
order or plan for programmer discipline will affect this in the real
world.
Log entries are usually in an unreadable mixture of styles. Many log
entries are just plain meaningless. Some are foolish. Some are even
insulting. Examples:
"Corrected spelling of misspelling." "Bug fix." "Reversed stupid
change in previous revisions." "If Joe could do his job, this would
already have worked."
Log entries are not managed well by the tools. Any merge can cause
conflicts in the $\Log$ data. Branch merges produce incomplete logs.
They can be edited into chaos and they are not regenerated. They waste
space duplicating information available to the developer with a single
command.
Even if correct when originally entered, as changes are made to the
file, log entries become false over time. Humans are not good at
reading down through a list and remembering only the last change
affecting something. Over time *most* of the log is wrong.
Even if still correct, the log data is almost useless to developers
without the code diffs. If you can get code diffs, you can display the
log.
For source customers the problem is even worse. The last thing you
want to show customers is a hodge-podge of tiny comments about large
changes followed by a series of emergency fixes before delivery. If
you distribute sources, then you should provide documentation, or
changelogs reviewed by people who won't let comments like "Fixed for
stupid customer." out the door.
Conclusion: Though some people would prefer to see in this FAQ
techniques for making the $\Log$ entries the best they can be, I
believe them to be a lost cause. My suggestion is to hunt down, root
out and destroy all occurrences of $\Log$ and the unusable data
attached to it wherever you may find it.
Last modified: _6/13/1997_
21. Why should I trust automatic merges?
Some developers have the feeling that three-way merging doesn't work.
They fear and distrust the way the "update" command automatically
merges committed changes from the Repository into the working file.
Experience has shown that most merges are utterly painless and most of
the rest are easily resolved. The few conflicts that cause headaches
are nearly all due to poor communication between developers, a problem
no source control system can obviate.
Some developers were troubled in the past by flaky Unix software. I
can't say that everything is perfect, but the tools CVS depends on
(RCS and diff, mainly) are fairly solid nowadays. They work.
Since it does seem to work for most of us, the algorithm is unlikely
to change soon. Why not test it on a couple trouble spots and if it
works for you, use it for a while? Then you can make an informed
decision.
Last modified: _6/13/1997_
22. How does CVS decide if it can safely perform a merge?
CVS can merge any text file, possibly discovering a conflict and
leaving overlaps for you to edit. Editing the conflict markers out of
the file is a moment's work, but resolving the conflict could take an
arbitrary amount of time. CVS works to determine if it *should* merge,
not if it *can*.
See 2B.6 for how the merge proceeds.
Last modified: _6/13/1997_
23. After resolving merge conflicts in a file, what if I want to keep my
previous version, and not take any of the branch changes?
If you want to retain your previous version, a version on the MAIN
branch greater than 1.1 (one you committed there), just throw the
merged file away and "cvs update" the file.
You don't need to commit something to remember it. The tags you place
before and after the merge should give all the handles you need to
find various versions. You don't have to create a new version of the
file.
If you want to retain the previous Vendor revision, you can grab a
copy of it using "cvs update -p" and commit it or use the technique
described in 3B.3 to revert back to the Vendor branch.
Last modified: _6/13/1997_
Category: /Advanced_Topics_/Engineering/
" + Engineering"
1. Where can I find out about Software Engineering?
A couple different people suggested this book:
Software Configuration Management: Coordination for Team Productivity;
Wayne A. Babich; Addison Wesley; 1986; ISBN 0-201-10161-0
A number of others suggested Appendix B of the book "Decline and Fall
of the American Programmer" by Ed Yourdon, called "The Programmer's
Bookshelf". It list 87 books you are expected to have read. Since they
publish many of the books, Prentice-Hall distributes this list as
"Prentice Hall Professional Technical reference PTR-125-AA3.
One interesting item from the Yourdon book: The total number of
professional computer books sold is less than the number of
programmers currently in the United States. It wasn't clear from the
book whether this meant "per year" or not, but it is still
frightening.
Last modified: _6/13/1997_
2. How do I flexibly arrange the modules file to describe my sources?
An equivalent question might be, "How do I structure my sources?" This
can be a difficult question especially in the areas that are more
political than technical.
Generally you want to think about which pieces of your system need to
be checked out together, built as one system or tagged as a consistent
whole. You should certainly create module names that correspond to
complete, buildable collections that you would tag and release as one
"product". It is also convenient to create module names for small
sections of the Repository containing files that will all be worked on
at the same time by the same person or group.
Once you have defined the structure of your work, you can usually see
how to lay it out in a Repository. After that the modules file is
easy. You set up module names and aliases to match what you need to
check out by name. If you like relative directories, it is possible,
but not recommended, to work completely without a modules file. See
1D.11 and 2C.7 for some info about the modules file.
Here are a few types of modules. You should experiment to see what
kind of structure each of these produces. They all have different
uses.
Connected projects in one group with two separate helper
directories. The helper directories can contain build tools, header
files, libraries, or whatever you like.
These are all aliases that checkout relative pathnames. The equivalent
results could be produced by placing the selected relative pathnames
on the "cvs checkout" command line.
pr1 -a P1 HELPERS
pr2 -a P2 HELPERS
pr3 -a P3 HELPERS
pr12 -a P1 P2 HELPERS
pr13 -a P1 P3 HELPERS
pr23 -a P2 P3 HELPERS
P1 -a group1/proj1
P2 -a group1/proj2
P3 -a group1/proj3
HELPERS -a group1/helper1 group1/helper2 MAKEFILE
MAKEFILE -a group1/Makefile
Actual Repository directory structure: (from $CVSROOT down)
group1/ Makefile The top level Makefile. helper1/ helper2/ Helper
files and dirs proj1/ Files and dirs proj2/ Files and dirs proj3/
Files and dirs
"checkout group1" produces a duplicate of the above. "checkout projX"
produces all but "projY" and "projZ". "checkout projXY" produces all
but "projZ".
Here is the exact same set of module names describing the same
Repository layout using module names (and aliases containing module
names) instead of merely aliases for relative pathnames.
There is one difference in the result. The name of the top level
directory in the checked out working tree will match the "module" name
(e.g. pr1) instead of always being "group1" as it was in the first
example above.
pr1 group1 proj1 &HELPERS
pr2 group1 proj2 &HELPERS
pr3 group1 proj3 &HELPERS
pr12 group1 proj1 proj2 &HELPERS
pr13 group1 proj1 proj3 &HELPERS
pr23 group1 proj2 proj3 &HELPERS
HELPERS -a helper1 helper2 group1-Makefile
helper1 group1/helper1
helper2 group1/helper2
group1-Makefile -d . group1 Makefile
The above line (with the -d in it) says that when the module named
"group1-Makefile" is checked out, the file named Makefile file will be
found in a directory named $CVSROOT/group1 and will be checked out
into a directory named '.', which obviously already exists.
The & references say to interpret those pathnames relative to the
directory where the whole module is stored. For the "pr1" module, that
directory is "group1", so the &HELPERS reference winds up placing
Makefile in '.' relative to "group1".
A short one containing the basic "module" actions:
m1 head/path file1 dir2 file3 dir4 file5
When checked out, a directory named "m1" appears in your current
directory. Elements named file1, dir2, file3, dir4, and file5 appear
in it. They were originally taken as relative paths from
$CVSROOT/head/path.
Here's another way to construct a working directory out of pieces of
the Repository:
projX projX Makefile &projX_inc &projX_src &projX_doc
# The first line selects a single file within projX, plus
# the contents of three other modules. Those three other
# modules rename their directories.
projX_inc -d include projX/inc projX_src -d source projX/src projX_doc
-d documentation projX/doc
A Unix tree. This is similar to what CVS was developed for and the
way I have used it for years.
# Top level
unix unix
u_bin unix/bin
u_etc unix/etc
u_man unix/man
usr-bin unix/usr.bin
# Subdirs of top level dirs. (tiny subset)
ls unix/bin/ls
fsck unix/etc/fsck
man8 unix/man/man8
# Programs without subdirs. (tiny subset)
cat unix/bin Makefile cat.c
uniq unix/usr.bin Makefile uniq.c
# /usr/local/src
localsrc localsrc
gnu localsrc/gnu
public localsrc/public
X11 localsrc/X11
# GNU and PD tools
cvs localsrc/gnu/cvs
emacs localsrc/gnu/emacs
rcs localsrc/gnu/rcs
btoa localsrc/public/btoa
tcsh localsrc/public/tcsh
# X11 related items.
tvtwm localsrc/X11/contrib/tvtwm
"unix" was checked out and built from the top down, using a set of
Makefiles that knew about the whole structure. "localsrc" was kept
checked out in /usr/local/src.
At any time I could run "checkout ls" or "checkout cat" and get a
simple directory with only that tool in it, plus a subset Makefile
that knew how to build that tool against the installed (or alternate,
via environment variables) headers and libraries.
I found it very handy to be able to run "ls" and see the three tools I
was porting that week.
Last modified: _6/13/1997_
3. Can I have multiple source repositories, one for each project?
Yes, you can have as many Repositories as you like. But each
Repository must be managed separately, creating additional work.
Question 4A.1 provides a short description of setting up a single
Repository. A few additional considerations:
It is a good idea to start by creating a single Repository and split
it up (or create additional Repositories) only if you believe it is
really necessary. I would only create a new Repository if the data is
completely disconnected from the rest of the main Repository.
If there is a lot of overlap among the developers working on the
collections of files you want to place in different Repositories, or
if there is any connection between those collections, I would go out
of my way to create a single Repository. It is much easier to manage.
Disk space should not be a factor since you can build up a
Repository using symbolic links and/or remote mounts.
Each Repository is completely distinct. You can't check out modules
from different Repositories at the same time. A better way of looking
at it is that if you *can* check out two modules or directories with a
single "checkout" command (without contortions or explicit absolute
pathnames), then they are in the same Repository.
To "checkout" modules from multiple Repositories, you must use the
"cvs -d" option on all CVS commands or alter your $CVSROOT variable
when you change focus to another Repository. If you work with multiple
Repositories, it is a good idea to configure CVS to use absolute
pathnames in the ./CVS/Repository file, since most commands (other
than "checkout") will use that file rather than $CVSROOT.
If you configure CVS to use relative pathnames in your
./CVS/Repository files, you must always be careful to set your
$CVSROOT properly or you will get unexpected results.
If you have two modules or directories by the same name at the same
relative path inside two different Repositories, you are asking for
disaster. You could unexpectedly update a directory with completely
unrelated files. This is not a fanciful example -- a Repository is
occasionally duplicated for release purposes in which case *all* the
paths in the two Repositories are the same.
Last modified: _6/13/1997_
4. Who should administer the Repository and manage the modules file?
This is a "management style" question. In large or traditional groups,
the CVS procedures are warped to conform to local conventions. In
small groups, in groups with strong personalities or on new projects
the choice of source control procedures can help create some of the
working environment. Here is a taxonomy of environments I have worked
in or helped set up:
Situation 1.
A small number of competent developers working on a medium size
project. We all got along and we all respected each other (at least
technically). Anyone edited anything.
Modules and Repository admin was mostly left to me. I never found a
problem in minor changes made by anyone else.
Situation 2.
A large number of experienced developers sprinkled with wackos. Many
of the developers didn't want to deal with any kind of source control.
They wanted a full-service source control system that caused them zero
thought.
I learned "big stick" diplomacy here. There was a small number of
"designated" (by me) people who were allowed to do *anything* other
than "update" and "commit". Even "checkouts" were controlled. This is
where I found "history" and "release" the most useful.
Situation 3.
A small number of developers who wanted me to "help", but who didn't
want to deal with anything other than their favorite algorithms.
I didn't have the time to baby-sit this group, so I designated one of
them to be my official contact and made him do it all. He felt sullied
by the requirement to pay attention to anything other than his pet
coding projects, but enjoyed the "status" of being the only one who
could touch the control files without my kicking the chair out from
under him.
Situation 4.
A huge number of developers of covering the whole spectrum of
competence and experience split into 20 groups, none of which
cooperated with the others, working on 57 different projects, most of
which didn't inter-operate.
Managing it in any coherent way was not my responsibility (and beyond
my tolerance for chaos). Too many people. So I privately designated a
person in each group to be the contact and kept watch on the
Repository activity. When something went wrong, I notified the contact
for the group and told him what was happening and *he* kept his troops
in line. They were tougher with their own group that I would have
been.
Eventually only a few people were willing to touch the control files,
since they were flamed from all directions if they screwed up.
Situation 5.
In a medium group of really *serious*, and seriously overworked,
people, someone else was designated the "master". I convinced the
master I knew what I was doing and went on my way.
No one else in the world was allowed to touch anything.
Situation 6.
In a large amorphous group of beginners, experts and clowns, over whom
no one had official control, I was forced to employ a group of
relative beginners (who became experts rather quickly) to police the
world. The ultimate in locking the barn after the horse was stolen, we
kept Chaos from destroying us only by use of superior firepower.
My choice, if allowed, is to let anyone touch anything. I keep backups
of important items and let people know individually whether I want
them to touch things or not. If someone on my "no touch" list touches
and succeeds, they are allowed more slack. If they screw up after
being warned, their screwup becomes public. After a few months, I
usually have no trouble keeping the world running smoothly, at least
from my (and CVS's) perspective.
Last modified: _6/13/1997_
5. Isn't disk space a big factor? CVS copies files out of the Repository,
duplicating everything.
Everyone knows that disk space is getting cheaper. How do we reconcile
this with the equally well-known problem that *all* disk is *always*
filled up?
In my opinion, the main reason disk space will never be an unlimited
resource is that it is the major variable in organizational time/space
tradeoffs. It isn't a problem of waste or an aspect of Murphy's law,
as some claim it is, but rather a direct consequence of good
management. Disk space is, and will always be, a limited resource.
First, the cost of *deploying* that disk is not dropping as fast as
the cost of the storage medium. The cost of machines to hold the disks
and the networks to connect them are dropping more slowly than disk
media. And the cost of the human time necessary to manage the
machines, networks, disks, and the developers using them, is not
dropping at all. The cost of human time continues to rise.
If management decides that expensive human time can be saved by using
all that new disk space to keep the last three releases online, then
that's what it will be used for. If each release takes up a Gigabyte
and you support 30 platforms, a simple time-saving suggestion has just
grabbed 100 Gigabytes of disk space. And we've ignored the potential
disk storage needed to support "better Customer Service", another
management refrain.
Even at 30 cents per Megabyte (next year's price), you've just used up
$30,000 of disk space. And that doesn't count the computers, tape
drives and humans necessary to maintain and deploy all of it. Spending
money to save time has its own overhead, too.
Binaries are getting bigger. Graphics and data collection devices can
eat up any amount of disk. There are more tools available, more
libraries, more raw data than you can ever store. My home computer has
a Gigabyte of disk on it. It could easily handle 30.
The "economy" of disk storage media will never remove the need to
manage disk space.
So, here's an un-reviewed suggestion originally from Graydon Dodson
, which I've altered and edited heavily.
- Keep a directory where the whole tree is checked out. (It might be
built and tested once in a while to make sure it is worth linking to,
but that doesn't affect the source control aspect of this procedure).
Let's call it /master/build.
- Write a tool that creates a tree of directories (like the X11
"lndir" command) filled with links to the checked out files in the
/master/build tree.
This tool should also provide real copies of, not symlinks to, all the
files within the CVS administrative directories.
- You could also provide a way for the tool to take a list of whole
directories that you will never change, for which it would create a
single symlink to the directory and not a subtree of symlinks to
files. Or you could rm -r pieces of the resulting working directory
yourself and replace it with links.
- If you want to edit a file, you have to grab a real copy and keep it
until your revision shows up in the /master/build tree. I'd create a
script to do this: cvsgrab
#!/bin/csh -f
set f = $1
if (! -l $f) then
echo "file $f is not a symlink"
exit 1
endif
rm $f
set rev = `grep "^/$f/" CVS/Entries | awk -F/ '{print $3}'`
cvs update -p -r $rev $f > $f
You can't do a plain "cvs update" since that would grab newer
revisions from the Repository, not the revision you wanted to start
with. After the file is no longer a symlink, you can work normally.
You'll have to run "update" before "commit" anyway if there are newer
revisions.
- Presumably there would also be a tool to traverse the link tree and
revert it to links if there are no modified files and/or if all the
real files match the revision of the /master/build tree.
- To avoid confusing CVS when the /master/build revisions are updated
but your CVS/Entries files is not, CVS would have to change to handle
symlinks. It currently causes problems with this scenario:
./ is a symlink.
./CVS/Entries says you are revision 1.2.
The corresponding CVS/Entries file in /master/build says the latest
revision is 1.3.
cvs update shows a 'C' conflict flag.
Last modified: _6/13/1997_
Category: /Advanced_Topics_/Installing_CVS/
" + Installing CVS"
1. What do I have to do before I install CVS?
You must decide where to set up a Repository.
Though you can construct a Repository tree structure using links and
mount points, there must be a single copy of each real file across
your entire organization. You may not "rdist" files and expect to edit
both copies.
CVS does not support a truly distributed Repository. You can have
multiple Repositories, but each one must be mounted (not copied or
"rdist"ed) from a single place onto all machines where it will be
used.
Initially, a Repository takes about same amount of disk space as the
sources you want to put into it, plus a bit of overhead for the RCS
files.
See Section 4B. For multiple Repositories, see 4G.3
You need a directory in everyone's $PATH variable where you can
install all the executables. /usr/local/bin is a common place.
You need some helper tools besides CVS such as "RCS" and a good set
of "diff" and "diff3" programs. See 1B.4 for suggestions.
Read the README, INSTALL and ChangeLog files to see what you are
getting into.
Though you can probably muddle along without it, you should appoint
one or more "Repository Administrators" who will be responsible for
maintaining the Repository structure, administrative files and the
"modules" interface.
Someone at your site should probably be on the info-cvs mailing list.
See 1B.5.
Last modified: _6/13/1997_
2. How do I configure the CVS programs?
You should certainly start by reading the README file, the INSTALL
files and possibly the ChangeLogs in each directory, the Makefile.in
files and the "cvsinit.sh" program.
Execute the ./configure command.
Type "make".
After running "make" you might try running the "sanity.sh" script:
./src/sanity.sh `pwd`/src/cvs
It writes into /tmp/cvs-sanity by default.
Finish reading the INSTALL file and test out the system.
Last modified: _6/13/1997_
3. What do I have to install?
Install the "cvs" executable and "mkmodules" from the CVS sources.
The man page is useful too. If you plan to report bugs, you should
also install "cvsbug".
Set your $CVSROOT environment variable and create the Repository
(which you planned out in 4A.1) with the "cvsinit" command at the top
of the CVS sources.
You'll need to edit the Repository control files created by
"cvsinit".
Install any helper programs mentioned in the modules file.
Last modified: _6/13/1997_
4. How do I work around the merge problems in GNU diff version 2.1 or
later?
See 1B.4 If you use recent versions of RCS and "diff", you won't run
into the above. If you do, see 5B.8
Last modified: _6/13/1997_
Category: /Advanced_Topics_/Internal_errors/
" + Internal errors"
1. Explain: "ci error: unexpected EOF in diff output"
RCS versions earlier than 5.5 print the above error when a file does
not end in a newline character. It can be caused by:
- Editing with Emacs and not using "require-final-newline".
- Committing a binary file.
- Filesystem failures (NFS!) that put nulls in your file.
The solution is to upgrade to RCS 5.5 or later. (Of course, this won't
fix filesystem failures. It will merely allow RCS (and therefore CVS)
to handle the file without error.)
Last modified: _6/13/1997_
2. Explain: "RCS file /Repository/module/file.c,v is in use"
This is an RCS error that occurs when its internal lock file has been
left around by an RCS command interrupted by some sort of system
crash, disk failure or SIGKILL signal.
Go into the Repository and look for files with names similar to
"file.c,v", usually starting with ',', '_' or '#'. Make sure they are
really crash remnants and do not belong to transactions in progress --
a recent last-modified timestamp is a good indicator of a live
transaction. Delete them if they are old.
Last modified: _6/13/1997_
3. Explain: "co error, line 2: Missing access list"
This is an error message from RCS Version 3 when it tries to read a
file created by a later version of RCS.
HP decided to "standardize" on an ancient version of RCS some time
ago. You can't use it for CVS. See 4H.6.
Since the error comes from having a later version of RCS than HP
supports, you probably did install the later version but must have
recently changed your $PATH or installed the HP package that has RCS
in it.
You should either reconfigure CVS to use absolute pathnames to the
proper versions of the RCS programs that CVS uses, or change your PATH
to look there first. If you haven't installed the latest version of
RCS, you should upgrade. See 1B.4
Last modified: _6/13/1997_
4. Explain: "error: RCS file name `xyz .c' contains white space"
RCS 5.6 doesn't allow white space in filenames. Apparently this
restriction will be removed in RCS 5.7, but CVS may still require that
filenames have no white space in them.
Last modified: _6/13/1997_
5. Explain: cvs checkout: warning: is not (any longer) pertinent
This message occurs in three instances:
When there is an entry in the ./CVS/Entries for file and there
is no RCS file in the Repository to back it up.
If the working file exists, and hasn't changed (determined from the
timestamp) it is removed.
When you try to check out a piece of the Repository with:
cvs checkout some/place/in/repository/tree
and at least the first element of the path (i.e. "some" in the above)
exists, but some part of the rest of it does not.
The checkout command checks the modules file first for the whole path,
then for a prefix of the path as a module name. If it doesn't find
*any* portion of your path in the modules file, it says:
cvs checkout: cannot find module `' - ignored
If it finds some set of prefix directories, it prints the message you
see.
In practice this is usually a spelling error.
If the Repository files you are trying to check out or update are
not readable by you, the same problems can occur. Check the
permissions on the files involved.
Last modified: _6/13/1997_
6. Why did a Repository file change from ,v to ,,?
This is an RCS problem, since the ,, syntax for file names is
used by RCS and not CVS.
RCS constructs a new ,v in a temporary file named ,,
(which doubles as a lock file) then renames it to ,v when it is
done. The only way this is reliable is if your system's version of
rename(2) is an atomic, as required by POSIX.
If your system has a non-atomic (and therefore non-POSIX) rename(2)
system call, RCS runs uses an internal version of this algorithm to
approximate the atomic rename:
rm ,v; ln ,, ,v; rm ,,
If the system crashes, or you lose your NFS connection between the
first "rm", but before the "ln", you can be left only with the
,, file. If the crash or network failure occurs between the "ln"
and the final "rm", you could be left with a pair of linked names.
Recovery:
- If only the ,, exists, rename it to ,v.
- If both ,, and ,v exist and are linked, remove the
,, file.
- If both ,, and ,v exist and are separate files, look at
the dates, "diff" them and make your best guess. This sounds like the
remnants of two separate events.
Last modified: _6/13/1997_
Category: /Advanced_Topics_/Other_Systems/
" + Other Systems"
1. I use a NeXT. Is there anything I need to know?
NeXTSTEP 3.0's Interface Builder uses "nib" directories, rather than
the files used in previous revisions. It removes files it doesn't
recognize, making it impossible to place such a directory under CVS --
the CVS admin directory will be removed.
Some time ago, posted a palette named CVSPalette
that claimed to resolve this problem. It was intended to preserve the
CVS administrative directories within nib documents (directories) that
Interface Builder usually removes.
CVSPalette is no longer in its announced place:
ftp.cs.orst.edu:/pub/next/submissions
though I did find two other interesting files on ftp.cs.orst.edu:
/software/NeXT/sources/tools/cvs-next-2_1_1.tar.Z
which is a port of CVS 1.3 (along with RCS and diff) and:
/software/NeXT/sources/programming/cvs.postamble-2.4.gz
which appears to be a set of wrappers for CVS commands that claim to
allow you to use CVS effectively (and without need for the "command
line") on a NeXT machine.
[[Anyone know the truth about CVS and NeXT?]]
Last modified: _6/13/1997_
2. I use OS/2 and/or DOS and/or Windows. Is there anything I need to know?
When using a local repository, be sure to specify the local access
method or CVS will interpret the drive letter as a remote host name
due to the : following it:
WRONG: CVSROOT=C:\SRC\CVSROOT
RIGHT: CVSROOT=:local:C:\SRC\CVSROOT
(larry.jones@sdrc.com)
You can share RCS files between Unix and DOS while avoiding the MS-DOS
file name limits by setting your RCSINIT environment variable to
'-x/,v'. New RCS files will be created without the standard ",v"
suffix, though files ending in ",v" will still be found if there is no
matching file in the same directory without the ",v".
Erik van Linstee offers an OS/2 and a DOS port of CVS 1.3 in:
ftp.informatik.tu-muenchen.de:/pub/comp/os/os2/gnu/devtools or
ftp.rrzn.uni-hannover.de:/pub/os2-local
The files are named:
cvs13p?[bs].zip
Where the ? stands for the patch level (currently 8) and the b is for
the binaries, the s for the sources.
There are three binaries. An OS/2 only one (32-bit), a DOS only one
(16-bit) and an EMX one that runs on both (32-bit).
There are many differences between the Unix and the DOS versions of
CVS. Read the material that comes with the DOS version before using
it.
[[Updates?]].
Last modified: _9/22/1997_
3. I use SCO Unix. Is there anything I need to know?
On SCO/UNIX 3.2 V2.0 POSIX signals don't work. Unfortunately the
configure program detects POSIXness and configures in the use of POSIX
signals. Workaround : Edit out the check for POSIXness in the
configure script. [[You could also remove all occurrences of
"-DPOSIX=1" from the Makefiles after configure is run. -dgg-]]
SCO/UNIX doesn't understand #!/ syntax. This breaks the
use of log.pl as it gets invoked by /bin/sh instead of
!#/usr/local/bin/perl. WorkAround : edit log.pl and change it into a
shell script which invokes perl with log.perl (renamed from log.pl) as
input.
Contributed by Joe Drumgoole
Last modified: _6/13/1997_
4. I use AIX. Is there anything I need to know?
The only report on AIX claims to have no trouble using it in concert
with SunOS and IRIX platforms.
Last modified: _6/13/1997_
5. I use IRIX. Is there anything I need to know?
If you see "uid" numbers where you would expect user names, try adding
-lsun to the link line. Without it CVS is unable to retrieve "passwd"
data through NIS.
Last modified: _6/13/1997_
6. I use an HP system. Is there anything I need to know?
HP distributes RCS version 3 (a circa 1983 release!) with HP-UX. CVS
does not work with RCS version 3; it requires RCS version 4 or later.
Your best bet is to find the latest version of RCS and install it
somewhere.
HP-UX 8.07 has a serious bug with the mmap system call and NFS files;
the bug can crash the operating system. Make sure that you configure
RCS to avoid mmap by setting has_mmap to 0 in RCS's conf.h. This bug
is fixed in HP-UX 9.
Contributed by Paul Eggert
If using the setgid() trick described in 4D.13, you will have to
create an entry in the /etc/privgroup file to give the group assigned
to the cvs executable setgid permission (see setprivgrp(1m)).
Additionally, if you are restricting "read" access to the Repository
by limiting access to the executable (this requires yet another
group), then you will require that /etc/logingroup exists and is
configured correctly (usually it's just alink to /etc/group).
Contributed by Dale Woolridge
Last modified: _6/13/1997_
7. I use AFS. Is there anything I need to know?
There is a problem with the way CVS performs its locking when the
files are within AFS. When your current PTS id != your uid, the locks
are not deleted. The stat() system call returns the PTS id of the
owner. If that id != your uid, CVS assumes you did not lock it, and
leaves the lock files alone. The next time you try to use it, it
complains that someone has the repository locked.
Contributed by Michael Ganzberger
[[This was against CVS 1.3. Is it still in CVS 1.4?]]
Last modified: _6/13/1997_
8. I use A/UX. Is there anything I need to know?
[[??]]
Last modified: _6/13/1997_
Category: /Advanced_Topics_/Related_Software/
" + Related Software"
1. How do I use CVS under Emacs? Is there an Emacs cvs-mode?
The pcl-cvs package distributed with CVS is an emacs package that
helps with the update/commit process. When you are ready to update,
you use the 'cvs-update' command within emacs. This executes "update"
and fills a cvs-mode buffer with a line for each file that changed.
The most helpful features are: descriptive words for what happened
(i.e. Merged or Conflict rather than 'U' or 'C'), single keys bound to
diffs and commits, and the ability to mark arbitrary groups of files,
possibly from different directories, for commit as a whole.
All the developers in my group that use emacs find pcl-cvs a much
friendlier and more helpful way to update/commit than raw cvs. One vi
user even converted to emacs just to use pcl-cvs.
Contributed by Jeffrey M Loomis
Last modified: _6/13/1997_
2. What is GIC (Graphical Interface to CVS)?
GIC provides a graphical user interface to the Concurrent Version
System (CVS), a powerful revision control system. GIC is
implemented in the Tcl/Tk programming language and is intended to
augment the sometimes cumbersome CVS command line interface.
Note that according to the official GIC page at
http://www.cpsc.ucalgary.ca/redirect/grouplab/projects/gic/
GIC is no longer being maintained and tkCVS is recommended
instead.
For more on tkCVS, see
.
kingdon@cyclic.com
Last modified: _9/6/1997_
3. What is CAVEMAN?
CAVEMAN is a front end to CVS written in PERL providing a collection
of features desired by the site where it was developed.
- The ability to spread a "project" over multiple Repositories.
- Optional automatic tagging after each commit.
- Additional locking of files.
- Extra before and after program hooks.
- A layer of event logging.
- All sorts of error messages.
- Many changes to the semantics of commands.
It is available via anonymous ftp on ftp.llnl.gov [128.115.54.18] in
gnu/caveman_vX.Y.Z.tar.gz (The numbers X, Y, & Z vary.)
contact Kathleen Dyer kdyer@llnl.gov
(510)423-6803
(510)423-5112 FAX
[[Does someone want to elaborate?]]
Last modified: _6/13/1997_
Category: /Advanced_Topics_/Setting_up_and_Manag/
" + Setting up and Managing the Repository"
1. What do I do first? How do I create a Repository?
First, install all the programs. (See Section 4A.)
Then create a Repository by executing "cvs -d init". (This works with
CVS 1.9.)
Now you can configure your repository by checking out CVSROOT: "cvs -d
checkout CVSROOT". Change into the created directory CVSROOT. Edit the
files you want to edit, and afterwards, commit the changes by typing
"cvs commit".
You will certainly want to add modules of your own. Edit the "modules"
file and add lines to describe the items you want to "checkout" by
module name. Here's a short list that could be used for storing a
small number of GNU and PD sources:
local local
gnu local/gnu
emacs local/gnu/emacs
cvs local/gnu/cvs
public local/public
pdprog1 local/public/pdprog1
pdprog2 local/public/pdprog2
test test
junk test/junk
Andreas Kostyrka
Last modified: _4/21/1998_
2. What are those files in $CVSROOT/CVSROOT?
There are eight Repository control (or "database") files of interest
in the CVSROOT directory:
modules contains the "modules" database. See 1D.11, 2C.7, 4B.6 and
4B.7 for more details.
commitinfo contains two columns: 1. a regular expression to match
against pathnames within the Repository and
a to execute for matching pathnames.
When you execute "commit", CVS passes the Repository pathname for each
directory (and the files to commit within that directory) to
. If exits with a non-zero status, the commit is
blocked.
A associated with a pathname of "DEFAULT" is executed if
nothing else matches. Every associated with a pathname of
"ALL" is executed separately.
rcsinfo contains the same first column as commitinfo, but the second
column is a template file for specifying the log entry you are
required to enter for each commit.
"DEFAULT" and "ALL" work the same as in the commitinfo file.
editinfo contains the same two columns as commitinfo, but the
in the second column is intended to do some consistency
checking on the commit log.
"DEFAULT" works as in commitinfo.
loginfo contains the same two columns as commitinfo, but the
is expected to read a log message from its standard input.
The can do anything it wants with the log information, but
normally it is appended to a log file or sent to mailing lists.
"DEFAULT" & "ALL" work the same as in commitinfo.
cvsignore contains "ignore" patterns that are added to the built-in
ignore list. See 2D.10.
checkoutlist contains a list of other files kept under RCS in
$CVSROOT/CVSROOT that should be checked out by mkmodules to provide a
readable copy.
history contains a stream of text records, one for each event that
the "history" command is interested in. Though the contents of the
history file can be read, it is intended to be read and displayed by
the "history" command. This file is the only one in the above list
that is not under RCS.
Last modified: _6/13/1997_
3. Is there any other state stored in the Repository besides in the
$CVSROOT/CVSROOT directory?
Only in the RCS files. The Repository holds exactly two things: the
tree of RCS files (each usually ending in ",v") and the CVSROOT
directory described above.
Last modified: _6/13/1997_
4. How do I put sources into the Repository?
There are three main ways to put files in the Repository:
Use the "import" command described in Section 3H.
This method is the fastest way to put trees of new code into the
Repository and the *only* way to handle source releases from a 3rd
party software vendor.
Use "add" followed by "commit".
This is how to add new files and directories to the Repository, a few
at a time. Directories don't need to be committed.
You can move RCS files directly into the Repository.
You should create a directory hierarchy to hold them, but you can just
move arbitrary ",v" files into the Repository. The only "state" in the
Repository other than within ",v" files is in the required CVSROOT
directory at the top of the Repository.
Last modified: _6/13/1997_
5. What file permissions should I use on (and in) the Repository?
If you are using pserver (password-authenticated access), see below.
If you run a completely open environment (which usually means that you
don't have, or don't want to waste, the time to deal with it):
- Set all directory permissions to 777.
- Have everyone set their umasks to 0.
(BTW, I don't suggest this. I am merely reporting it.)
If you are a normal Unix shop and want to use groups effectively:
- Set all the directory permissions in the Repository to 775.
If you are using a system that handles both System V and BSD
filesystems, you might have to set the permissions to 2775.)
If you are using one of the many recent versions of Unix that don't
allow you to use the full octal mode, then you'll have to type: chmod
u=rwx,g=rwx,o=rx,g+s dir>
- Change all the groups on the directories to match the groups you
want to write to various directories.
- Make sure every user is in the appropriate groups.
- Have everyone set their umask to 002, including root.
If you don't want non-group members to even read the files, do the
above, but change:
- Repository directory permissions to 770. (or 2770)
- umasks to 007.
If you work in an environment where people can't be trusted to set
their "umask" to something reasonable, you might want to set the umask
for them:
mv /usr/local/bin/cvs /usr/local/bin/cvs.real
cat > /usr/local/bin/cvs
#!/bin/sh
umask 2 # Or whatever your site standard is.
exec /usr/local/bin/cvs.real ${1+"$@"}
^D
Pserver (Password-Authenticated Access) <blome@de.ibm.com>
The above suggestions are not valid when you use the pserver facility.
Be sure to read and understand the manual section about this (should
be 4.6.something). Above all: do /not/ make the repository and CVSROOT
group writeable. In CVSROOT, make `history´ group or world writeable
instead.
I suggest creating one unix group per project group. In the
repository, you would then create one directory for each group, group
writeable. New projects must then be created in these group
directories. If you don't want to say <group>/<project> on
checkout, create a <project> module and point it there.
Last modified: _9/24/1998_
6. How do I structure my Repository?
The Repository holds your software. It can be all interrelated or it
can be a bunch of separately managed directories.
How you break a whole system down into its component parts, while
defining interfaces between them, is one aspect of "Software
Engineering", a discipline that requires the study of dozens of
strange and wonderful areas of the computer and management worlds.
CVS provides a way to keep track of changes to individual files, a way
to "tag" collections of files, and a way to "name" collections of
files and directories. That's all. Everything else is in the way you
apply it.
In other words, you should structure your Repository to match your
needs, usually tied in with the other tools you use to build, install
and distribute your work. Common needs include the ability to:
- mount (or automount) directories from many places in your
organization.
- check out just what you need and no more.
- check out multiple sections in a fixed relation to each other.
- check out large sections to match the assumptions built into your
build system. (Makefiles?)
In my opinion, you should start small and keep everything in one tree,
placing each major sub-system into a separate directory. Later, when
you know what you are doing, you can make it more sophisticated.
Last modified: _6/13/1997_
7. Why would anyone use "modules"? They are too restrictive. I want to be
able to select just the files I want to edit.
Any form of structure is restrictive. If you believe that total chaos
is a viable working paradigm, or if you believe you can keep track of
the interrelations between all portions of your Repository in your
head, then you can do what you please.
If you believe that systems of files require management and structure,
then the "modules" idea is very useful. It is a way to impose a naming
scheme on a tree of files, a naming scheme that can be simpler than a
large list of relative pathnames.
The "modules" file represents a published interface to the Repository
set up by your Repository Administrator. If s/he did a creditable job,
the modules offered will be internally consistent and will smoothly
interact with the rest of your environment.
Last modified: _6/13/1997_
8. How do I rename a file or directory? What are the consequences?
In CVS there is no single "rename" command.
See 2C.4 for the suggested way to rename a file or directory.
The rest of this section covers some of the consequences of renaming.
A "renaming database" has been proposed that would keep track of name
changes so that "update -r " would continue to work across the
renaming. But as it stands, you have to pick one of the following
options:
Use the technique described in 2C.4. (For each file, duplicate the
file in the Repository, "remove" the old version so it winds up in the
Attic and strip all Tags off the new version.)
- "update -r " produces the correct files.
- The duplicated revision history can be slightly misleading.
- A plain (i.e. without the "-r ") "checkout" or "update -d" will
create directories "renamed" this way, but you can delete it and a
plain "update" won't bring it back.
Move the files and directories in the Repository to the new names.
- You save the revision history under a different file name.
- You save a little space.
- "update -r " produces the wrong files or directories.
This is not a good general solution, but if you plan never to look
back (someone may be gaining on you!), it is sometimes a useful
notion.
If you are clever with Makefiles, you might be able to rework them to
handle either the new or old names, depending on which ones exist at
the time. Then you can move an old onto the new, more
sophisticated, revision of the Makefile. (Yes, this changes the
"released" file if indicates a release. But it is an option.)
- Important Note: If you rename a directory, you must rename the
corresponding directory in every checked-out working directory. At the
same time, you must edit the pathname stored in the ./CVS/Repository
file within each of the moved directories.
The easiest way to move a lot of directories around is to tell
everyone to remove their working directories and check them out again
from scratch.
- The file exists in the working directory and in the ./CVS/Entries
file, but not in the Repository. For the old file, "update" prints:
cvs update: xyz.c is no longer in the repository
and deletes the file. If the file was modified, "update" prints:
cvs update: conflict: xyz.c is modified but no longer in the
repository C xyz.c
and leaves the file alone. In the new directory, you see:
U xyz.c
as you would if someone else executed "add" and "commit".
For each file, copy the working file to a new name in the working
directory and use the "cvs remove" to get rid of the old old file and
"cvs add" to add the new one. Since there is no way for CVS to remove
a directory, this only works for files.
- This is what most people think of first. Without a "rename" command,
the remove/add technique seems obvious.
- You lose the connection of your new working file to its past
revision history.
Last modified: _6/13/1997_
9. What are "Attic" directories?
When you use the "remove" command on a file, CVS doesn't delete the
file, it only registers your desire to delete it.
When you "commit" a removed file, CVS moves the Repository's matching
RCS file into a sub-directory named "Attic" within the Repository.
Attic files are examined when the '-r' or '-D' option is used on
"checkout" or "update". If the specified revision, tag or date matches
one on a file in the Attic, that file is checked out with the others.
You can think of the Attic as a sort of dead branch, which is only
looked at when you refer to a or .
Last modified: _6/13/1997_
10. Is it OK to remove anything from the Repository?
In general, removing anything from the Repository is a bad idea. The
information in a deleted object is lost forever. There are many ways
to skip over files, directories and revisions without deleting them.
Here are some of the consequences of removing the following things
stored in the Repository:
CVSROOT files (Repository control files)
The Repository will work without any of them, but you should
understand what you are losing by deleting them. See 4B.2.
Revisions
The only way to remove revisions is to use the "admin -o" command (or
the equivalent RCS command "rcs -o").
They are lost forever. Any tags formerly attached to deleted revisions
are now pointing into the Phantom Zone. You'll need to contact Jor-el
to get them back.
Files
You should not remove a file unless you truly never want to see it
again. If you want to be able to check out an old revision of this
file, use "cvs remove" instead.
Tags
Tags take up little space and you can't recover from deleting them. If
you depend on tags for releases you will lose vital information.
Directories
There is no Attic for directories, so the only way to remove them is
to use "rm -r". They are gone forever.
If you delete (or move) a directory, all checked-out versions of that
directory will cause CVS to halt. You'll have to visit each
checked-out directory and remove the matching working directory by
hand.
Attic files
The "remove" command sends files to the Attic. To really delete them,
you have to go into the Attic and use "rm".
If a file in the Attic has a Tag on it that you might ever want to
check out again, you probably don't want to delete it.
Lock files (named: "#cvs.[wr]fl.")
These are lock files. If you are getting "lock" errors and the dates
on the lock files indicate that they are old, you can delete them.
Deleting lock files still in use by a CVS process might produce
unusual errors.
Last modified: _6/13/1997_
11. Can I convert to CVS from RCS without losing my revision history?
Yes, you can simply move (or copy) your RCS files into a directory
within the Repository, check out that directory and start working.
Last modified: _6/13/1997_
12. Can I move RCS files with branches in them into the Repository?
Yes, but they may not work if you created branches in a way that
conflicts with CVS's assumptions:
You can't use .0. branches. (They are reserved for "Magic" branch
tags.)
If you use branch 1.1.1, you can't use the Vendor branch.
You can use other RCS branches under CVS. There is no need to create
"magic" branch tags because the physical branch already exists.
Last modified: _6/13/1997_
13. Can I use raw RCS commands on the Repository?
You can use raw rcs commands directly on the Repository if you take a
little care. The Repository itself contains no "CVS state" (as opposed
to RCS revision histories) outside the CVSROOT directory.
But using raw RCS commands to change branches, tags or other things
that CVS depends on may render the files unusable.
See 4D.7 on RCS/CVS sharing of the Repository and Section 3B on the
"admin" command.
Last modified: _6/13/1997_
14. How do I convert from SCCS to RCS?
You'll have to execute something like "sccs2rcs" (in the CVS contrib
directory) on every file. Then you can move the resulting RCS files
into the Repository as described above.
Last modified: _6/13/1997_
15. How do I limit access to the Repository?
There are all sorts of ways to restrict access to Repository files,
none of which are hooked directly into CVS.
Techniques for limiting access include:
Training, management and good backups.
The best form of Repository control is a combination of:
- A reliable backup scheme (verify it!)
- Enough training to ensure your developers are competent and
knowledgeable about all areas of your sources.
- Effective management of the boundaries and grey areas.
In many cases, technical solutions to "security" problems are
inadequate. You should first try to avoid them.
Personal Opinion: In an environment where "unknowns" are allowed to
touch important sources the "owner" of the CVS Repository must be a
large, loud, vigorous lout with a well-balanced truncheon and the
right to use it. Don't underestimate the effectiveness of letting
everyone know they will be strapped into the stocks on the Town Common
and pelted with vegetables if they break something they don't
understand without first asking the experts.
Set Unix groups and permissions. See 4B.5. You can set different
owners, groups and permissions for each sub-directory within the
Repository if that helps.
Catch invocations of "commit" by defining pre-commit programs in the
"commitinfo" file. This is fairly powerful, since it can block commits
based on anything you can program. Take a look at the programs in the
"contrib" directory of the CVS source tree.
Use multiple Repositories, each with its own protection scheme. If
you use NFS (or AFS) you can even use "export" restrictions to various
groups of machines to keep (for example) the Engineering Repository
off the Customer Service machines.
Try the "setgid" trick described in 4D.13.
Try to use the RCS access control lists, though I don't think CVS
will handle them cleanly.
Edit the source code to CVS to add your own access control.
Last modified: _6/13/1997_
16. What are the Repository Administrator's responsibilities?
Generally, the Administrator should set "policy", create the
Repository and monitor its size and control files.
Some specific responsibilities include:
Examining the Repository once in a while to clean up:
Trash files left by misguided developers who mistake the Repository
for a working directory.
Non-RCS files. Other than the files CVS needs in the
$CVSROOT/CVSROOT directory, every file in the Repository should be an
RCS file.
Lock files (both CVS '#*' and RCS ',*' files) left around after
crashes.
Wrong permissions, groups and ownerships.
Locked files. (RCS locks, that is.)
Attic files that should never have been under CVS at all. Don't
blindly delete files from Attic directories -- they were mostly put
there (via the "cvs remove") for a reason. Files that should be
deleted are binary files (e.g. '*.o', 'core', executables) that were
mistakenly inserted by "import -I !".
Maintaining the modules file.
Storing site-specific ignore patterns in the
$CVSROOT/CVSROOT/cvsignore file.
Storing the names of non-standard CVSROOT files (See 4B.2) in the
$CVSROOT/CVSROOT/checkoutlist
Maintaining the other Repository control files: commitinfo, loginfo,
rcsinfo and editinfo.
Pruning the history file every once in a while. (Try the
"cln_hist.pl" script in the "contrib" directory.)
Staying aware of developments on the info-cvs mailing list and what
is available in the FTP and WWW archives.
Running "ps ax" once in a while and kill off any "update" programs
not running as "root". It is too easy to leave the "cvs" off the front
of the "cvs update" command.
Executing monitor programs to check the internal consistency of the
Repository files. Ideas:
Files that have a default RCS branch that is not 1.1.1 (From an
abuse of "admin -b".)
Files that have only Revisions 1.1 and 1.1.1.1, with a default
branch of "MAIN". (From an abuse of "admin -o".)
Existing branch tags and various branch consistency checks.
Last modified: _6/13/1997_
17. How do I move the whole Repository?
Copy or move the tree. (On Unix systems, a set of piped "tar" commands
works great. If the Repository does not contain any symlinks, which it
normally doesn't, you can also use "cp -r".)
If you can avoid changing $CVSROOT (i.e. the "logical" pathname of the
Repository) by replacing the old location with a symbolic link to the
new location, you don't have to do anything else.
(You could also mount the new location on top of the old location if
you are using NFS or some other filesystem that allows it.)
If you must change $CVSROOT, you must also tell everyone to change the
CVSROOT environment variable in all running shells and in any personal
configuration files ('.' files on Unix) where it is set.
The Repository itself contains no references to its own name, except
possibly in some of the files in the CVSROOT directory. If your
modules (or loginfo, commitinfo, etc.) file mentions helper programs
directly in the Repository, you'll have to change the pathnames to
point to the new Repository location.
The main changes you'll have to make are to all the CVS administrative
files (./CVS/Repository and ./CVS/Root) in every working directory
ever checked out from the previous location of the Repository you just
moved.
You have three choices:
If all ./CVS/Repository files in all working directories contain
relative pathnames, you don't have to do anything else.
Have everyone "release" or delete their working directories (after
committing, or just saving, their work) and check them all out again
from the new Repository after the move.
Use "find . ( -name Repository -o -name Root )" and a PERL or shell
script to run through all the ./CVS/Repository and ./CVS/Root files
and edit the values in the files.
Last modified: _6/13/1997_
18. How do I change permissions on a file in the Repository by using a CVS
command? (i.e. without using "chmod 777 $CVSROOT/dir/file")
When you first "import" or "add"/"commit" a file, the read and execute
bits on the Repository file are inherited from the original source
file, while the write bits on the Repository file are are turned off.
This is a standard RCS action.
After that, there is no way to alter the permissions on a file in the
Repository using CVS (or RCS) commands. You have to change the
permissions on both your working file and on the Repository file from
which it was retrieved.
Whenever you "checkout" the file or retrieve a new revision via
"update" (or after a "commit"), your working file is set to match the
permissions of the Repository file, minus any "umask" bits you have
set.
Last modified: _6/13/1997_
Category: /Advanced_Topics_/Tricks_of_the_Trade/
" + Tricks of the Trade"
1. How can you even check in binary files, let alone allow CVS to do its
auto-merge trick on them?
First of all, if you want to use binary files, you should get RCS 5.7
and CVS 1.9 or later (earlier versions had some support, but there have been
bug fixes). Secondly, follow the instructions for installing RCS very
carefully (it is easy to get it installed so it works for everything
except binary files).
Then, specify 'cvs add -kb' instead of just 'cvs add' to add a binary
file. If you want to set an existing file to binary, run 'cvs admin
-kb' (and then check in a new copy of the file). Note that old
versions of CVS used -ko instead of -kb for binary files, so if you
see a reference to -ko in the context of binary files, you should
think -kb instead.
Of course when 'cvs update' finds that a merge is needed, it can't
do this for binary files the same way as for text files. With the
latest versions (e.g. CVS 1.9.14), it should be able to give you both
versions and let you merge manually. Another approach is to
run 'cvs admin -l' to lock files, as described in
"How can I lock files while I'm working on them the way RCS does?"
elsewhere in this FAQ. See also
"Is there any way to import binary files?" and
"How do I "add" a binary file?" elsewhere in this FAQ.
kingdon@cyclic.com
Last modified: _9/6/1997_
2. Can I edit the RCS (",v") files in the Repository?
Yes, but be very careful. The RCS files are not free-form files, they
have a structure that is easily broken by hand-editing. The only time
I would suggest doing this is to recover from emergency failures that
are difficult to deal with using CVS commands, including the "admin"
command, which can talk directly to RCS.
Though no one actively encourages the editing of RCS files, many
people have succumbed to the urge to do so when pressed for time. The
reasons given, usually with evident contrition, include:
- Editing mistakes in, or adding text to, log entries. (If you have
RCS 5.6 or later, you should use `cvs admin -m'.)
- Renaming or moving symbolic names. (You should `cvs admin -N'
instead.)
- Unlocking a file by changing the "locker" from someone else to
yourself. (It's safer to use `cvs admin -u -l'.)
- Making global changes to past history. Example: Eradicating former
employees names from old documents and Author entries. (And someone
thought the "history" command was evidence of Big Brother! I never
realized how much help a wide-open revision control system could have
provided to The Ministry of Truth.)
Last modified: _6/13/1997_
3. Can I edit the ./CVS/{Entries,Repository,Tag} files?
Yes, but with CVS 1.3 and later, there is almost no reason to edit any
of the CVS administrative files.
If you move pieces of your Repository around it can be faster to edit
all the ./CVS/Repository files rather than checking out a large tree.
But that is nearly the only reason to do so.
Last modified: _6/13/1997_
4. Someone executed "admin -o" and removed revisions to which tags/symbols
were attached. How do I fix them?
It depends on what you mean by "fix". I can think of three ways to fix
your predicament:
Remove the tags.
Assuming you really wanted to get rid of the revision and its
associated tags, you can remove them with the "admin" command. The
"tag -d" command will only remove tags attached to existing revisions.
You can remove a tag, even if it is attached to a non-existent
revision, by typing:
cvs admin -N
Retrieve the outdated revision.
You should first look in your backup system for recent versions of the
file. If you can't use them, you can carefully extract each revision
that followed the earliest outdated revision using RCS (or "cvs
admin") commands and reconstruct the file with all the right
revisions, branches and tags. This is a lot of work.
You *can't* insert a revision into the current RCS file.
Move the Tags to another revision in each file.
If you want to move the tags to another valid revision, you have two
choices, both of which require that you find all the revision numbers
of the files you want to "tag" and execute the following command
sequences on each .
Use "update" to grab the revision you want, then execute a normal
"tag" command to Tag that revision:
cvs update -r
cvs tag
Use "admin" to set the tag to a specific revision:
cvs admin -N:
Last modified: _6/13/1997_
5. How do I move or rename a magic branch tag?
(To rename a non-branch see 3O.9.)
Before reading this, read 3M.3 and 3M.4 and understand exactly how tag
and rtag use '-r' and why it won't do the right job here.
First, I have to explain exactly what a magic branch tag is.
A magic is an artificial tag attached to a non-existent
revision on a non-existent branch number zero. It looks like this:
TAG1:.0.Y
is the "branch point revision", a normal revision with an
odd number of '.'s in it. (e.g. 1.5, 1.3.1.6, etc)
Y is an even number (e.g. 2, 4, 6, etc.) All CVS branches,
other than the Vendor branch, are even numbered.
TAG1 is considered by CVS to be attached to revision . The first
"update -r TAG1 " after applying TAG1 will produce a copy of
revision with a sticky tag of TAG1. The first "commit" to that
file will cause CVS to construct an RCS branch named .Y and check
in revision .Y.1 on the new branch.
Note: TAG1 is *not* considered to be attached to by RCS, which
explains why you can't refer directly to the branch point revision for
some CVS commands.
Moving a magic is the act of reapplying the same tag to
different revisions in the file:
TAG1:.0.Y
to
TAG1:.0.Z or TAG1:.0.B
You can move a magic branch tag to the revisions of your choice by
using "update" to find the revisions you want to tag and reapplying
the tag to all the files with the '-F' option to force it to move the
existing .
cvs update -r (or '-A' for the Main Branch)
cvs tag -F -b
If the earlier location of TAG1 refers to a physical branch within any
RCS file, moving it will make the existing branch in the file seem to
disappear from CVS's view. This is not a good idea unless you really
want to forget the existence of those RCS branches.
If the "update" above retrieves the original branch point revision
(), the "tag" command above will create the tag:
TAG1:.0.Z
Where Z is 2 greater than the highest magic branch already on revision
. The TAG1 branch will still have the same branch point (i.e.
revision ), but the first commit to the new TAG1 branch will create
a different RCS branch number (.Z instead of .Y).
Renaming a magic is the act of changing
TAG1:.0.Y
to
TAG2:.0.Y
There is no harm in changing a tag name as long as you forget that
TAG1 ever existed and you clean up any working directories with sticky
TAG1 tags on them by using "update -A", "update -r " or by
removing the working directories.
On the other hand, actually changing the tag is not easy.
See 3M.3 for why the seemingly obvious solution won't work:
cvs tag -b -r
The only direct way to rename a magic tag is to use the "admin"
command on each file: (You might want to use '-n'. Read "man rcs" and
look at the '-n' and '-N' options.)
cvs admin -N: .
cvs tag -d
But you have to be careful because "admin" is different from other CVS
commands:
"admin" can be used recursively, but only by specifying directory
names in its argument list (e.g. '.'),
Where "rtag -r " would interpret as
a magic CVS branch tag, "admin" is a direct interface to RCS which
sees a magic branch tag as a simple (though non-existent) RCS revision
number.
This is good for us in this particular case, but different from normal
CVS.
"admin" also skips the Attic and produces different kinds of errors
than CVS usually does. (Because they are coming directly from RCS.)
The other way to rename a magic is to edit the Repository
files with a script of some kind. I've done it in the past, but I'll
leave it as an exercise for the reader.
Last modified: _6/13/1997_
6. Can I use RCS locally to record my changes without making them globally
visible by committing them?
You can, but it will probably confuse CVS to have ",v" files in your
working directory. And you will lose all your log entries when you
finally commit it.
Your best bet is to create your own CVS branch and work there. You can
commit as many revisions as you want, then merge it back into the main
line (or parent branch) when you are finished.
Last modified: _6/13/1997_
7. How can I allow access to the Repository by both CVS and RCS?
The first step is to try not to. If some people are using CVS, there
is no reason for everyone not to. It is not hard to learn the basics
and CVS makes certain operations *easier* than a series of RCS
commands. Personal preference in what software tools can be applied to
a shared Repository has to take second place to system integration
needs. If you disagree, try writing some Lisp code for inclusion in
your Unix kernel and see what kind of reception you get.
If you really must allow routine RCS access to the CVS Repository, you
can link an RCS sub-directory into a piece of the Repository:
ln -s /Repository/some/directory/I/want RCS
and RCS will work just fine.
Those who are using RCS will have to keep the following in mind:
If a file was originally added to the Repository by "import" and has
not been changed using CVS, the *RCS* default branch will remain
attached to the Vendor branch, causing revisions checked-in by "ci" to
wind up on the Vendor branch, instead of the main branch. Only CVS
moves the RCS default branch on first commit.
The way around this is to checkin (using "ci") all the files first and
move them into the Repository. That way they won't have Vendor
branches. Then RCS will work OK.
It is possible to use "rcs" and "ci" to make the files unusable by
CVS. The same is true of the CVS "admin" command.
Normal RCS practice locks a file on checkout with "co -l". In such
an environment, RCS users should plan to keep survival gear and food
for at least 30 days near their desks. When faced with bizarre and
unexpected permission errors, howling mobs of slavering CVS users will
run the RCS users out of town with pitchforks and machetes.
See 3C.8 for a way to avoid machetes aroused by lock collisions.
Though files checked in by RCS users will correctly cause
"up-to-date" failures during CVS "commits" and they will be
auto-merged into CVS working directories during "update", the opposite
won't happen.
RCS users will get no warning and will not be required to merge older
work into their code. They can easily checkin an old file on top of a
new revision added by CVS, discarding work committed earlier by CVS
users.
See the howling mob scenario described above.
RCS is great. I have used it for years. But I wouldn't mix it this
way. In a two-camp society, you are asking for real trouble, both in
technical hassles to clean up and in political hassles to soothe.
Branch merges will also be a major problem.
Last modified: _6/13/1997_
8. I "updated" a file my friend, "bubba", committed yesterday. Why doesn't
the file now have a modified date of yesterday?
CVS restores dates from the RCS files only on first "checkout". After
that, it is more important to maintain a timestamp relative to the
other files in the working directory.
Example: You committed a source file at 5PM. Bubba updated his copy of
the file, grabbing your changes, then changed and committed a new
revision of the file at 6PM. At 7PM, you compile your file. Then you
execute "update". If CVS sets the date to the one in the RCS file, the
file would be given a timestamp of 6PM and your Makefile wouldn't
rebuild anything that depended on it. Bad news.
Note that the same logic applies to retrieving a revision out of the
Repository to replace a deleted file. If CVS changes your file in an
existing working directory, whether it was because a new revision was
committed by someone else or because you deleted your working file,
the timestamp on the retrieved working file *must* be set to the
current time.
When you first retrieve a file, there is no reason to expect any
particular timestamp on the file within your working area. But later,
when dependency checking is performed during a build, it is more
important for the timestamps on the local files to be consistent with
each other than than it is for working files to match the timestamps
on the files in the Repository. See 4D.17 for some more about
timestamps.
Last modified: _6/13/1997_
9. Why do timestamps sometimes get set to the date of the revision,
sometimes not? The inconsistency causes unnecessary recompiles.
The "checkout" command normally sets the timestamp of a working file
to match the timestamp stored on the revision in the Repository's RCS
file.
The "commit" command retains the timestamp of the file, if the act of
checking it in didn't change it (by expanding keywords).
The "update" command sets the time to the revision time the first time
it sees the file. After that, it sets the time of the file to the
current time. See 4D.8 for a reason why.
Here's a two-line PERL program to set timestamps on files based on
other timestamps. I've found this program useful. When you are certain
you don't want a source file to be recompiled, you can set its
timestamp to the stamp on the object file.
#!/usr/local/bin/perl
#
# Set timestamp of args 2nd-Last to that of the first arg.
#
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime)
= stat(shift);
utime($atime,$mtime,@ARGV);
Last modified: _6/13/1997_
10. While in the middle of a large "commit", how do I run other commands,
like "diff" or "stat" without seeing lock errors?
Type:
cvs -n
The '-n' option to the main cvs command turns off lock checking, a
reasonable act for read-only commands given the promise offered by
'-n' not to alter anything. The "diff", "log" and "stat" commands
provide the same information (for files that are not being committed)
when used with and without the '-n' option.
Warning: Ignoring locks can produce inconsistent information across a
collection of files if you are looking at the revisions affected by an
active commit. Be careful when creating "patches" from the output of
"cvs -n diff". If you are looking only at your working files, tagged
revisions, and BASE revisions (revisions whose numbers are read from
your ./CVS/Entries files), you should get consistent results. Of
course, if you catch a single file in the middle of RCS activity, you
might get some strange errors.
Note that the suggested command is "cvs -n ". The visually
similar command "cvs -n" has no relation to the suggested
usage and has an entirely different meaning for each command.
"cvs -n update" also works in the middle of a commit, providing
slightly different information from a plain "cvs update". But, of
course, it also avoids modifying anything.
You could also use the RCS functions, "rlog" and "rcsdiff" to display
some of the information by referring directly to the Repository files.
You need RCS version 5 or later for the commands described above to
work reliably.
Last modified: _6/13/1997_
11. Where did the ./CVS/Entries.Static file come from? What is it for?
Each CVS working directory contains a ./CVS/Entries file listing the
files managed by CVS in that working directory. Normally, if the
"update" command finds a file in the Repository that is not in the
./CVS/Entries file, "update" copies the appropriate revision of the
"new" file out of the Repository and adds the filename to the Entries
file. This happens for files:
Added to the Repository from another working directory.
Dragged out of the Attic when switching branches with "update -A" or
"update -r".
Whose names were deleted from the ./CVS/Entries file.
If the ./CVS/Entries.Static file exists, CVS will only bring out
revisions of files that are contained in either ./CVS/Entries or
./CVS/Entries.Static. If a Repository file is found in *neither* file,
it is ignored.
The ./CVS/Entries.Static file is created when you check out an
individual file or a module that creates working directories that
don't contain all files in the corresponding Repository directory. In
those cases, without an ./CVS/Entries.Static file, a simple "update"
would bring more files out of the Repository than the original
"checkout" wanted.
The ./CVS/Entries.Static file can be removed by hand. It is
automatically removed if you run "update -d" to create new directories
(even if no new directories are created). (Internally, since
"checkout" turns on the '-d' flag and calls the "update" routine, a
"checkout" of a module or directory that writes into an existing
directory will also remove the ./CVS/Entries.Static file.)
Last modified: _6/13/1997_
12. Why did I get the wrong Repository in the loginfo message?
You probably:
Use multiple Repositories.
Configured CVS to use absolute pathnames in the ./CVS/Repository
file.
Configured CVS not to use the ./CVS/Root file.
Typed the "commit" command in one Repository with your $CVSROOT
pointing at another.
"commit" and all other CVS commands will heed an absolute pathname in
the ./CVS/Repository file (or in the "-d CVSrootdir" override), but
the log function doesn't take arguments -- it just looks at $CVSROOT.
If you avoid even one of the four steps above, you won't see this
problem. If you configure ./CVS/Root, you won't be allowed to execute
the program causing the error.
Last modified: _6/13/1997_
13. How do I run CVS setuid so I can only allow access through the CVS
program itself?
Setuid to root is not a great idea. Any program that modifies files
and is used by a widely distributed group of users is not a good
candidate for a setuid program. (The worst suggestion I've ever heard
was to make *Emacs* setuid to root.)
Root access on Unix is too powerful. Also, it might not work in some
(secure?) environments.
Running it setuid to some user other than root might work, if you add
this line to main.c near the beginning:
setuid(geteuid());
Otherwise it uses *your* access rights, rather than the effective
uid's.
Also, you have to invent a fake user whose name will show up in
various places. But many sites, especially those who might want a
setuid CVS for "security", want personal accountability -- no generic
accounts. I don't know whether accountability outweighs file security.
And finally, unless you take action to limit the "admin" command, you
are leaving yourself unprotected anyway.
Last modified: _6/13/1997_
14. How about using groups and setgid() then?
Here is a way to run CVS setgid in some environments:
Stick this near the front of the main() in main.c:
setgid(getegid());
This will allow "access" to work on systems where it only works on the
real gid.
Create a group named "cvsg". (This example uses "cvsg". You can name
it as you wish.)
Put *no* users in the "cvsg" group. You can put Repository
administrators in this group if you want to.
Set the cvs executable to setgid (not setuid):
cd /usr/local/bin; chown root.cvsg cvs; chmod 2755 cvs
Make sure every file in the Repository is in group "cvsg":
chown -R root.cvsg $CVSROOT
Change all directory permissions to 770. This allows all access to
the files by the "cvsg" group (which has no members!) and no access at
all to anyone else.
find $CVSROOT -type d -exec chmod 2770 {} \;
On some systems you might have to type:
find $CVSROOT -type d -exec chmod u=rwx,g=rwx,o=,g+s {} \;
This should allow only the cvs program (or other "setgid to group
cvsg") programs to write into the area, but no one else. Yes the user
winds up owning the file, but s/he can't find it again later since
s/he can't traverse the tree. (If you enable the world execute bit
(mode 2771) on directories, users can traverse the tree and the user
who last wrote the file can still write to it.)
If you want to allow read access, check out an entire tree somewhere.
You have to do this anyway to build it.
Note: If you are using a stupid file system that can't inherit file
groups from the parent directory (even with the "setgid" (Octal 2000)
bit set), you might have to modify CVS (or RCS) to reset the group
every time you create a new file. I have not tested this.
The setgid() method shares with the setuid() method the problem of
keeping "admin" from breaking things.
Last modified: _6/13/1997_
15. How do I use the "commitinfo" file?
Go read 4B.2 first.
The "commitinfo" file allows you to execute "sanity check" functions
before allowing a commit. If any function called from within the
commitinfo file exits with a non-zero status, the commit is denied.
To fill out a "commitinfo" file, ask yourself (and those sharing your
Repository) these questions:
- Is there anything you want to check or change before someone is
allowed to commit a file? If not, forget commitinfo.
If you want to serialize binary files, you might consider something
like the rcslock.pl program in the contrib directory of the CVS
sources.
- Do you want to execute the same exact thing before committing to
every file in the Repository? (This is useful if you want to program
the restrictions yourself.) If so, set up a single line in the
commitinfo:
DEFAULT /absolute/path/to/program
CVS executes the program once for each directory that "commit"
traverses, passing as arguments the directory and the files to be
committed within that directory.
Write your program accordingly. Some examples exist in the contrib
directory.
- Do you want a different kind of sanity check performed for different
directories? If so, you'll have to decide what to do for all
directories and enter lines like this:
regexp1 /absolute/path/to/program-for-regexp1
regexp2 /absolute/path/to/program-for-regexp2
DEFAULT /absolute/path/to/program-for-all-else
- Is there anything you want to happen before *all* commits, in
addition to other pattern matches? If so, include a line like this:
ALL /absolute/path/to/program
It is executed independently of all the above. And it's repeatable --
you can have as many ALL lines as you like.
Last modified: _6/13/1997_
16. How do I use the "loginfo" files?
See 4B.2 and the "commitinfo" question above.
The "loginfo" file has the same format as the "commitinfo" file, but
its function is different. Where the "commitinfo" information is used
before a commit, the "loginfo" file is used after a commit.
All the commands in the "loginfo" file should read data from standard
input, then either append it to a file or send a message to a mailing
list. If you want to make it simple, you can put shell (the shell used
by "popen(3)") command lines directly in the "loginfo" (or
"commitinfo") file. These seem to work:
^special /usr/ucb/Mail -s %s special-mailing-list ^other /usr/ucb/Mail
-s %s other-mailing-list DEFAULT (echo '===='; echo %s; cat) >
/path/name/to/log/file
Last modified: _6/13/1997_
17. How can I keep people with restrictive umask values from blocking
access to the Repository?
If a user creates a new file with restricted permissions (e.g. 0600),
and commits it, the Repository will have a file in it that is
unreadable by everyone. The 0600 example would be unreadable by
*anyone* but root and the user who created it.
There are 3 solutions to this:
Let it happen. This is a valid way to protect things. If everyone is
working alone, a umask of 077 is OK. If everyone is working only in
small groups, a umask of 007 is OK.
Train your users not to create such things if you expect to share
them.
See 4B.5 for a small script that will reset the umask.
I personally don't like the idea of a program automatically
*loosening* security. It would be better for you all to talk about the
issue and decide how to work together.
Last modified: _6/13/1997_
Category: /Commands_/
" Commands "
Category: /Commands_/add_ad_new/
" + "add", "ad", "new""
1. What is "add" for?
To add a new directory to the Repository or to register the desire to
add a new file to the Repository.
The directory is created immediately, while the desire to add the file
is recorded in the local ./CVS administrative directory. To really add
the file to the Repository, you must then "commit" it.
Last modified: _6/13/1997_
2. How do I add a new file to the branch I'm working on?
The user actions for adding a file to any branch, including the Main
Branch, are exactly the same.
You are in a directory checked out (or updated) with the '-A' option
(to place you on the Main Branch) or the "-r " option (to
place you on a branch tagged with ). To add to the
branch you are on, you type:
cvs add
cvs commit
If no ./CVS/Tag file exists (the '-A' option deletes it), the file
will be added to the Main Branch. If a ./CVS/Tag file exists (the "-r
" option creates it), the file will be added to the branch
named (i.e. tagged with) .
Unless you took steps to first add the file to the Main Branch, your
new file ends up in the Attic.
Last modified: _6/13/1997_
3. Why did my new file end up in the Attic?
The file is thrown into the Attic to keep it from being visible when
you check out the Main Branch, since it was never committed to the
Main Branch.
Last modified: _6/13/1997_
4. Now that it's in the Attic, how do I connect it to the Main branch?
That can be considered a kind of "merge". See 4C.8
Last modified: _6/13/1997_
5. How do I avoid the hassle of reconnecting an Attic-only file to the Main
Branch?
You create it on the Main Branch first, then branch it.
If you haven't yet added the file or if you decided to delete the new
Attic file and start over, then do the following: (If you added the
file (or worse, the 157 files) to the Attic and don't want to start
over, try the procedure in 4C.8.)
Temporarily remove the sticky branch information. Either:
Move the whole directory back to the Main Branch. [This might not be
a good idea if you have modified files, since it will require a merge
in each direction.]
cvs update -A
*or*
Move the ./CVS/Tag file out of the way.
mv ./CVS/Tag HOLD_Tag
Add and branch the file "normally":
cvs add
cvs commit
cvs tag -b
[ is the same Branch Tag as you used on all the other
files. Look at ./CVS/Entries or the output from "cvs stat" for sticky
tags.]
Clean up the temporary step.
If you moved the ./CVS/Tag file, put it back. Then move the new file
onto the branch where you are working.
mv HOLD_Tag ./CVS/Tag
cvs update -r
If you ran "update -A" rather than moving the ./CVS/Tag file, move
the whole directory (including the new file) back onto the branch
where you were working:
cvs update -r
Last modified: _6/13/1997_
6. How do I cancel an "add"?
If you want to remove the file entirely and cancel the "add" at the
same time, type:
cvs remove -f
If you want to cancel the "add", but leave the file as it was before
you typed "cvs add", then you have to fake it:
mv .hold
cvs remove
mv .hold
Last modified: _6/13/1997_
7. What are the ./CVS/file,p and ./CVS/file,t files for?
The ./CVS/file,p and ./CVS/file,t files are created by the "add"
command to hold command line options and message text between the time
of the "add" command and the expected "commit".
The ./CVS/file,p file is always null, since its function was absorbed
by the "options" field in the ./CVS/Entries file. If you put something
in this file it will be used as arguments to the RCS "ci" command that
commit uses to check the file in, but CVS itself doesn't put anything
there.
The ./CVS/file,t file is null unless you specify an initial message in
an "add -m 'message'" command. The text is handed to "rcs -i
-t./CVS/file,t" to create the initial RCS file container.
Both files must exist to commit a newly added file. If the
./CVS/file,p file doesn't exist, CVS prints an error and aborts the
commit. If the ./CVS/file,t file doesn't exist, RCS prints an error
and CVS gets confused, but does no harm.
To recover from missing ,p and ,t files, just create two zero-length
files and rerun the "commit".
Last modified: _6/13/1997_
8. How do I "add" a binary file?
If you configured CVS to use the GNU version of "diff" and "diff3",
you only need to turn off RCS keyword expansion.
First you turn off RCS keyword expansion for the initial checkin by
using "add -ko". It works like "update -ko" in creating a "sticky"
option only for the copy of the file in the current working directory.
cvs add -ko
Commit the file normally. The sticky -ko option will be used.
cvs commit
Then mark the RCS file in the Repository so that keyword expansion is
turned off for all checked out versions of the file.
cvs admin -ko
Since "admin -ko" records the keyword substitution value in the
Repository's RCS file, you no longer need the sticky option. You can
turn it off with the "update -A" command, but if you were on a branch,
you'll have to follow it "update -r " to put yourself back
on the branch.
Managing that binary file is another problem. See 4D.1.
Last modified: _6/13/1997_
Category: /Commands_/admin_adm_rcs/
" + "admin", "adm", "rcs""
1. What is "admin" for?
To provide direct access to the underlying "rcs" command (which is not
documented in this FAQ) bypassing all safeguards and CVS assumptions.
Last modified: _6/13/1997_
2. Wow! Isn't that dangerous?
Yes.
Though you can't hurt the internal structure of an RCS file using its
own "rcs" command, you *can* change the underlying RCS files using
"admin" in ways that CVS can't handle.
If you feel the need to use "admin", create some test files with the
RCS "ci" command and experiment on them with "rcs" before blasting any
CVS files.
Last modified: _6/13/1997_
3. What would I normally use "admin" for?
Normally, you wouldn't use admin at all. In unusual circumstances,
experts can use it to set up or restore the internal RCS state that
CVS requires.
You can use "admin -o" (for "outdate") to remove revisions you don't
care about. This has its own problems, such as leaving dangling Tags
and confusing the "update" command.
There is some feeling among manipulators of binary files that "admin
-l" should be used to serialize access. See 3C.8.
An interesting use for "admin" came up while maintaining CVS itself. I
import versions of CVS onto the Vendor branch of my copy of CVS, make
changes to some files and ship the diffs (created by "cvs diff -c -r
TO_BRIAN") off to Brian Berliner. After creating the diff, I retag
("cvs tag -F TO_BRIAN") the working directory, which is then ready to
produce the next patch.
I'll use "add.c" as an example (only because the name is short).
When the next release came out, I discovered that the released "add.c"
(version 1.1.1.3 on the Vendor branch) was exactly the same as my
modified file (version 1.3). I didn't care about the changelog on
versions 1.2 and 1.3 (or the evidence of having done the work), so I
decided to revert the file to the state where it looked like I had not
touched the file -- where I was just using the latest on the vendor
branch after a sequence of imports.
To do that, I removed all the revisions on the main branch, except for
the original 1.1 from which the Vendor branch sprouts:
cvs admin -o1.2: add.c
Then I set the RCS "default branch" back to the Vendor branch, the way
import would have created it:
cvs admin -b1.1.1 add.c
And I moved the "TO_BRIAN" Tag to the latest revision on the Vendor
branch, since that is the base from which further patches would be
created (if I made any):
cvs admin -NTO_BRIAN:1.1.1.3 add.c
Instead of 1.1.1.3, I could have used one of the "Release Tags" last
applied by "import" (3rd through Nth arguments).
Suggestion: Practice on non-essential files.
Last modified: _6/13/1997_
4. What should I avoid when using "admin"?
If you know exactly what you are doing, hack away. But under normal
circumstances:
Never use "admin" to alter branches (using the '-b' option), which CVS
takes very seriously. If you change the default branch, CVS will not
work as expected. If you create new branches without using the "tag
-b" command, you may not be able to treat them as CVS branches.
See 3C.8 for a short discussion of how to use "admin -l" for
serializing access to binary files.
The "admin -o " allows you to delete revisions, usually a bad
idea. You should commit a correction rather than back out a revision.
Outdating a revision is prone to all sorts of problems:
Discarding data is always a bad idea. Unless something in the
revision you just committed is a threat to your job or your life,
(like naming a function "_is_a_dweeb", or including the
combination to the local Mafioso's safe in a C comment), just leave it
there. No one cares about simple mistakes -- just commit a corrected
revision.
The time travel paradoxes you can cause by changing history are not
worth the trouble. Even if CVS can't interfere with your parents'
introduction, it *can* log commits in at least two ways (history and
loginfo). The reports now lie -- the revision referred to in the logs
no longer exists.
If you used "import" to place into CVS, outdating all the
revisions on the Main branch back to and including revision 1.2 (or
worse, 1.1), will produce an invalid CVS file.
If the ,v file only contains revision 1.1 (and the connected
branch revision 1.1.1.1), then the default branch must be set to the
Vendor branch as it was when you first imported the file. Outdating
back through 1.2 doesn't restore the branch setting. Despite the above
admonition against it, "admin -b" is the only way to recover:
cvs admin -b1.1.1
Although you can't outdate a physical (RCS) branch point without
removing the whole branch, you *can* outdate a revision referred to by
a magic branch tag. If you do so, you will invalidate the branch.
If you "outdate" a tagged revision, you will invalidate all uses of
the , not just the one on . A tag is supposed to be
attached to a consistent set of files, usually a set built as a unit.
By discarding one of the files in the set, you have destroyed the
utility of the . And it leaves a dangling tag, which points to
nothing.
And even worse, if you commit a revision already tagged, you will
alter what the pointed to without using the "tag" command. For
example, if revision 1.3 has attached to it and you "outdate"
the 1.3 revision, will point to a nonexistent revision. Although
this is annoying, it is nowhere near as much trouble as the problem
that will occur when you commit to this file again, recreating
revision 1.3. The old tag will point to the new revision, a file that
was not in existence when the was applied. And the discrepancy
is nearly undetectable.
If you don't understand the above, you should not use the admin
command at all.
Last modified: _6/13/1997_
5. How do I restrict the "admin" command? The -i flag in the modules file
can restrict commits. What's the equivalent for "admin"?
At this writing, to disable the "admin" command, you will have to
change the program source code, recompile and reinstall.
Last modified: _6/13/1997_
6. I backed out a revision with "admin -o" and committed a replacement. Why
doesn't "update" retrieve the new revision?
CVS is confused because the revision in the ./CVS/Entries file matches
the latest revision in the Repository *and* the timestamp in the
./CVS/Entries file matches your working file. CVS believes that your
file is "up-to-date" and doesn't need to be updated.
You can cause CVS to notice the change by "touch"ing the file.
Unfortunately what CVS will tell you is that you have a "Modified"
file. If you then "commit" the file, you will bypass the normal CVS
check for "up-to-date" and will probably commit the revision that was
originally removed by "admin -o".
Changing a file without changing the revision number confuses CVS no
matter whether you did it by replacing the revision (using "admin -o"
and "commit" or raw RCS commands) or by applying an editor directly to
a Repository (",v") file. Don't do it unless you are absolutely
certain no one has the latest revision of the file checked out.
The best solution to this is to institute a program of deterrent
flogging of abusers of "admin -o".
The "admin" command has other problems." See 3B.4 above.
Last modified: _6/13/1997_
Category: /Commands_/checkout_co_get/
" + "checkout", "co", "get""
1. What is "checkout" for?
To acquire a copy of a module (or set of files) to work on.
All work on files controlled by CVS starts with a "checkout".
Last modified: _6/13/1997_
2. What is the "module" that "checkout" takes on the command line?
It is a name for a directory or a collection of files in the
Repository. It provides a compact name space and the ability to
execute before and after helper functions based on definitions in the
modules file.
See 1D.11.
Last modified: _6/13/1997_
3. Isn't a CVS "checkout" just a bunch of RCS checkouts?
Like much of CVS, a similar RCS concept is used to support a CVS
function. But a CVS checkout is *not* the same as an RCS checkout.
Differences include:
CVS does not lock the files. Others may access them at the same
time.
CVS works best when you provide a name for a collection of files (a
module or a directory) rather than an explicit list of files to work
on.
CVS remembers what revisions you checked out and what branch you are
on, simplifying later commands.
Last modified: _6/13/1997_
4. What's the difference between "update" and "checkout"?
The "checkout" and "update" commands are nearly equivalent in how they
treat individual files. They differ in the following ways:
The "checkout" command always creates a directory, moves into it,
then becomes equivalent to "update -d".
The "update" command does not create directories unless you add the
'-d' option.
"Update" is intended to be executed within a working directory
created by "checkout". It doesn't take a module or directory argument,
but figures out what Repository files to look at by reading the files
in the ./CVS administrative directory.
The two commands generate completely different types of records in
the "history" file.
Last modified: _6/13/1997_
5. Why can't I check out a file from within my working directory?
Though you *can* check out a file, you normally check out a module or
directory. And you normally do it only once at the beginning of a
project.
After the initial "checkout", you can use the "update" command to
retrieve any file you want within the checked-out directory. There is
no need for further "checkout" commands.
If you want to retrieve another module or directory to work on, you
must provide two pathnames: where to find it in the Repository and
where to put it on disk. The "modules" file and your current directory
supply two pieces of naming information. While inside a checked-out
working directory, the CVS administrative information provides most of
the rest.
You should be careful not to confuse CVS with RCS and use "checkout"
in the RCS sense. An RCS "checkout" (which is performed by the RCS
"co" command) is closer to a "cvs update" than to a "cvs checkout".
Last modified: _6/13/1997_
6. How do I avoid dealing with those long relative pathnames?
This question has also been phrased:
How do I avoid all those layers of directories on checkout? or Why do
I have to go to the top of my working directory and checkout some long
pathname to get a file or two?
This type of question occurs only among groups of people who decide
not to use "modules". The answer is to use "modules".
When you hand the "checkout" command a relative pathname rather than a
module name, all directories in the path are created, maintaining the
same directory hierarchy as in the Repository. The same kind of
environment results if you specify a "module" that is really an alias
expanding into a list of relative pathnames rather than a list of
module names.
If you use "module" names, "checkout" creates a single directory by
the name of the module in your current directory. This "module"
directory becomes your working directory.
The "module" concept combines the ability to "name" a collection of
files with the ability to structure the Repository so that consistent
sets of files are checked out together. It is the responsibility of
the Repository Administrators to set up a modules file that describes
the software within the Repository.
Last modified: _6/13/1997_
7. Can I move a checked-out directory? Does CVS remember where it was
checked out?
Yes and Yes.
The ./CVS/Repository file in each working directory contains a
pathname pointing to the matching directory within the Repository. The
pathname is either absolute or relative to $CVSROOT, depending on how
you configured CVS.
When you move a checked-out directory, the CVS administrative files
will move along with it. As long as you don't move the Repository
itself, or alter your $CVSROOT variable, the moved directory will
continue to be usable.
CVS remembers where you checked out the directory in the "history"
file, which can be edited, or even ignored if you don't use the
"working directory" information displayed by the "history" command.
Last modified: _6/13/1997_
8. How can I lock files while I'm working on them the way RCS does?
Until the day arrives of the all-powerful merge tool, there are still
files that must be accessed serially. For those instances, here's a
potential solution:
Install a pre-commit program in the "commitinfo" file to check for
RCS locks. The program "rcslock.pl" performs this function. It can be
found in the contrib directory of the CVS source distribution.
When you want to make a change to a file you know can't be merged,
first use "cvs admin -l" to lock the file. If you can't acquire the
lock, use the standard "locked out" protocol: go talk to the person
holding the lock.
Make sure the pre-commit program prints a message and exits with a
non-zero status if someone besides the user running "commit" has the
file locked. This non-zero exist status will cause the "commit" to
fail cleanly.
Make sure the pre-commit program exits with a zero status if the
file is either unlocked or locked by the user running "commit". The
"cvs commit" command that kicked off the pre-commit program will take
a zero exist status as an OK and checkin the file, which has the
side-effect of unlocking it.
===> The following is opinion and context. Don't read it if you are
looking for a quick fix.
The topic of locking CVS files resurfaces on the network every so
often, producing the same results each time:
The Big Endians:
CVS was designed to avoid locks, using a copy-modify-merge model.
Locking is not necessary and you should take the time to learn the CVS
model which many people find workable. So why not get with the program
and learn how to think the CVS way?
The Little Endians:
The users determine how a tool is to be used, not the designers. We,
the users, have always used locking, our bosses demand locking,
locking is good, locking is God. I don't want to hear any more
lectures on the CVS model. Make locking work.
Any organization making active changes to a source base will
eventually face the need to do parallel development. Parallel
development implies merges. (If you plan to keep separate copies of
everything and never merge, good luck. Tell me who you work for so I
can buy stock in your disk suppliers this year and sell your stock
short next year.)
Merges will never go away. CVS chose to make "merges" stand front and
center as an important, common occurrence in development. It is one
way of looking at things.
For free-format text, the merge paradigm gives you a considerable
amount of freedom. It does take a bit of management, but any project
should be ready to deal with it.
On the other hand, there are many files that can't be merged using
text merge techniques. Straight text merge programs like "diff3" are
guaranteed to fail on executables (with relative branch statements),
files with self-referential counts stored in the file (such as TAGS
files), or files with relative motion statements in them (such as
Frame MIF files, many postscript files). They aren't all binary files.
For these types of files, and many others, there are only two
solutions:
Complex merge tools that are intimately aware of the contents of the
files to be merged. (ClearCase, and probably others, allow you to
define your own "files types" with associated "merge tools".)
Serialization of access to the file. The only technical solution to
the problem of serialization is "locking".
Since you can call a program that offers:
"Which one do you want? A/B?"
a "merge tool", more and more merge tools will appear which can be
hooked into a merge-intensive program like CVS. Think of a bitmap
"merge" tool that displays the bitmaps on the screen and offers a
"paint" interface to allow you to cut and paste, overlay, invert or
fuse the two images such that the result is a "merged" file.
My conclusion is that the need for locking is temporary, awaiting
better technology. For large development groups, locking is not an
alternative to merging for text files.
Last modified: _6/13/1997_
9. What is "checkout -s"? How is it different from "checkout -c"?
The '-c' and '-s' options to "checkout" both cause the modules file to
appear on standard output, but formatted differently.
"checkout -c" lists the modules file alphabetized by the module name.
It also prints all data (including options like '-a' and "-o ")
specified in the modules file.
"checkout -s" lists the modules file sorted by "status" field, then by
module name. The status field was intended to allow you to mark
modules with strings of your choice to get a quick sorted report based
on the data you chose to put in the status fields. I have used it for
priority ("Showstopper", etc as tied into a bug database), for porting
status ("Ported", "Compiled", etc. when porting a large collection of
modules), for "assignee" (the person responsible for maintenance), and
for "test suite" (which automatic test procedure to run for a
particular module).
Last modified: _6/13/1997_
Category: /Commands_/commit_ci_com/
" + "commit", "ci", "com""
1. What is "commit" for?
To store new revisions in the Repository, making them visible to other
users.
Last modified: _6/13/1997_
2. If I edit ten files, do I have to type "commit" ten times?
No. The "commit" command will take multiple filenames, directory names
and relative pathnames on the command line and commit them all with
the same log message. If a file is unchanged, even if it is explicitly
listed on the command line, CVS will skip it.
Like all CVS commands, "commit" will work on the whole directory by
default. Just type "cvs commit" to tell CVS to commit all modified
files (i.e. the files that "update" would display preceded by 'M') in
the current directory and in all sub-directories.
Last modified: _6/13/1997_
3. Explain: cvs commit: Up-to-date check failed for `'
You may not "commit" a file if your BASE revision (i.e. the revision
you last checked out, committed or retrieved via "update") doesn't
match the HEAD revision (i.e the latest revision on your branch,
usually the Main Branch).
In other words, someone committed a revision since you last executed
"checkout", "update" or "commit". You must now execute "update" to
merge the other person's changes into your working file before
"commit" will work. You are thus protected (somewhat) from a common
form of race condition in source control systems, where a checkin of a
minor alteration of a second copy of the same base file obliterates
the changes made in the first.
Normally, the "update" command's auto-merge should be followed by
another round of building and testing before the "commit".
Last modified: _6/13/1997_
4. What happens if two people try to "commit" conflicting changes?
Conflicts can occur only when two developers check out the same
revision of the same file and make changes. The first developer to
commit the file has no chance of seeing the conflict. Only the second
developer runs into it, usually when faced with the "Up-to-date" error
explained in the previous question.
There are two types of conflicts:
When two developers make changes to the same section of code, the
auto-merge caused by "update" will print a 'C' on your terminal and
leave "overlap" markers in the file.
You are expected to examine and clean them up before committing the
file. (That may be obvious to *some* of you, but . . .)
A more difficult problem arises when two developers change different
sections of code, but make calls to, or somehow depend on, the old
version of each other's code.
The auto-merge does the "right" thing, if you view the file as a
series of text lines. But as a program, the two developers have
created a problem for themselves.
This is no different from making cross-referential changes in
*separate* files. CVS can't help you. In a perfect world, you would
each refer to the specification and resolve it independently. In the
real world you have to talk/argue, read code, test and debug until the
combined changes work again.
Welcome to the world of parallel development.
Last modified: _6/13/1997_
5. I committed something and I don't like it. How do I remove it?
Though you *can* use the "admin -o" (synonym: "rcs -o") command to
delete revisions, unless the file you committed is so embarrassing
that the need to eradicate it overrides the need to be careful, you
should just grab an old version of the file ("update -p -r
" might help here) and commit it on top of the offending
revision.
See Section 3B on "admin".
Last modified: _6/13/1997_
6. Explain: cvs commit: sticky tag `V3' for file `X' is not a branch
The message implies two things:
You created your working directory by using "checkout -r V3", or you
recently executed "update -r V3".
The tag named V3 is not a branch tag.
CVS records (i.e. makes "sticky") any "-r " argument handed
to the "checkout" or "update" commands. The is recorded as
the CVS working branch, which is the branch to which "commit" will add
a new revision.
Branch tags are created when you use the -b switch on the "tag" or
"rtag" commands. Branch tags are magic tags that don't create a
physical branch, but merely mark the revision to branch from when the
branch is needed. The first commit to a magic branch creates a
physical branch in the RCS files.
You can commit onto the end of the Main Trunk, if you have no sticky
tag at all, or onto the end of a branch, if you have a sticky branch
tag. But you can't commit a file that has a sticky tag not pointing to
a branch. CVS assumes a sticky Tag or Revision that does not refer to
a branch is attached to the middle of a series of revisions. You can't
squeeze a new revision between two others. Sticky dates also block
commits since they never refer to a branch.
Scenario1:
If you don't want a branch and were just looking at an old revision,
then you can move back to the Main Branch by typing:
cvs update -A {files or dirs, default is '.'}
or you can move to the branch named by:
cvs update -r {files or dirs, default is '.'}
Scenario2:
If you really wanted to be on a branch and made an earlier mistake by
tagging your branch point with a non-branch tag, you can recover by
adding a new branch tag to the old non-branch tag:
cvs rtag -b -r