Different modifications
of a project are kept track of by CVS in the form
of revisions. This means that if you want to
back up to an older version of your software you can
do so without too much grief.
Different versions of a project are called the
revision numbers of that project. They typically look like
1.1, 1.2. Nothing too magical.
CVS also allows us to branch off of our revision tree
and develop older revisions without affecting newer ones.
We won't be going over that.
setenv CVSROOT /home/cs300/CVSstuff
setenv CVS_RSH "ssh"
and then either log out or
source ~/.cshrcNow activate CVS by issuing cvs init at the command line.
UNIX% cvs initYou should be able to cd to your repository now. It will be a blank directory except for a directory named CVSROOT which contains various administrative files:
UNIX% printenv CVSROOT /home/cs300/CVSstuff UNIX% cvs init UNIX% cd $CVSROOT cs300/CVSstuff% ls CVSROOT/
cs300/pub/project1% cat > textfile
Knight Rider was a funny movie, but somehow I liked Herby better as a car!! cs300/pub/project1% ls textfile cs300/pub/project1% pwd /home/cs300/pub/project1Now maybe you think otherwise!! Say you want to discuss this important issue and I decide the best thing to do would be to put the directory into the repository.
How to do that ??? - By using the magic term : cvs import
cd to the project directory, then cvs import -m "project comments" <project-Name>
vendor-tag release-tags cs300/pub/project1% cvs import -m "new project" proj1 v1 r1 N proj1/textfile No conflicts created by this importI have created a new module in our repository named proj1. The -m switch is for a log message that is required by CVS. If you don't put one on the command line CVS will drop you into whatever editor you have specified with your EDITOR environmental variable. This is most annoying. I always go ahead and specify a message using -m. Don't worry about the last two arguments. I don't think CVS does either.
cs300/pub/project1% cd ..;rm project1 cs300/pub% cvs checkout proj1 cvs checkout: Updating proj1 U proj1/textfileWe are working from a copy from our repository. The directory proj1 looks the same as the old one with the addition of a CVS directory for the version control system. You can examine these:
cs300/pub/proj1% cd CVS cs300/pub/proj1/CVS% ls Entries Repository Root cs300/pub/proj1/CVS% cat Repository proj1 cs300/pub/proj1/CVS% cat Root /home/cs300/CVSstuff cs300/pub/proj1/CVS% cat Entries /textfile/1.1.1.1/Tue Aug 29 05:27:30 2000// DFYI:
cs300/pub/proj1% cat >> textfile A shadowy flight into the dangerous world of a man who does not exist! cs300/pub/proj1% cp -r /home/cs300/www-home/prg/cq . cs300/pub/proj1% ls cq/ CVS/ textfile cs300/pub/proj1% touch newfileNow at this point CVS has no idea what I have done. Until I make these changes known to the repository they aren't official. They'll just be present in my local copy. We have to make CVS aware of these changes. First lets take care of the change to textfile. :
cs300/pub/proj1% cvs commit -m "Added line two!!" cvs commit -m "Added line two touch newfile" cvs commit: Examining . Checking in textfile; /home/cs300/CVSstuff/proj1/textfile,v <-- textfile new revision: 1.2; previous revision: 1.1 done cs300/pub/proj1% cvs add newfile cvs add: scheduling file `newfile' for addition cvs add: use 'cvs commit' to add this file permanently cs300/pub/proj1% cvs add cq Directory /home/cs300/CVSstuff/proj1/cq added to the repository cs300/pub/proj1% ls cq bad.c* cq.h* histo.c* int* makefile* cq.c* CVS/ index.html* int.c* qcat.c*Notice that CVS added a directory named CVS within the cq directory. CVS will place a CVS directory with the administrative files in each directory within a project. Go ahead and commit again:
cs300/pub/proj1% cvs commit -m "added a file and a directory" cvs commit: Examining . cvs commit: Examining cq RCS file: /home/cs300/CVSstuff/proj1/newfile,v done Checking in newfile; /home/cs300/CVSstuff/proj1/newfile,v <-- newfile initial revision: 1.1 doneNow erase the directory and check out the module again. This will be our working copy of the project (or module, I'll use both terms) that is stored in the project.
cs300/pub% rm proj1 cs300/pub% cvs checkout proj1 cvs checkout: Updating proj1 U proj1/newfile U proj1/textfile cvs checkout: Updating proj1/cq cs300/pub% ls proj1 cq/ CVS/ newfile textfile cs300/pub% cat proj1/testfile cs300/pub% cat proj1/textfile Knight Rider A shadowy flight into the dangerous world of a man who does not existWe have a problem however. Examine the contents of the cq directory:
cs300/proj1% ls cq/ CVS/ newfile textfile cs300/proj1% ls cq CVS/So where did the files go?
cs300/proj1% cvs remove cq cvs remove: Removing cq cs300/proj1% rm cq cs300/proj1% !cp cp -r /home/cs300/www-home/prg/cq . cs300/proj1% cvs add cq Directory /home/cs300/CVSstuff/proj1/cq added to the repository cs300/proj1/cq% foreach file (`ls`) foreach? cvs add $file foreach? end cvs add: scheduling file `calculate.c' for addition cvs add: use 'cvs commit' to add this file permanently cvs add: scheduling file `day-number.c' for addition cvs add: use 'cvs commit' to add this file permanently cvs add: scheduling file `find_max.c' for addition cvs add: use 'cvs commit' to add this file permanently cvs add: cannot add special file `CVS'; skipping cvs add: scheduling file `histo.c' for addition cvs add: use 'cvs commit' to add this file permanently cs300/proj1/cq% cd ..;cvs commit -m "Added the directory AND the files I hope"Now let's delete our working copy and check out another one and see if the directory contains all of the files it needs to:
cs300/proj1% cd .. cs300% rm proj1 cs300% cvs checkout !:1 cvs checkout proj1 cvs checkout: Updating proj1 U proj1/newfile U proj1/textfile cvs checkout: Updating proj1/cq U proj1/cq/calculate.c U proj1/cq/day-number.c U proj1/cq/find_max.c U proj1/cq/histo.c
Now to verify:
cs300% cd proj1 cs300/proj1% ls cq
CVS/ calculate.c* day-number.c* find_max.c* histo.c*So everything is there, and the only main difference seems to be the CVS directory inside the cq directory. Some of you may wonder what the line cvs checkout !:1 does. The csh has a history function that remembers previous commands and allows you to repeat previous commands or portions of previous commands. History manipulation is a very powerful tool, and hopefully we'll go over it in more detail in a later class. I just wanted to throw it in there so you could have something to mull over.
cs300/proj1/cq% cvs diff histo.c Index: histo.c =================================================================== RCS file: /home/cs300/CVSstuff/proj1/cq/histo.c,v retrieving revision 1.1 diff -r1.1 histo.c 37a38 > /* adding a comment at the end of histo.c */As you can imagine the output from cvs diff can get pretty huge, which is why I modified 1 file and gave cvs diff instructions to only search for that one file (it defaults to ., as most other CVS commands do). You'll periodically want to do a cvs update to keep yourself in sync with the repository. This command will update your copies of source files from changes that other developers have made to the source in the repository, but doing a cvs update won't wipe out your changes:
cs300/proj1/cq% cvs update . cvs update: Updating . M histo.c cs300/proj1/cq% tail -1 histo.c /* adding a comment at the end of histo.c */ cs300/proj1/cq% cvs diff histo.c Index: histo.c =================================================================== RCS file: /home/cs300/CVSstuff/proj1/cq/histo.c,v retrieving revision 1.1 diff -r1.1 histo.c 37a38 > /* adding a comment at the end of histo.c */So your working copy still has the modified line in it. Now suppose someone else had checked out this same file before you had committed your change i.e. without the extra line at the end of histo.c:
On a separate window:
cs300% mkdir test cs300/test% cvs checkout proj1 cvs checkout: Updating proj1 U proj1/newfile U proj1/textfile cvs checkout: Updating proj1/cq U proj1/cq/histo.c U proj1/cq/calculate.c U proj1/cq/day-number.c U proj1/cq/find_max.c cs300/test% cd proj1/cq cs300/test/proj1/cq% cat >> histo.c /* Adding a comment and preparing to cause a conflict !! */ cs300/test/proj1/cq% cvs commit -m "conflict!!" cvs commit -m "conflict!" cvs commit: Examining . Checking in histo.c; /home/cs300/CVSstuff/proj1/cq/histo.c,v <-- histo.c new revision: 1.2; previous revision: 1.1 doneOkay now in my original window I decide that it is time to commit:
cs300/proj1/cq% cvs commit histo.c cvs commit: file `histo.c' had a conflict and has not been modified cvs [commit aborted]: correct above errors first!I'll need to update to check and see what has been goofed around in my program. At this point CVS will try to merge the conflicts. Remember that the two lines were entered in the same location so when CVS did a line-by-line check it detected the errors:
cs300/proj1/cq% cvs update histo.c RCS file: /home/cs300/CVSstuff/proj1/cq/histo.c,v retrieving revision 1.1 retrieving revision 1.2 Merging differences between 1.1 and 1.2 into histo.c rcsmerge: warning: conflicts during merge cvs update: conflicts found in histo.c C histo.c
Now I already know that the conflict exists toward the end of the file so I can just examine the end of histo.c:
cs300/proj1/cq% tail -7 histo.c } <<<<<<< histo.c /* adding a comment at the end of histo.c */ ======= /* Adding a comment and preparing to cause a conflict !! */ >>>>>>> 1.2The conflicts are denoted by the <<<<<<< and >>>>>>> markers. The second set of markers denotes the version that exists in the repository and the revision number while the line that is in my working copy of histo.c appears first. The way to resolve such conflicts is to edit the files, take out the conflicts, and re-commit. When working with a group of people on a project all of those involved will want to periodically cvs update and cvs commit to keep conflicts to a minimum. CVS will not allow you to check in a file for which an unresolved conflict exists.
cs300/proj1/cq% cvs status histo.c =================================================================== File: histo.c Status: File had conflicts on merge Working revision: 1.2 Result of merge Repository revision: 1.2 /home/cs300/CVSstuff/proj1/cq/histo.c,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none)CVS tells us that the file histo.c is the result of a merge and that there were conflicts. Now let's fix it by removing the delimiters and the comments that we don't want, commit our copy, and check the status:
cs300/proj1/cq% tail -2 histo.c } /* All comments removed */ cs300/proj1/cq% cvs commit -m "went ahead and removed both of the comments" cvs commit: Examining . Checking in histo.c; /home/cs300/CVSstuff/proj1/cq/histo.c,v <-- histo.c new revision: 1.3; previous revision: 1.2 done cs300/proj1/cq% cvs status histo.c =================================================================== File: histo.c
Status: Up-to-date Working revision: 1.3 Wed Sep 13 14:19:09 2000 Repository revision: 1.3 /home/cs300/CVSstuff/proj1/cq/histo.c,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none)
cs300/proj1/cq% pwd /home/cs300/proj1/cq cs300/proj1/cq% cvs remove index.html cvs remove: file `index.html' still in working directory cvs remove: 1 file exists; remove it first cs300/proj1/cq% rm index.html cs300/proj1/cq% cvs remove index.html cvs remove: scheduling `index.html' for removal cvs remove: use 'cvs commit' to remove this file permanently cs300/proj1/cq% cvs commit -m "removed cq/index.html" cvs commit: Examining . cvs commit: Committing . Removing index.html; /home/cs300/CVSstuff/proj1/cq/index.html,v <-- index.html new revision: delete; previous revision: 1.1 doneNotice in my example that first I tried to (incorrectly) cvs remove before I actually removed the file using rm and got an error message.
cs300/proj1/cq% ls CVS/ calculate.c* day-number.c* find_max.c* histo.c*
cs300/proj1/cq% rm histo.c cs300/proj1/cq% cvs remove histo.c cvs remove: scheduling `histo.c' for removal cvs remove: use 'cvs commit' to remove this file permanently cs300/proj1/cq% cvs add histo.c U histo.c cvs add: histo.c, version 1.3, resurrected cs300/proj1/cq% ls CVS/ calculate.c* day-number.c* find_max.c* histo.c*
The file was resurrected. If you had caught the mistake before executing cvs remove then you could have just used cvs update:
cs300/proj1/cq% rm histo.c cs300/proj1/cq% cvs update cvs update: Updating . cvs update: warning: histo.c was lost U histo.c cs300/proj1/cq% ls CVS/ calculate.c* day-number.c* find_max.c* histo.c*
cs300/proj1/cq% rm *.c *.h int* makefile mv: cannot access int.c cs300/proj1/cq% ls cs300/proj1/cq% cvs remove cvs remove: Removing . cvs remove: use 'cvs commit' to remove these files permanently cs300/proj1/cq% cvs commit -m "removed the files in the cq directory" cvs commit: Examining . cvs commit: Committing . ...
Now just use cvs update with the -d (for directory) and -P (for "prune") options:
cs300/proj1/cq% cd .. cs300/proj1% ls CVS/ cq/ newfile textfile cs300/proj1% cvs update -dP cvs update: Updating . cvs update: Updating cq cs300/proj1% ls CVS/ newfile textfile
cs300/proj1% mkdir pinger cs300/proj1% cd pinger cs300/proj1% cp /jade/homes/cs300/pub/pinger/* . cs300/proj1% cvs add pinger Directory /home/cs300/CVSstuff/proj1/pinger added to the repositoryNow I used my foreach statement from above to add all of the files into the repository and did a cvs commit. Now we want to rename the directory pinger to something else. Just mv the files over to a new directory, do a cvs update -dP to clear the old directory out of your working copy, , and add the files in the new directory using cvs add and cvs commit. Working with directories and CVS can get convoluted very quickly, but thats just how things are.
cs300/newmod% ls CVS/ index.html* cs300/newmod% cat >> index.html <howdy></howdy> cs300/newmod% cvs commit -m " modified the index file " cvs commit: Examining . cvs commit: Committing . Checking in index.html; /home/cs300/CVSstuff/newmod/index.html,v <-- index.html new revision: 1.2; previous revision: 1.1 doneNow suppose that I wanted to get a look at the old copy:
cs300/newmod% rm index.html cs300/newmod% cvs update -r 1.1 index.html cs300/newmod% tail -1 index.html </HTML>So perhaps this wasn't a very useful example, but apply this to programming projects. If you're trying to do a program in incremental steps and you goof up the current version then if you use CVS you can easily back up to a previous version. Now if I want to go back to the most recent copy:
cs300/newmod% cvs update -A cvs update: Updating . U index.html cs300/newmod% tail -1 index.html <howdy></howdy>When I checked out the file with the lower revision it got checked out with something called a "sticky tag" that basically set the current version of the index.html file to 1.1 as far as my working copy was concerned even though the repository had a more recent copy (1.2). The cvs update -A was required to get back into the repository and check out the most recent version. If I hadn't used it CVS would have continually checked out the old revision instead of the new one when I tried to update.
cs300/newmod% cvs status index.html =================================================================== File: index.html Status: Up-to-date Working revision: 1.2 Wed Sep 13 17:48:03 2000 Repository revision: 1.2 /home/cs300/CVSstuff/newmod/index.html,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) cs300/newmod% cvs update -j 1.2 -j 1.1 index.html cvs update: warning: index.html was lost U index.html RCS file: /home/cs300/CVSstuff/newmod/index.html,v retrieving revision 1.2 retrieving revision 1.1 Merging differences between 1.2 and 1.1 into index.htmlNow check to see that the revision made in 1.2 is gone:
cs300/newmod% tail -1 index.html </HTML>And notice that the status has set the revision as 1.2:
cs300/newmod% cvs status index.html =================================================================== File: index.html Status: Up-to-date Working revision: 1.2 Wed Sep 13 17:55:22 2000 Repository revision: 1.2 /home/cs300/CVSstuff/newmod/index.html,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none)There is also a way of "tagging" an entire directory with a "release number" using cvs tag version_number to tag the files in a directory and cvs checkout -r version_number module to retrieve the files. I never do this, and thus won't spend any more time on it.
$Id$ $Date$ $Author$ $Revision$Which are the following:
cs300/newmod% head -10 index.html $Id: index.html,v 1.3 2000/09/13 18:10:12 cs300 Exp $ $Date: 2000/09/13 18:10:12 $ $Author: cs300 $ $Revision: 1.3 $ Revision 1.3 2000/09/13 18:10:12 cs300 sdf
cs300/newmod% cvs log cvs log: Logging . RCS file: /home/cs300/CVSstuff/newmod/index.html,v Working file: index.html head: 1.3 branch: locks: strict access list: symbolic names: version_whatever: 1.2 v1: 1.1.1.1 r1: 1.1.1 keyword substitution: kv total revisions: 4; selected revisions: 4 description: ---------------------------- revision 1.3 date: 2000/09/13 18:10:12; author: cs300; state: Exp; lines: +5 -0 sdf ---------------------------- revision 1.2 date: 2000/09/13 17:42:35; author: cs300; state: Exp; lines: +1 -0 modified the index file ---------------------------- revision 1.1 date: 2000/09/13 17:40:52; author: cs300; state: Exp; branches: 1.1.1; Initial revision ---------------------------- revision 1.1.1.1 date: 2000/09/13 17:40:52; author: cs300; state: Exp; lines: +0 -0 creating a new module =============================================================================This can be handy if you are thinking about backing up a revision or two and are interested in checking out things such as old log messages or checking when the files were modified.
setenv CVSROOT ext:joeuser@larry.cas.utk.edu:/home/cs300/reposThe other side has to be set up to accept connections. Two of the modifications require root access because you have to muck around with inetd.conf and /etc/services. I definitely won't be going into all of that, but I did want to make you aware that CVS has this capability.