[Go To www.civilution.com]   Civilution
Tools for evolving civilizations


 
   

CVS for Civilution members

OK, I'm going to regurgitate what little I know about CVS that is most relevant to everyone.

In MOST (non-web) development situations, CVS works by keeping one "master" copy, then doling out "slave" copies to the personal workspaces of developers that ask for them. if two developers both checkout and edit the same file, the last person to $ cvs commit <filename> is notified by CVS that somebody else has already contributed changes; CVS then requires that the version they want to commit be merged ($ cvs update <filename>) with the master copy.

BUT we are all working in the same directory. If two (or more) of us try to edit the same file at the same time, we are going to run into emacs and vi file locks. Those are far more annoying than CVS, so I suggest we deal with this problem by not editing the same file at the same time. If you have a strong reason to edit the same file at the same time as another developer here, either our file architecture is waay lame or you should be pair programming (or somebody locked the file by changing something in an open editor and left on a 3-day weekend).

All files in /web/ directories under CVS control are constantly in a state of "checked out", since that is the only way they can be accessible to AOLserver. (Otherwise, for example, there would be no /web/sextant/ directory at all.)


PROCEDURAL RECOMMENDATIONS:


Status

Since all files are always checked out, you don't need to do anything special when you want to edit a file in the first place. But there is one thing you should do:

To see if a given file (say, foo.tcl) has been modified since it was last committed, type:

$ cvs status foo.tcl

The status of a file that HAS NOT been modified is Up-to-date. The status of a file that HAS been locally modified is Locally Modified. If you want to work on a locally modified file, ask around to see who else is working on it.


Difference

If no one present admits to altering the file, you may want to see just how different the current version is from the most recent CVS-endorsed version. Use the following (the only line you have to type is the first one):

$ cvs diff foo.tcl
Index: foo.tcl
================================
RCS file: /cvsweb/sextant-dev/www/foo.tcl,v
retrieving revision 1.18
diff -r1.18 foo.tcl
27c27,30
< 14 This here is the line I'm going to delete for the demonstration.
---
>
>
> 15 This is the line I have added for the demonstration.

All the lines that start with a "<" are in the master copy, but have been deleted by whomever has modified the version you want to work on. All lines starting with ">" have been recently added. Notice that I also added a couple blank lines in the above example.

