Kurt Schwehr -- May 2003 Quick CVS Tutorial Revision Control using CVS (Concurrent Version System) $Id: $ INTRO: This document will try to guide you through the basics of using CVS. It will use the GDC systems as a starting point. You don't need to know too much to get started using cvs, but you can learn endless amounts more as you become more experienced with it. To go into greater detail on CVS, you can use some of these resources. Take a look at them after you do the tutorial. http://www.cvshome.org/ emacs M-x info C-s cvs info emacs man cvs NOTES: * man pages for GNU software are not always that up to date * emacs does not seem to have all the info pages installed on gdcultra I suggest trying a computer with a recent version of linux on it for this. * info is not installed on gdcultra I suggest trying a computer with a recent version of linux on it for this. PREPARING A CVS MASTER (Just look at this section, don't do anything) YOU CAN SKIP THIS SECTION. This is how I setup the CVS master database on gdcultra. This is only done once to get things rolling. cvs -d /net/gdcspm/schwehr/test/Master init Now we'll add one module named "gdcscripts" with one script in it using the "import" command to bring in an existing script named seambeamsearch. You only use import very rarely. Usually you use "add" mkdir tmp cd tmp cp /GDC/bin/DOsbf1line.search seabeamsearch.csh emacs seabeamsearch.csh chmod +x seabeamsearch.csh export CVSROOT=/net/gdcspm/schwehr/test/Master cvs import gdcscripts schwehr start cd .. cvs get gdcscripts WORKING WITH CVS USING THE COMMAND LINE Now, I'll go through the basic CVS commands that you'll use commonly when doing a lot of CVS work. Make sure that you have write access to the CVS Master database or CVS will not be to work. This example will start you off from scratch in you own directory using an existing CVS repository. NOTE: CVS has a lot of terms for the same thing. It takes a little time to get used to this. An example is that "get" and "checkout" are the exact same thing. (Will change this to point to the GDC CVS Master when it is set up) Let's get started checking out the files that we'll be working with and editing. A note on format of this document... I will indent commands a couple spaces. Comments that you don't type will be everything that follows a "#" and includes the "#". Sample outout will be after ">" # Login and setup # This is a comment. Use ssh, telnet gives your password to the bad guys ssh gdcultra.ucsd.edu bash # I will use bash. csh drives me nuts export CVSROOT=~schwehr/test/Master # Can put this in your .bashrc cd mkdir tmp cd tmp ls -l # Notice that the directory is empty cvs get gdcscripts > cvs checkout: Updating gdcscripts > U gdcscripts/seabeamsearch.csh ls -l # Now there is a directory named gdcscripts You now have a directory named gdcscripts with a file in it named seabeamsearch.csh. You do not have to checkout (aka get) files everytime you want to work with them. CVS keeps info about the files in a directory near the files as you will see soon. Let's add a file to the repository. cd gdcscripts emacs $USER.txt # use the text editor of choice. I like emacs # Put a line or two of text in it. # or you can do this # These three lines are nifty unix trick cat << EOF > $USER.txt This is a sample file to put into CVS EOF unset EDITOR # I don't like to get put into vi export EDITOR=emacs # I don't like to get put into vi cvs add $USER.txt # Now a file with your name is in cvs cvs commit $USER.txt # Type in a comment for the log cvs status $USER.txt # This will tell you about the file > =================================================================== > File: schwehr.txt Status: Up-to-date > > Working revision: 1.1 Tue Sep 18 23:14:14 2001 > Repository revision: 1.1 /net/gdcspm/schwehr/test/Master/gdcscripts/schwehr.txt,v > Sticky Tag: (none) > Sticky Date: (none) > Sticky Options: (none) We have a file now that we can work on to try out some features of cvs and learn how we will deal with day to day editing of files. DAY-TO-DAY FILE EDITING Let's start by putting some informational stuff in our file so that when we edit it, we will have a sense of what changes have been made. The $Id$ tag gets replaced with version number, author, and some other stuff. The $Log$ tells cvs that we want the log to also be put into the file less $USER.txt # Before cat << EOF >> $USER.txt \$Id\$ \$Log\$ EOF less $USER.txt # After We are now going to inspect and commit this change to our file. Be very careful about checking in files. If you make a mistake, someone may come find you and ask you why you did whatever it is you did. cvs status $USER.txt > File: schwehr.txt Status: Locally Modified cvs diff $USER.txt > Index: schwehr.txt > =================================================================== > RCS file: /net/gdcspm/schwehr/test/Master/gdcscripts/schwehr.txt,v > retrieving revision 1.1 > diff -r1.1 schwehr.txt > 1a2,3 > > $Id$ > > $Log$ It looks like we made the changes we wanted. So lets commit them so that others can get our latest version. cvs commit $USER.txt Added log and id tags to the file less $USER.txt # notice that CVS has replaced Id and Log # with information about the file. cvs log $USER.txt > head: 1.2 > ---------------------------- > revision 1.2 > date: 2001/09/18 23:30:14; author: schwehr; state: Exp; lines: +2 -0 > Added log and id tags to the file > ---------------------------- > revision 1.1 > date: 2001/09/18 23:15:59; author: schwehr; state: Exp; > This is a first entry in the log There is just one more basic command that you'll need to know right off. That is the update command. Update tries to bring files up to the latest version. This will get additions and fixes from other users. If you've modified a file that someone else has checked in additions since you last updated, cvs will try to merge the changes with yours. See elsewhere what to do if cvs finds a conflict between your changes and those of another user. Try running update. You should run this often (like at the start of each day that you modify files in cvs). cvs update This is just a quick tutorial. You'll need to read further in the manuals and ask people as you encounter more concepts with CVS. It is very powerful and as good as most revision control systems that any mear mortal could afford. ClearCase is just too expensive and complicated to be worth it. And yes, you can use cvs from MS-Windows, just don't ask me to show you. FURTHER STUFF (TODO) * How to use CVS remotely. You can use ssh to checkout stuff on other computers. This involves setting up your CVSROOT and CVSRSH environment variables. * How to use CVS from emacs. Emacs has pretty good support for editing files that are under CVS control. Just start editing the file. When you want to check in a file, you can do "control-x v v" or in emacs speak "C-x v v". It will then pop up another window that you type the log comments in. Then when you're done, type "C-c C-c" in the log window and you're changes are checked in. Super easy. CVS catch phrases: "update frequently and often" "Use cvs from within emacs... you're life will be better C-x v v" "Please do not write essays in the log comments" "Try to check in changes on a regular basis... big diffs are painful" "How do you use branches? Painfully." "You can check in binary files, but rarely is it a good idea." ---------------------------------------------------------------------- For Dave M's request... Now that you have a cvs tree, what do you put in it and how do you build software across multiple computers. There are MANY ways to do this. Here is a recommended strategy that I've developed over the last 10 years. It is not the world's best, but sometime GNU autoconf, automake, and libtool get confusing. In your CVS tree you create a structure like this: ${TOPDIR}/doc/ ${TOPDIR}/include/ ${TOPDIR}/bin/ ${TOPDIR}/bin/`uname`-`uname -r` ${TOPDIR}/lib/ ${TOPDIR}/lib/`uname`-`uname -r` ${TOPDIR}/src/ ${TOPDIR}/src/Makes/ ${TOPDIR}/src/Makefile Then in the rest of source, try to break groups of source code into directories that can produce a library and some headers. The local makefile should be setup to build the library and install everything. The library goes into ${TOPDIR}/lib/`uname`-`uname -r` and the header goes into ${TOPDIR}/include/. The only problem with the above is on Linux where `uname -r` returns 2.4.0, 2.4.1, 2.4.2, which are pretty similiar. The minor and minor.minor numbers have little bearing on compatibility, which is often dependent on gcc version and glibc version. As of summer 2003, make sure you always build with gcc-3.x. gcc-2.x.x are NOT compatible with gcc-3.x... well they might be for straight C code, but not for C++ or Fortran. So you need to build a makefile structure. Here is a sample top level Makefile: #!gmake # Tell emacs it is a -*- Makefile -*- # # FILE: Makefile # Makefile for all subdirectories in PROJECT_NAME/src # # REQUIREMENTS: # Gnu make (gmake) # makedepend # makeheader # # USAGE: # # type "make" for usage # # BUGS: # # Bugs? What bugs? We only have features here. # # REVISION HISTORY: # $Id: Makefile,v 1.18 2000/02/29 20:55:32 nguyen Exp $ # 02-Mar-1997 Kurt Schwehr. Copy Dan Christian's Makefile for Marsokhod. # 17-Oct-1997 Kurt Schwehr. Copied from pathfinder project. # # $Log: Makefile,v $ # There have been many revisions. # #------------------------------------------------------------------------------ # several rules rely on borne shell syntax/abilities # Alternatively use /bin/bash. Do NOT use csh or tcsh! SHELL=/bin/sh ############################################################################## # Determine what operating system we are trying to build for # Override on command line for cross compilation (e.g. OS_SYSNAME=m68kVx) OS_SYSNAME := $(shell uname -s) OS_RELEASE := $(shell uname -r) # Assume that we are not building 64 bit binaries. ifeq ($(OS_SYSNAME),IRIX64) OS_SYSNAME := IRIX endif # FIX: handle linux numbers OS := $(OS_SYSNAME)-$(OS_RELEASE) ############################################################################## ################ # keep install directories relative if possible TOPDIR=.. INCDIR=$(TOPDIR)/include LIBDIR=$(TOPDIR)/lib BINDIR=$(TOPDIR)/bin # Unix Group GRP := some group # COM - Common across platforms. COMDIRS := # Put in order that they they should be built in. UNIXDIRS := \ Dir1 \ Dir2 PYDIRS := PyUtil ALLDIRS := $(COMDIRS) $(UNIXDIRS) # directores to build for unix targets SUBDIRS = $(COMDIRS) $(UNIXDIRS) default: @echo "Use one of the following:" @echo "gmake build-all Depend then install each directory" @echo "gmake depend Build all dependencies" @echo "gmake all Build all targets" @echo "gmake install-headers Pre install headers. Do once." @echo "gmake install Build/install all targets" @echo "gmake clean Remove intermediate files" @echo "gmake clean-dist Remove all created files/directories" @echo "gmake update CVS update relevant directories" @echo @echo "To build the whole package the first time:" @echo " make install-headers;make depend;make install" @echo @echo "After first time just do: 'make install'" # build everything in a single pass # this does the correct things for a proper fist build build-all: inst-dirs -for d in $(SUBDIRS) ; do \ echo "make depend; make install in $$d" ; \ ([ ! -h $$d ] && cd $$d && \ $(MAKE) -fMakefile $(MFLAGS) depend \ && $(MAKE) -fMakefile $(MFLAGS) install);\ done # Do CVS updates of all build directories update: -for d in $(ALLDIRS) ; do \ echo "cvs update in $$d" ; \ ([ ! -h $$d ] && cd $$d && cvs update -d);\ done # build installation destination directories inst-dirs: [ -d $(INCDIR) ] || \ (mkdir $(INCDIR);chgrp $(GRP) $(INCDIR);chmod g+s $(INCDIR)) [ -d $(LIBDIR) ] || \ (mkdir $(LIBDIR);chgrp $(GRP) $(LIBDIR);chmod g+s $(LIBDIR)) [ -d $(LIBDIR)/$(OS) ] || \ (mkdir $(LIBDIR)/$(OS); \ chgrp $(GRP) $(LIBDIR)/$(OS); \ chmod g+s $(LIBDIR)/$(OS)) [ -d $(BINDIR) ] || \ (mkdir $(BINDIR);chgrp $(GRP) $(BINDIR);chmod g+s $(BINDIR)) [ -d $(BINDIR)/$(OS) ] || \ (mkdir $(BINDIR)/$(OS); \ chgrp $(GRP) $(BINDIR)/$(OS); \ chmod g+s $(BINDIR)/$(OS)) depend: -for d in $(SUBDIRS) ; do \ echo "Making $@ in $$d" ; \ ([ ! -h $$d ] && cd $$d && $(MAKE) -fMakefile $(MFLAGS) $@ ); \ done all: -for d in $(SUBDIRS) ; do \ echo "Making $@ in $$d" ; \ ([ ! -h $$d ] && cd $$d && \ ([ -f .make.$(OS).dep ] \ || $(MAKE) -fMakefile $(MFLAGS) depend) && \ $(MAKE) -fMakefile $(MFLAGS) $@ ); \ done install-headers: inst-dirs -for d in $(UNIXDIRS) ; do \ echo "Making $@ in $$d" ; \ ([ ! -h $$d ] && cd $$d && \ ([ -f .make.$(OS).dep ] \ || $(MAKE) -fMakefile $(MFLAGS) depend) && \ $(MAKE) -fMakefile $(MFLAGS) $@ ); \ done install: inst-dirs -for d in $(SUBDIRS) ; do \ echo "Making $@ in $$d" ; \ ([ ! -h $$d ] && cd $$d && \ $(MAKE) -fMakefile $(MFLAGS) $@ ); \ done clean: -for d in $(SUBDIRS) ; do \ echo "Making $@ in $$d" ; \ ([ ! -h $$d ] && cd $$d && $(MAKE) -fMakefile $(MFLAGS) $@ ); \ done clean-dist: -for d in $(SUBDIRS) ; do \ echo "Making $@ in $$d" ; \ ([ ! -h $$d ] && cd $$d && $(MAKE) -fMakefile $(MFLAGS) $@ ); \ done # FIX: add fortran tags? tags: @echo Building tags file for emacs... @# Cheesy hack. Should do a better job, like this... @# $(FIND_SOURCES) | $(XARGS_ONELINE) $(ETAGS) -o $(TAGSFILE) @#etags {*,*/*}/*.{c,cc,h} find . \( -name "*.[cChHx]" -o -name "*.cc" \) -print | xargs etags @echo Done. coffee: @echo Only real punks ask their computer for coffee... @imgview javalogo52x88.gif help: @echo Sending netscape to the html directory... @netscape -remote 'openURL(file:${TOPDIR}/doc/html/index.html)' & trouble: find . \( -name "*.[cChH]" -o -name "*.cc" \) -print |xargs grep -n FIX