Last Updated: March 25, 2004 CVS Basics ========== CVS thankgoodness has been pretty stable over the years so most likely these things will still work for you. I'm working off the 1.11.3 manual. Initializing your CVS Tree -------------------------- % cvs -d /usr/local/cvsroot init This puts several administrative files into /usr/local/cvsroot/CVSROOT Administrative Files You Might Care About ----------------------------------------- Note these files you should checkout. When you check them back in they are active immediately. If you write a SCRIPT though that resides in CVSROOT, you have to checkit out, make changes, and then cp the script into CVSROOT for the script to work there. Kinda weird but you get used to it. * CVSROOT/cvswrappers A list of extensions that you can have CVS treat as binaries (-kb) * CVSROOT/loginfo You can specify a checkin script that is run every time CVS is invoked (look below for more info) * CVSROOT/taginfo Same thing as above but the script runs everytime a tag operation is done. Importing a CVS Project ----------------------- * First things first. Setup your environment correctly. For me I have in my ~/.cshrc: setenv CVSROOT /www/cvsroot setenv CVSEDITOR `which vim` % source ~/.cshrc * Yah I'm a VIM kind of guy. I'm going to use a servlet example here. So my directory structure to be imported looks like |-- build.properties |-- build.xml |-- build_sonone.xml |-- build_tomcat.xml |-- docs |-- lib | |-- commons-beanutils.jar | |-- commons-collections.jar | |-- commons-dbcp.jar | |-- commons-digester.jar | |-- commons-fileupload.jar | |-- commons-lang.jar | |-- commons-logging.jar | |-- commons-pool.jar | |-- commons-resources.jar | |-- commons-validator.jar | |-- jakarta-oro-2.0.jar | |-- jdbc2_0-stdext.jar | |-- mm.mysql-2.0.2-bin.jar | `-- struts.jar |-- src | `-- com | `-- oofnet | `-- admin | |-- AdminLoginAction.java | |-- AdminLoginForm.java | |-- ApplicationResources.properties | `-- OofnetAdmin.properties `-- web |-- WEB-INF | |-- app.tld | |-- struts-bean.tld | |-- struts-config.xml | |-- struts-config.xml.old | |-- struts-form.tld | |-- struts-html.tld | |-- struts-logic.tld | |-- struts-nested.tld | |-- struts-template.tld | |-- struts-tiles.tld | |-- struts.tld | |-- web.warContent | |-- web.xml | |-- web.xml.old | `-- webuser.sql |-- login.jsp |-- login2.jsp |-- mailapp.jsp |-- main_menu.jsp `-- styles |-- cream.org `-- oofnet_standard.css: * Notice the .cvsignore file which contains all the files/directories CVS should ignore. It has: build dist build.properties lib Dealing with Binary Files ------------------------- * I actually want to include the binary libaries in lib into the library using the binary mode of CVS. Let's import this project first and then I'll handle that.. # Assume we're at the base of that tree here. # In this context here, webapps_dev/oofnet_admin will make this app to appear in # $CVSROOT/webapps_dev/oofnet_admin # "Oofnet Adminstration App" is the message associated with the app, if # you leave it blank it'll prompt you into your editor for one so put it in. # # oofnet is the "vendor" tag # start is the "release" tag # These tags may or may not be useful to you in a future context. % cvs import -m "Oofnet Administration App" webapps_dev/oofnet_admin oofnet start * Your screen should have just exploded. Time to check out your new app % cd .. % mv oofnet_admin oofnet_admin_old # Remember we put it in webapps_dev/oofnet_admin so now we should be in ../webapps_dev % cd .. % cvs checkout webapps_dev/oofnet_admin * You should now have a working directory in oofnet_admin. Time to handle the binary files in /lib that did not get imported into the repository. # Enter the checked out module % cd oofnet_admin % mkdir lib % cp ../oofnet_admin_old/lib/* ./lib # The key here is -kb flag (which tags the files as binary) % cd lib % cvs add -kb -m "Java Libraries" ./*.jar % cvs commit * That should be it. Checkout webapps/oofnet_admin to see how things worked. Library files should be available. * In this particular example build.properties was not included since it included stuff that would not be applicable to other developers. Make sure you recreate/copy this file from in this case oofnet_admin_old/build.properties. % cp ../oofnet_admin_old/build.properties . Adding Files ------------ * Pretty simple here. After committing you are popped into your editor for your notes as to what changed. % cvs add filename.java % cvs commit Removing Files -------------- * If you look at the tree above there are some files that obviously need to be trashed. /WEB-INF/web.xml.old comes to mind # Remove the file first than invoke cvs remove % cd WEB-INF % rm web.xml.old % cvs remove web.xml.old % cvs commit * You can mess with the files in the cvs tree directly if you want a clean tree. Not recommended. Renaming Files -------------- * Think of it as a file removal and file add so: % mv OldFile.java NewFile.java % cvs remove OldFile.java % cvs add NewFile.java % cvs commit -m "Renamed Oldfile.java to NewFile.java" Oldfile.java % NewFile.java Updating Your Working Directory with change from other developers ----------------------------------------------------------------- * Pray that your fellow developers didn't break anything. # In your working directory % cvs update History ------- * CVS History command. You must create the $CVSROOT/CVSROOT/history to enable this feature. Tracks checkout, commit, rtag, update, release commands. cvs history [-report] [-flags] [-options args] [files] More interesting options: -c Report on each time commit was using -o Report on checked out modules (default) -a Show all users Option Args: -u username Show records for user name -t tag Show records since tag Branching --------- You can retrive a branch by checking it out of the repository fresh or just updating your current checkout. % cvs checkout -r rel-1-0-patches tc Or % cd tc % cvs update -r rel-1-0-patches To find out what branch you are working on: % cvs status -v filename Look for the file named "Sticky tag" - this tells you the branch you are working on. ======================================================================================== CVS Idiocies: loginfo and filenames with spaces http://mail.gnu.org/archive/html/info-cvs/2003-04/msg00267.html There is a mailbot script that handles this here: http://pasky.or.cz/~pasky/dev/cvs/ciabot.pl. On Thu, 24 Apr 2003 Larry Jones wrote: > BackLoop writes: > > > > But there is problem with folders and filenames containing spaces - > > the loginfo substitute parameter %s returns the folder and filelist > > separated by space. Also I tried to capture stdout but there is the > > same- filelist separated by space. > > Any ideas how to resolve this? Maybe there is some patch for CVS which > > adresses the problem? > > The best solution is to not use spaces in file and directory names. > Failing that, a workaround is to use an upsupported character (space is > traditional) in the format string to give you an empty field that you > can key off of. For example, using %{ s } instead of %s would result in > something like: > > "my directory ,my first file, ,my second file," > > Of course, if you also have commas in your file/directory names, that > makes life a bit more interesting. Our users seem to create filenames with every possible character, so I use multiple "unsupported characters" just to lessen the likelihood that a comma in the filename will cause problems. I use a ',' as the unsupported character simply because multiple spaces is harder to see. eg. %{,,,sVv} would send the script something like: baz/foo bar ,,,file 1,1,2,1.3 ,,,file 2,1.1,1.2 ,,,file 3,1.7,1.8 then in perl: ($dir, @files) = split(' ,,,', $filelist); for (@files) { # Don't use split here because filename may contain commas ($filename, $oldrev, $newrev) = (m/(.*),(.*),(.*)/); ... } If your script needs to determine which files were Added, Modified or Removed, then you probably need to use the oldrev %{V} and newrev %{v} format strings as I did above. The reason is because you can't reliably determine if a file was Added/Modified/Removed by looking at STDIN. For example commit 4 files; the first named "file has space" which is a "Modified" file and the next 3 named "file", "has" and "space" which are "Added" files. STDIN to the loginfo script will show something like: Modified Files: file has space Added Files: file has space If you only look at STDIN you can't tell which files were Added and which were Modified. Is "Modified Files" showing "file", "has" and "space" or is it showing "file has space"? To get around this, you can use the %{,,,sVv} format string. The $oldrev for an "Added" file will be "NONE" and the $newrev for a "Removed" file will be "NONE", so: $state = ($oldrev =~ /NONE/i) ? 'A' : (($newrev =~ /NONE/i) ? 'R' : 'M'); --- Backing out changes: % cvs update -j1.28 -j1.27 mozilla/js/rhino/docs/download.html This means, merge changes from version 1.27 to 1.28 (current version) of download.html, Then you gotta commit this change. (Look at bonsai.mozilla.org) --- Forcing a moving of tags Difference between cvs tag -Fb TAGNAME filename (old, deprecated) cvs tag -FBb TAGNAME filename (new for version > 1.11p1) In short instead of using % cvs -Fb TAGNAME filename You should be using: % cvs -FBb TAGNAME filename IMPORTANT: DO NOT omit the lower case b. (that stands for branch) YOU MUST HAVE ONE CAPITAL B and ONE small b. IF you OMIT THE lower case b YOU WILL CHANGE TAGNAME from a BRANCH to a TAG in that directory. THIS IS VERY VERY BAD. So here's an simple example that I just did for Vinnie: ---------------------------------------------------------------------- [135]% mkdir temp_mars [136]% cd temp_mars [138]% cvs co clients2/echo/osx/src/CEchoDiskCreator.m U clients2/echo/osx/src/CEchoDiskCreator.m [141]% cd clients2/echo/osx/src/ [143]% cvs status CEchoDiskCreator.m =================================================================== File: CEchoDiskCreator.m Status: Up-to-date Working revision: 1.23 Repository revision: 1.23 /pgpsrc/clients2/echo/osx/src/CEchoDiskCreator.m,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) [144]% cvs tag -FBb TAGNAME CEchoDiskCreator.m T CEchoDiskCreator.m (You know the tagging worked when you get that T prefix) ---------------------------------------------------------------------- Sanity Check: [146]% mkdir TAGNAME [147]% cd TAGNAME/ [148]% cvs co -r TAGNAME clients2/echo/osx/src/CEchoDiskCreator.m U clients2/echo/osx/src/CEchoDiskCreator.m [149]% cd clients2/echo/osx/src/ [150]% cvs status CEchoDiskCreator.m =================================================================== File: CEchoDiskCreator.m Status: Up-to-date Working revision: 1.23 Repository revision: 1.23 /pgpsrc/clients2/echo/osx/src/CEchoDiskCreator.m,v Sticky Tag: TAGNAME (branch: 1.23.2) Sticky Date: (none) Sticky Options: (none) ---------------------------------------------------------------------- For Reference: (http://lists.gnu.org/archive/html/info-cvs/2002-05/msg00363.html) ---------------------------------------------------------------------- CVS Security: cvs admin commands are controlled by the unix group cvsadmin Only people in those group can use cvs admin commands (Refer to the CVS admin portion of the manual - pg 93) (Security spiel below): There are three attacks in particular that I would be concerned with. An attacker who can get access to the repository can trash it any way he or she likes. For this reason, I recommend having a separate server with limited login access. An attacker who can execute "cvs admin" commands can effectively destroy the files in the repository. For this reason, I recommend limiting the ability to use "cvs admin" to administrators, which is accomplished by creating the Unix group "cvsadmin" on the server and restricting it to the administrators. An attacker who can manipulate files in CVSROOT can cause other people to execute arbitrary programs without realizing it, potentially trashing the repository. For this reason, I recommend restricting access to CVSROOT to administrators. This can be done by assigning CVSROOT to the "cvsadmin" group and removing all permissions other than owner and group. http://www.thornleyware.com/scm/cvsconfig/security.html ---------------------------------------------------------------------- How do I list all changed files between 2 dates or tags in CVS? % cvs rlog -Q rlog -N -rTAG_ONE::TAG_TWO modules_list Anything with selected revisions > 1 represents a changed file ---------------------------------------------------------------------- Trying adding a file or commiting and getting a "hash.c :312 Assert failed Key != NULL" This can be caused if you have a case insensitive operating system. To fix this go into CVS and remove the offending file (it may very well be in the Attic so check there as well) and readd the file. As CVS IS case sensitive it'll freak out as it seems like you are trying to add an existing file - but the error only shows up on commit (frustratingly enough). "Hi, We are getting this error "hash.c :312 Assert failed Key != NULL" When we are trying to re-add a file in right "Case" which was removed from CVS using "cvs remove" from NT which off course is not case sensitive. The story is that file was initially added on the branch and never got added to the trunck but CVS automatically adds version 1.1 on the trunk anyway then file was removed "using cvs remove " because it was in the wrong "case" ( say file.txt) when we tired to readd it using "cvs add" with the right "Case" ( say File.txt) we started getting following error Assertion failed: *rcsnode == NULL, We found out from the list that there is bug and hence renamed the file to "file.txt.old' and then tried to add it again but then we got " ---------------------------------------------------------------------- http://lists.gnu.org/archive/html/info-cvs/2000-12/msg00134.html Re: Is it possible to change a branch tag name? From: Stephen Rasku Subject: Re: Is it possible to change a branch tag name? Date: Wed, 6 Dec 2000 10:07:58 -0800 (PST) -------------------------------------------------------------------------------- John Dunning wrote: > >One of the folks in my group has decided he wants to change the name >of a branch tag, after having done some amount of changing of files on >that branch. I'd never heard of a way to do that, and a scan of the >docs doesn't reveal anything that looks like a facility for doing >that, but I figured it was worth asking the list: Is there a way to >change the name of an existing branch tag? > Yes. Do: cvs admin -nnew-branch-name:old-branch-name cvs tag -d old-branch-name -------------------------------------------------------------------------------- How do I add a directory tree without using `cvs import'? Better to use: find . ! -name CVS -type d -exec cvs add {} \; cvs ci find . ! -path '*/CVS/*' ! -type d -exec cvs add {} \; Why: if you don't add directories first, then when you go to add files there will be no CVS metadata for them, most importantly the CVS root. So, add all the directories first. Then, check the tree in. Last, add all the files, but not anything in a CVS directory. The first command excludes directories named CVS. Otherwise, you will get an infinite loop, by making a CVS directory in your current target, then descending into it and trying to add that directory to CVS, which makes a CVS directory in that directory. - Vinny -------------------------------------------------------------------------------- Rolling back the repository based on a date Here is what you need to do if you want to revert the changes in you repository back two days: 1. Check out the HEAD cvs co module or cvs up 2. Create a tag based on the date, you could also create a remote tag if you want the rest of the world to know about it. The -D can be any date format that CVS will reconize. cvs tag -D "2 days ago" two_days_ago or cvs rtag -D "2 days ago" two_days_ago 3. Clear the sticky bits. cvs up -A 4. Do the reverse join. cvs up -j HEAD -j two_days_ago 5. Update after you do the join. cvs up 6. Commit the changes. cvs ci -------------------------------------------------------------------------------- 4.1 Using Update cvs update -j TagOrBranch1 -j TagOrBranch2 my_module The above command will locate the differences between TagOrBranch1 and TagOrBranch2. Of the lines that are different between them, the lines in TagOrBranch2 will be patched, or merged, into the sources in your working directory. An annoying problem that I have not yet solved is that new files that appear in TagOrBranch2 but not in TagOrBranch1 do not get created by the merge. The only thing I know of to get these files into the new version is to checkout TagOrBranch2, copy the files into the merged working directory, and do cvs add filename 4.2 Using Checkout cvs checkout -j TagOrBranch1 -j TagOrBranch2 my_module The above command will locate the differences between TagOrBranch1 and TagOrBranch2. Of the lines that are different between them, the lines in TagOrBranch2 will be patched, or merged, into the latest revision on the main trunk of my_module. In order to have these differences merged into a different branch, and then have that branch checked out, use cvs checkout -r BranchToMergeTo -j TagOrBranch1 -j TagOrBranch2 my_module Like update, file that were created between TagOrBranch1 and TagOrBranch2 do not get created automatically. -------------------------------------------------------------------------------- Checkout list -> Useful for those scripts you have in CVSROOT: cvs co CVSROOT * edit checkoutlist # comment lines begin with '#' checkin-mailer.pl "Can't check out checkin-mailer.pl!" log_tags_mailer.pl "Can't check out log_tags_mailer.pl!" -------------------------------------------------------------------------------- UTF-8 or UTF16 files. * Should be checked into repository as binary -kb * http://www.cvsnt.org/pipermail/cvsnt/2005-January/016705.html