Files for
git clone
Log | Files | Refs | README | LICENSE

commit 4ee9a13225aef0f985fff8b8cb115340fa0c7509
parent 0bb6374e14cdb9f8ea05fa8d0300e6e2ad00ae9b
Author: Jake Bauer <>
Date:   Wed,  3 May 2023 15:58:10 -0400

Add CVS garden page

Acontent/garden/ | 419+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcontent/garden/ | 2+-
2 files changed, 420 insertions(+), 1 deletion(-)

diff --git a/content/garden/ b/content/garden/ @@ -0,0 +1,419 @@ +Title: CVS +Summary: CVS + +# [%title] + +CVS is the Concurrent Versions System. It is a source control/version +control/revision control system like Git, Mercurial, Fossil, SVN, etc. + +I've written this document both as a reference for myself and as a quick +start guide that can hopefully be useful to others wanting to learn CVS. +Since git is a similar program that many likely already know, I've +written this with comparisons to git's functionality and with the +assumption that the reader is already familiar with revision control +systems. + +For actual documentation, check out the cvs(1) manpage and the +[CVS +book]( + +<ul> + <li><a href="#terminology">Terminology</a></li> + <li><a href="#checking-out-source-code">Checking Out Source Code</a></li> + <li><a href="#committing-changes">Committing Changes</a></li> + <li><a href="#adding-a-new-file-or-directory">Adding a New File or Directory</a></li> + <li><a href="#removing-a-file-or-directory">Removing a File or Directory</a></li> + <li><a href="#renaming-a-file-or-directory">Renaming a File or Directory</a></li> + <li><a href="#updating-your-working-directory">Updating Your Working Directory</a></li> + <li><a href="#resolving-merge-conflicts">Resolving Merge Conflicts</a></li> + <li><a href="#comparing-file-revisions">Comparing File Revisions</a></li> + <li><a href="#reverting-changes">Reverting Changes</a></li> + <li><a href="#creating-tags">Creating Tags</a></li> + <li><a href="#the-.cvsrc-file">The ~/.cvsrc File</a></li> +</ul> + +## Terminology + +CVS works entirely with a client-server model. + +A <b>module</b> is a single project (i.e. a collection of +related files). + +A <b>repository</b> is where a CVS server stores the modules it +manages. Though sometimes this term is used to refer to +a module/project as well. + +You <b>check out</b> a particular module to create a copy of it +on your system, called a <b>working copy</b>. + +When you <b>commit</b> a change, the change gets immediately +reflected in the module stored in the CVS repository. There is +no concept of making a local commit, then pushing that commit to +a remote repository. + +You <b>update</b> your local copy of the source code to bring +down and merge changes in the repository with your local working +copy. This is expected to be done regularly, as CVS will refuse +to commit changes to an older version of a file (similar to how +git won't let you push your changes if the remote contains +commits that you don't have). + +If you're coming from git, a "module" (sometimes also called +a repository or project) is equivalent to a git repository, +a "repository" is equivalent to something like GitHub or +a collection of git repositories, "checking out" is like +cloning, "committing" is mostly the same, and "updating" is like +pulling. + +## Checking Out Source Code + +Create a local working directory `<dir>` of a remote repository: + +``` +cvs -d <remote>:<path_to_cvs_repository> checkout <module> +``` + +For example, to check out a copy of the OpenBSD source: + +``` +cvs -d checkout -P src +``` + +In this case, the `-P` option will mean that if a directory is +empty in the remote repository, it will be pruned (removed) from +your local working copy. You may or may not want this. + +The `-D` flag can also be used to check out a repository as it was at +a specific date and time. For example, this will check out a module as +it was at exactly 17:00 UTC on 2023-04-30: + +``` +cvs checkout -D "2023-04-30 17:00 UTC" +``` + +This flag is also available for the `update`, `diff`, and other +commands. + +You can also have a CVS "server" that simply runs on your local +machine. For example, if you create a `/var/cvs` directory then +run `cvs init` inside of that directory, you will create a CVS +repository. You can then `cvs import` sources to create +a module, or simply `mkdir` a directory. Both must be followed +by `cvs checkout` commands to create working copies of the +module. + +``` +# mkdir /var/cvs # Set permissions/ownership of this directory as required +$ cvs -d /var/cvs init +$ cd myproject +$ cvs -d /var/cvs import myproject vendor_tag release_tag +$ cd .. +$ cvs -d /var/cvs checkout myproject +``` + +Or, for an empty module, you can just + +``` +$ mkdir /var/cvs/myproject +$ cvs -d /var/cvs checkout myproject +``` + +`vendor_tag` and `release_tag` are required by CVS when importing. More +information about these can be found under the book's [Tracking Third +Party +Sources]( +section. Since they don't really matter in this context you can just set +them to something like your username and "start" respectively. + +## Committing Changes + +Committing works similarly to git: you make changes to one or more files +and commit those changes to have them enshrined in the version history +of the repository. + +In CVS, however, there is no additional "push" step to have changes +appear in the remote repository. When you commit your changes, they are +immediately checked in from your working copy to the repository. + +Additionally, revisions are tracked per-file, not per-commit. That is to +say, there is no "commit hash" representing the state of the repository +at a given point in time, there is only specific revisions of individual +files, represented by revision numbers that increase as changes to the +file are made and committed. + +Commits are done like so: + +``` +cvs commit [file(s)] +``` + +If files are specified, only the changes made to those files are +committed. If no files are specified, then cvs will recursively commit +all changed files in the current directory. + +This command will also open your editor for you to type in a commit +message so you can explain your changes. You can use the `-m` flag +followed by a message as a shorthand if your message is not that long: + +``` +cvs commit -m "Made foo use bar instead" foobar.c +``` + +## Adding a New File or Directory + +To add a new file or directory to your repository, use the `cvs +add` command. + +``` +cvs add <file/dir> +``` + +Note that while adding a file will mark it to be added to the module on +next commit, adding a directory happens instantly, without a commit +required. + +Also note that if you want to add a file in a subdirectory to the +module, that subdirectory must already be added to the module. For +example, if I try to add `dir/file` to my module without first adding +`dir`, I get: + +``` +$ cvs add dir/file +cvs add: in directory dir: +cvs [add aborted]: there is no version here; do 'cvs checkout' first +``` + +I must instead do: + +``` +$ cvs add dir +Directory /var/cvs/dir added to the repository +$ cvs add dir/file +cvs add: scheduling file `dir/file' for addition +cvs add: use 'cvs commit' to add this file permanently +``` + +If there are multiple files in a directory, you can also do: + +``` +cvs add dir/* +``` + +to add all of them. + +## Removing a File or Directory + +Similarly, use the `cvs remove` command to remove a file or +directory: + +``` +cvs remove <file/dir> +``` + +CVS will refuse to remove a file from the repository if it still +exists on disk. That means you have to `rm` the file(s) or +directory(s) first, then run the remove command: + +``` +rm file +cvs remove file +``` + +Like with adding, removing a directory from the module does not +require a subsequent commit. + +Things that are removed are sent to the `Attic/` directory on +the repository, which provides a way to recover from accidental +deletion. + +## Renaming a File or Directory + +On many operating systems, renaming a file or directory is +simply a copy operation plus a remove operation—a copy of a file +or directory is made under a new name and the old one is +removed. This is similar in CVS, where a file must be copied +under a new name, the old file must be removed from CVS, and the +new file must be added: + +``` +$ mv file newfile +$ cvs remove file +$ cvs add newfile +$ cvs commit -m "Rename file to newfile" +``` + +For a directory: + +``` +$ mkdir newdir +$ cvs add newdir +$ mv dir/* newdir +$ cd dir +$ cvs rm <files> +$ cd ../newdir +$ cvs add <files> +$ cvs commit -m "Moved dir to newdir" +``` + +This is quite cumbersome for directories. Luckily, it's not +something that is typically done often, and it can be mitigated +by choosing a good layout for your project from the start. + +## Updating Your Working Directory + +Update your local copy of the sources with the latest available +in the remote repo: + +``` +cvs -q update -PAd +``` + +`-q` makes the output quieter, only printing out each file's +status: + +``` +U <path> - New file created in your repository or updated on the remote +P <path> - Like U but a patch containing the changes was sent instead of the entire file +A <path> - File added by you that will be committed to the repository when you next commit +R <path> - Like the above but the file will be removed +M <path> - File has been modified by you. If there were any changes on the remote, they have been merged successfully. +C <path> - File has a conflict that must be fixed before running the next commit +``` + +`-P` tells update to prune (remove) local directories that are +now empty (i.e. the directory no longer contains +revision-controlled files, so get rid of it). + +`-A` makes cvs grab the most up-to-date version of the file, +forgetting any sticky tags or dates you've set. From the +manpage: "If you get a working file using one of the -r, -D, or +-k options, cvs remembers the corresponding tag, date, or kflag +and continues using it on future updates; use the -A option to +make cvs forget these specifications, and retrieve the "head" +version of the file." + +`-d` tells update to create any directories that are missing in +your working copy but which exist in the repository. Without +this, CVS will not pull in any new directories that exist in the +repository but which don't exist in your working copy. + +### Resolving Merge Conflicts + +Conflict resolution looks very much like it does in git. For +example: + +``` +<<<<<<< file +Eve is the best. +======= +Alice is the best. +>>>>>>> 1.2 +``` + +Where the stuff before the `===` divider is your local working +copy and the stuff after is what's in the revision stored in the +remote repository (in this case revision `1.2` of the file). + +## Comparing File Revisions + +This is done with the `diff` command. + +To view the changes you've made to your working copy of a file compared +to the most recent committed revision: + +``` +cvs diff <file> +``` + +The diff command is recursive, so if a directory is specified +then a diff is shown for each changed file underneath that +directory recursively, and if no file is specified then diffs +for all files under the current directory recursively are shown. + +Two specific revisions can be compared by specifying the `-r` +flag: + +``` +cvs diff -r 1.1 -r 1.2 <file> +``` + +If only one `-r` is given, the revision of the current working +copy is used for the other. + +The diff command is also how you can create a changeset that you can +then send to a project's mailing list for review and comment. + +## Reverting Changes + +Reverting changes can be done with the `-j` flag to the `update` +command. In this case, if I have made some changes between +revisions 1.3 and 1.5 of a file that I want to revert (so the +file now goes back to the state it was at revision 1.3), +I would: + +``` +$ cvs update -j1.5 -j1.3 <file> +``` + +Which will create a new revision 1.6 that looks identical to +1.3. This has the effect of maintaining the changes that were +later reverted as part of the history, which are almost always +worth keeping. + +If you want to restore the state of one or more locally modified +files to an unmodified state, you can do that with the `-C` +flag to the `update` command: + +``` +cvs update -C <file> +``` + +This will create a `.#<file>` file which contains the changes +you previously made where `<file>` will now be a clean copy +pulled from the repository. This file can be used to either undo +this operation (i.e. restore your locally modified changes) or +it can just be deleted. + +## Creating Tags + +Tags work similarly in CVS as they do in git: they mark a specific point +in time in the revision history of a repository.The CVS book has some +great ASCII art illustrating how CVS tags work in [its chapter on +tags]( + +Tags can be made like so: + +``` +cvs tag RELEASE_1-0 +``` + +Note that tag names can only consist of alphanumeric characters plus the +dash '-' and underscore '_'. + +Tags can then be used to check out the source code of a module as it was when that tag was made: + +``` +cvs checkout -r RELEASE_1-0 +``` + +Tags can also be used in place of dates or revision numbers with +commands such as `diff` and `update`. + +## The ~/.cvsrc File + +Use this file to specify preferred command line options by +default, so you don't have to type them each time. + +I prefer: + +``` +cvs -q +diff -uNp +update -P +checkout -P +``` + +CVS also has many shorthands for its commands. For example, `up` +instead of `update`, `co` instead of `checkout`, or `ci` instead +of `commit`. + diff --git a/content/garden/ b/content/garden/ @@ -67,7 +67,7 @@ General documents, notes, and other bits and pieces I find valuable. * [Programming Philosophy](programming-philosophy) * [Bad Assumptions Made By User/Profile Systems](user-profile-systems-bad-assumptions) * Programming languages: [C](c), [Clojure](clojure), [Haskell](haskell), [Raku](raku), [LaTeX](latex), [uxn](uxn) -* Tools: [git](git), [Vim](vim), [plan9](plan9), [Make](make) +* Tools: [git](git), [CVS](cvs), [Vim](vim), [plan9](plan9), [Make](make) * Other: [Licenses](software-licenses), [Potential Project Names](project-names) ## 🖥️ System Administration