Rich Kulawiec on 16 Nov 2017 10:08:27 -0800 |
[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]
Re: [PLUG] Revision Control for the Rest of Us |
Excellent idea. And while it's clear that git has largely prevailed over its competitors and predecessors, let me put in a word for RCS. RCS has been around a very long time. It's very stable -- and very limited. There are all kinds of things it doesn't do, and of course, if you need to do those things, you probably shouldn't use it. But in its favor are two things: first, there are a lot of simple use cases that it handles beautifully. Second, you can learn it in ten minutes. I use it to do revision control on my resume, on my mail system's custom anti-spam rules, on my record collection (yes, I still own records) (and I listen to them), and things like that. Note that RCS works at the level of individual files, which has the advantage of keeping it simple and the disadvantage of not helping manage collections of files. (I do that with make(1).) So emphasis on the "simple" in "simple use cases". While we *did* use this for software development projects with thousands of files and many developers back in the day, I wouldn't recommend it now unless there was some very compelling reason. I've used git, subversion, SCCS, CVS, and so on. But I still rely on RCS for certain tasks because it does the job quickly, efficiently, accurately, and easily. (Note also that if you start out with it, and then it turns out you were wrong about the capabilities you needed, you can switch to most other revision control systems fairly easily.) Appended below is a quick how-to that really will have you using RCS in ten minutes. Less, if you read quickly. ;) ---rsk RCS consists of about ten commands, each of which has quite a few options that provide other capabilities as well -- but you only need to know a handful of things to start using it quite effectively. The basic idea of RCS is that it keeps the most current revision of a file as well as a set of "deltas" -- one for each previous revision -- which enable it to do/undo changes on the fly. All of these are stored in a single file, which has a format known to RCS; by default, these files are suffixed ",v". (You shouldn't even think about editing the ,v file.) Let's say for example you're working on a file called "foo.sh". If you check it into the RCS system like this: ci foo.sh (Note: ci == "check-in". You now know an RCS command.) You will get this message: enter description, terminated with single '.' or end of file: NOTE: This is NOT the log message! >> RCS is asking you for a description of the file. The reason it's reminding you, pointedly, that this isn't a log message is that you are not checking in a revision to the file: you are checking in the original file. So let's give it a description: >> An astoundingly clever shell script >> . (The single "." tells RCS you're done describing the file.) If you run "ls", you'll notice that you now have a file called "foo.sh,v" and that you no longer have a file "foo.sh". Don't panic. You can get your script back with: co foo.sh which will yield this: foo.sh,v --> foo.sh revision 1.1 done This is RCS's way of telling you that it has extracted revision 1.1 from foo.sh,v for you. Why 1.1? Because it's branch 1, revision 1 and because that's the numbering RCS chooses by default. (Note: co == "check-out". Now you know two RCS commands.) The "foo.sh,v" file is called the "delta file" in RCS terms. What's in the "foo.sh,v"? Well, the entire contents of foo.sh, plus some information that RCS uses to keep track of who checked it in, when it was checked in, etc. You can ask the RCS system to tell you everything it knows about "foo.sh,v" by doing this: rlog foo.sh (rlog == "RCS log". Now you know three RCS commands.) This will play back the entire change history of the file -- which of course isn't all that interesting at this point, because all you've done is create one revision. Now suppose you want to edit "foo.sh" to add a new routine. You'll notice that the copy you currently have isn't writable. That's because "foo.sh" is not "locked" by you. The idea is that in order to edit a file you have to check it out -- locked -- so that nobody else can edit it while you're doing so. To do this, you do a: co -l foo.sh (co -l == "check-out AND lock") Assuming that nobody else has beaten you to it, you now have a writable copy of "foo.sh" that you can edit to your heart's content. Anyone else trying to do a "co -l foo.sh" will be told that you currently have it locked. Now you might say "but I'm the only one who will ever..." and you know, you're right. This is still useful, though, because it defends you from your own mistakes: if you go to check out and edit foo.sh and discover that it's already locked, then that's probably because you checked it out a while ago, edited it, and forgot to check in your revisions. Maaaaaaybe you might want to figure out what happened before you proceed. When you're done editing, you can check the new version in -- and unlock the file -- by doing a: ci -u foo.sh (ci -u == "check-in AND unlock") RCS will prompt you for a description of what you did -- this is a good place to record your comments on the changes, such as "added a new routine foobar() which sorts an array". You'll note that RCS also automatically increments the version number on the file; it numbered your original version 1.1, and will number this one 1.2. Suppose you come along later and can't remember exactly what changes you made between 1.1 and 1.2. Well, if you do a: rcsdiff -r1.1 -r1.2 foo.sh RCS will show you just what is different between those two versions. This works for non-sequential revisions, e.g.: rcsdiff -r1.2 -r1.9 foo.sh will show all the differences between those two versions. (Now you know four RCS commands.) RCS has a lot of features, but frankly, all you probably really have to know to get started is: * co -l (Check out/lock a file so you can edit it) * ci -u (Check in/unlock a file to save changes) * rlog (Read revision history of a file) * rcsdiff (Look at specific changes between revisions) Most of these commands have a number of options, which you can read about in their manual pages. Some of those are more useful than others. RCS also does branching and merging (rcsmerge is a *great* little tool) and symbolic version naming and all kinds of stuff. None of which are needed for nearly all simple use cases. A couple things to be careful of: if RCS complains about not wanting to overwrite a file, it's probably a good idea to find out what's going on before telling it to go ahead; you may have just asked it to blow away your careful changes. The first thing you probably want to do is "rcsdiff" to figure out what's where. Second, and I probably should have put this in sooner, if the current working directory has a subdirectory named "RCS", then the ,v files will go there. Very handy...keeps the directory uncluttered. Example: % ls foo.sh RCS % ls RCS foo.sh,v Third, GNU make is RCS-aware. That is, it has built-in rules that allow it to figure out that if you say "make foo.sh", and foo.sh does not exist, but foo.sh,v or RCS/foos.sh,v does, it should invoke "co" to create the file. Appended below are the abridged PUCC (Purdue University Computing Center) pocket guide entries for some of the RCS-related commands. This just scratches the surface: for more information, see the manual pages for each command. ------------------------------------------------------------------------------- ci [<options>] <file(s)> Check in RCS files. -l[<rev>] Perform checkout with locking after checkin. -u[<rev>] Perform checkout without locking after checkin. -m<msg> Use <msg> as the log message for all files checked in. ------------------------------------------------------------------------------- co [<options>] <file(s)> Check out RCS files. -r[<rev>] Retrieve latest revision whose number is less than or equal to <rev>. -l[<rev>] Lock checked out revision. -u[<rev>] Unlock the retrieved revision (default: latest). -f[<rev>] Force overwriting of the working file. ------------------------------------------------------------------------------- rlog [-b] [-h] [-t] [-d<dates>] [-l[<lockers>]] [-r<revisions>] [-s<states>] [-w[<logins>]] [-L] [-R] <file(s)> Print log messages and other information about RCS files. Rlog prints the intersection of the revisions selected with the options -d, -l, -s, -w, intersected with the union of the revisions selected by -b and -r. -b Print information about revisions on default branch. -h Print using brief format. -t Same as -h, plus descriptive text. -r<revisions> Restrict report to specified comma-separated <revisions>. A range of revisions "r1-r2" means revisions from <r1> to <r2> on the same branch. -L Ignore RCS files that have no locks set. -R Only print name of RCS file. ------------------------------------------------------------------------------- rcsdiff [-b] [-cefhn] [-q] [-r<rev1>] [-r<rev2>] <file(s)> Compare two RCS revisions. Rcsdiff runs diff to compare two RCS revisions. If both <rev1> and <rev2> are omitted, rcsdiff compares the latest revision on the trunk with the working file. If only <rev2> is omitted, rcsdiff compares <rev1> with the working file. The -b, -c, -e, -f, and -h options have the same effect as with diff. -n Generate an RCS format edit script. ------------------------------------------------------------------------------- rcs [<options>] <file(s)> Change RCS file attributes or create RCS files. -l[<rev>] Lock specified revision. If <rev> omitted, lock latest revision on trunk. -u[<rev>] Unlock specified revision. If <rev> is omitted, unlock latest lock held by invoker. -L Set locking to strict. -U Set locking to non-strict. -o<range> Delete revisions specified by <range>. A range "r1-r2" specifies revisions from <r1> to <r2>. If one of the endpoints of the range is omitted, the range extends to the end of the branch. ------------------------------------------------------------------------------- rcsmerge -r<rev1> [-r<rev2>] [-p] <file> Merge RCS revisions. Rcsmerge finds the differences between <rev1> and <rev2> and modifies <file> to reflect these differences. <Rev1> may not be omitted; if <rev2> is omitted, the latest revision on the trunk is assumed. Rcsmerge prints a warning if an overlap occurs. -p Write result to stdout instead of overwriting <file>. ___________________________________________________________________________ Philadelphia Linux Users Group -- http://www.phillylinux.org Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce General Discussion -- http://lists.phillylinux.org/mailman/listinfo/plug