If the file has changed significantly since the last commit, you should commit the changes yourself (relax - I'm getting to that part). Don't worry about the fact that you don't know what had just been changed, log the commit with something like, "I'm just logging these changes so I can work on the file -Deane". It is possible for the person who did the uncommitted editing to change your comment later.


More Difference

To see what has changed between two versions, neither of which is the latest, do something like:

  • $ cvs diff -r 1.15 -r 1.17 index.tcl


Commit

In order to check in changes that have been made to a file and add a comment describing your changes to the CVS logs for that file, use:

$ cvs commit -m "Comment to be added to the log -YOU"

The -YOU part (i.e. -Carl) is not a requirement of CVS, but my suggestion. It will be nice to know who made a particular change so we can ask for more info if their logged comment is not explicit enough.

If you want to add a long comment to describe your changes, you should set either the EDITOR or CVSEDITOR environment variable to your favorite editor (I assume emacs). You can do this by adding the following to /home/YOU/.bash_profile:

CVSEDITOR=emacs
export CVSEDITOR

Then either log out and in again or $ source /home/YOU/.bash_profile If you don't use -m or set either of those environment variables, CVS will punish you by defaulting to vi.

How frequently should we commit? I suggest we commit modifications whenever one of the following happens:

  • A significant section of code we just added is working the way we want it to.
  • We have had enough of that particular file for now. (Going to go sleep, play in traffic, work on something else, etc)
  • Someone else wants to work on the file, and they don't want to take responsibility for logging what you were just up to.


Delete

Nothing ever really escapes from CVS. But if you want to think that it does, do the following:

  • Make sure the file's current status is Up-to-date
  • Delete the file in question with good 'ol rm
  • $ cvs remove filename
  • $ cvs commit filename

This is reversible.

Removing directories is a non-trivial operation. If you really want to do this, ask me and I'll try to learn how.


Add

If you found it necessary to create a new file in the first place, chances are you will want to have the same file in the same spot if you ever ask CVS to replicate the directory structure as it was at that moment in time.

$ cvs add filename
$ cvs commit filename

This will automatically add the file to whichever branch you are working on. Nothing special you need to worry about.

Adding new directories is also very simple:

$ cvs add directory_name     (no need to commit after this)

In order to add new files in a new directory, add the directory first, then cd directory and add the files.


Update and Log - Gleaning Information from CVS

$ cd /web
$ cvs -n update sextant-dev

This command is great. This will look through a directory tree under CVS control and answer a number of questions about its current state of affairs, such as:

  • What files are under CVS control?
  • I just woke up from a 9-hour coding frenzy. What have I modified and forgotten to commit?
  • What have I deleted but forgotten to tell CVS about?
  • What have I added but forgotten to tell CVS about?
And the like. The -n part of the command tells CVS not to actually change anything, but to just tell you what it would change. Do not forget the -n.

You can read more about the output of cvs update here or by typing man cvs.

cvs log is how you view the comments entered during commits:

  1. $ cvs log filename
  2. $ cvs log -rsextant-1-0a-staging index.tcl
If you want to see the log messages for sextant-dev, use number 1. For sextant-staging, use number 2. The difference here is the -rbranch name for sextant-staging. And yes, there really is no space between the -r and the branch name. Don't ask me why.

More about Update

You broke it. You don't know why, but the changes you have made to version 1.27 just won't cut it. Time to retreat to version 1.24:

  • $ cvs commit filename     (Unless you really don't want anyone to see just how badly you screwed it up.)
  • $ rm filename
  • $ cvs update -p -r 1.24 filename >filename
If you decide that version 1.24 is good enough for you, commit it as the latest version:
  • $ cvs commit filename


Branching

At present, the files in /web/sextant-dev/ and /web/sextant-staging/ all come from the same repository files, in /cvsweb/sextant-dev/*     When we decided the functionality of sextant-dev was sufficient, I ran:

  1. $ cd /web/sextant-dev
  2. $ cvs tag sextant-1-0a
Then, when I figured out we probably wanted to make a branch out of that release, I UN-tagged the files that weren't supposed to be included in the staging branch and ran:
  1. $ cd /web/sextant-dev
  2. $ cvs tag -b -r sextant-1-0a sextant-1-0a-staging
This made the original sextant-1-0a release into a new branch titled sextant-1-0a-staging. Now I could delete what was already in /web/sextant-staging and run:
  1. $ cd /web
  2. $ cvs checkout -d sextant-staging -r sextant-1-0a-staging sextant-dev
Notice that nothing altered in sextant-dev after the instant I ran the cvs tag command (number 2 above) was included in the release sextant-1-0a-staging.
So now, if we ever in the future need access to the contents of release sextant-1-0a exactly as they were when I first tagged the sources, we can get them into a directory named sextant-NEW by running:
  1. $ cd /web
  2. $ cvs checkout -d sextant-NEW -r sextant-1-0a sextant-dev


UN-Branching (Merging)

Great. Now, instead of just having our development directory tree to worry about, we have added a branch, doubling the size of the tree (and of course complexity scales in a merely linear fashion with additional branches, right?). Since all four of us are on both the development team and the testing team at the same time, we are constantly encountering permutations of the following scenario:

I just fixed this annoying bug in sextant-staging and I may or may not remember exactly what I went through to solve the problem. How can I move my bug-fix to sextant-dev so I don't have to solve the same problem again there?
If we were not all doing double-duty here, we testers would be content to play in our little universe of staging until the bugs were worked out. At that point, someone would magically merge our bug-fixes in staging back into the development sources.
If we worked only in development, we likewise wouldn't care what went on in staging. But since we do both, everyone here needs to know how to merge changes so you don't drive me mad with requests of this nature. This is not a trivial operation.

Scenario 1:

  • Directory: /web/sextant-staging/www/
  • Files edited: index.tcl
  1. $ cd /web/sextant-staging/www
  2. $ cvs commit index.tcl
  3. $ cvs log -h index.tcl
  4. $ cd /web/sextant-dev/www
  5. $ cvs commit index.tcl
  6. $ cvs update -j (REV FROM 3) -j sextant-1-0a-staging index.tcl
  7. $ cd /web
  8. $ cvs tag (INCREMENT REV FROM 3) sextant-staging
  9. $ cd /web/sextant-dev/www
  10. $ cvs commit index.tcl
In step 6, you can put a space-separated list of files where index.tcl is.
Notice that what you type in step 6 and 8 is dependent on what you get from step 3. What you are looking for is the most recent merge tag. It will look something like sextant-1-0a-staging-merge4 and will be at the top of the heading titled "symbolic names:". This label will be followed by a colon and a number - don't worry about that stuff, you only need to enter the label.

Step 8 is where you set the next merge tag. Increment the tag you read in step 3. I.e.:

  • sextant-1-0a-staging-merge4 becomes sextant-1-0a-staging-merge5
  • sextant-1-0a-staging-merge9 becomes sextant-1-0a-staging-merge10
And so on.

No, you aren't done yet. Well, maybe if you got lucky. If not, CVS detected a conflict on your attempted merge (if it has, it will say, "rcsmerge: warning: conflicts during merge"). This means the file(s) you specified at the end of line 6 have also been edited back in sextant-dev. CVS went ahead and merged anyway, but you are definitely going to have to edit the file before it will be bug-free and before you CVS will let you commit that file a la step 10. When CVS sees a conflict, it does something like this:

<<<<<<< test.html

21 It demonstrated good behavior I suppose.
=======

20 MORE changes. I need an example for the CVS help page.
>>>>>>> 1.19.2.3

CVS deliniates the boundaries of the conflict with "<<<<<<<" and ">>>>>>>". A line of "=======" separates what is in test.html in the CURRENT directory (the original branch, sextant-dev), from what was in revision 1.19.2.3 (sextant-staging branch, the file YOU presumably edited). You the programmer get to resolve this by deleting the special characters and resolving the conflicts they illustrate however you see fit. Clearly this might not be easy if you yourself were responsible for the changes only on staging or only on dev, but not both. If you can't figure out what to remove and what to leave, use your knowledge of cvs log and cvs diff to determine who was responsible for changing the relevant lines, then go ask them.

Scenario 2:

  • Directory: /web/sextant-staging/*
  • Files edited: More than you want to list
  1. $ cd /web
  2. $ cvs commit sextant-staging
  3. $ cvs commit sextant-dev
  4. $ cvs log -h sextant-staging |less
  5. $ cvs update -j sextant-1-0a-staging-merge3 -j sextant-1-0a-staging sextant-dev
  6. $ cvs tag sextant-1-0a-staging-merge4 sextant-staging
  7. $ cvs commit sextant-dev
Once again, you may run into conflicts during the merge. You will have to resolve those before step 7.
Once again, you are looking for the most recent merge tag in step 4.
If you do not run step 3, step 5 will skip files in sextant-dev which have been edited since their last commit (that would be bad). You should read through the list of all the scenarios cvs update may encounter so you know how to avoid them. Do not fear, there are only 7.


Merging the other direction

How about if you make some change on the development server that you want to port over to the staging server?

YOU DON'T

The whole point of having staging is so we don't randomly incorporate additional features that may not be ready. Once ALL of the sources under development are approved as a unit by all of us, we tag another alpha version and roll it to staging en-masse. This really shouldn't happen more frequently than every week or two.


emacs

MarkD@arsdigita.com wrote a short, simple summary of how to use emacs commands to accomplish CVS-related tasks.


More CVS. Must know more CVS!

Here is a comprehensive CVS reference.
The whole shebang is in just one file, which makes it very convenient to use your browser's text searching capability.


How to Annoy the CVS Admin

If you've read this far, it's probably clear to you that I have no love for CVS. Therefore, I am unlikely to appreciate any actions which require me to spend more time wrestling with arcane CVS commands. Or even with common CVS commands. In fact, if I never encounter another CVS command or reference as long as I live, I will get steadily happier and happier until I die of sheer unbridled ecstasy. To prevent this from happening, try one of the following:
  • Slough off responsibility for learning about and executing the commands in this document.
  • Randomly move files and directories around.
  • Randomly move files and directories around between the development, staging, and production branches.
  • Add a directory in one place, then decide it really should be someplace else. Then decide it really should be on a different development branch.
  • Forget to commit your changes.
  • Decide not to add the file you just created because, "It's only important right now. I'm really only using it for testing, and Very Soon Now we will release this product and testing will no longer be necessary."
  • Use the Civilution web development branches to experiment with fascinating new CVS commands.
  • Use the Civilution web development branches to experiment with fascinating new CVS emacs shortcuts.
  • Create and add a new file, then forget to commit it.
  • rm a file from the filesystem, then forget to remove or commit it.
Naturally I reserve the right to add to this list as my experience warrants. In fact, should YOU (yes, you!) choose to take on the responsibilities of a CVS Admin, this prize could be yours as well!


Ignoring CVS

Fine, so what happens if all us Civiloonies ignore CVS completely while doing development? We can still use CVS once we decide that /web/sextant-dev/ is working particularly well and we should take a snapshot of it to move to /web/sextant-staging/. But why not use cp -R? I can also write a cron job to commit all sextant-dev changes once a day, which would gain us alteration resolution and the ability to "turn back the clock" should something go awry. Of course our backups already do that (albeit slower).

So there really is no point to using CVS unless we conscientiously commit our edits with informative log entries.


deane@civilution.com