Linux tips with CVS
Well, we use CVS for our version control at work, and yesterday we had to do something a bit unorthodox that entailed me updating an entire branch back to the trunk (long story). So, in the process, I was responsible for committing literally hundreds of files in our project, and after confirming and reconfirming that I had all the files up to date and modified correctly, I devised a way to “automate” a mass add and commit. In case this helps someone else out there, I thought I would share.
Anyway, if you use CVS to any extent, you are probably aware of how update (up for short) works and the fact that you can use the -n and -q modifiers to keep the actions from actually taking place so you can examine the results before carrying it out. Well, for quite some time now, I have been piping the results through a simple grep command to get me a list of specific files I need to work with. For instance, if I wanted just a list of files that I have created (not yet in CVS) and those I have locally modified in order to know a full list of files I have yet to commit, I would run something like this:
> cvs -nq up -d | grep ^[?M]
Obviously, the question mark is the new file listing and the M is for local modifications. If you have already added files to the repository but not yet committed them, you may also need to add the ‘A’ modifier in there to pull in those files as well (so your regexp for your grep would look like this instead: ^[?MA]).
So, building on this base, I thought there must be a simple way to get the listing of filenames only, instead of the leading character and space that designates its status. After consulting with a friend on the best approach, I settled on a simple regular expression substitution — the same regexp, in fact, that I used in the initial grep. Now, I wanted to pull only those files (filename only) that CVS knows nothing about, so I navigated to the root directory of my application and ran the following command:
> cvs -nq up -d | grep ^\? | sed 's/^\? //'
Voila! I had a full file listing (including paths) of all files in my application that CVS knows nothing about. Now, since there were well over 150 files, I wanted to avoid having to run a manual commit on each one, so I thought there must be a way to use xargs to do the dirty work for me. If you have ever used this command before, you probably already know where I am headed. By simply piping the result list through xargs and running a cvs add, with one command, I could easily find and add all new files to my repository in one fell swoop. Here is the command I ran to do just this:
> cvs -nq up -d | grep ^\? | sed 's/^\? //' | xargs -i cvs add {}
If you’re not familiar with xargs, I would definitely recommend you read up on it, because it has proven to be absolutely invaluable in situations like this for me.
So, at this point, I have all my files added, so I need to commit everything that has either an A or M status (Added or Modified respectively), so I did something very similar with my commit call, but to be safe, I decided to go ahead and push all output (errors, too) to a log file to be able to examine it thoroughly, just in case the result was larger than my shell buffer could handle. After seeing the previous command, this one should be a piece of cake to figure out:
> cvs -nq up -d 2>&1 | grep ^[AM] | sed 's/^[AM] //' | xargs -i cvs commit -m "My Commit Message" {} > mylogfile.txt
That’s it! With the previous two commands, from any given directory, you can both add and commit any new or locally modified files to your CVS repository. Again, don’t do something like this until you are absolutely positive you have everything in working order. In our case, everything went off without a hitch!
Again, the final version of the two commands I personally ran were:
> cvs -nq up -d 2>&1 | grep ^\? | sed 's/^\? //' | xargs -i cvs add {} > add_log.txt
> cvs -nq up -d 2>&1 | grep ^[AM] | sed 's/^[AM] //' | xargs -i cvs commit -m "My Message" {} > commit_log.txt
Hope this is of some help to someone out there. Now, off to work on my next Tower Defense post!
Garth Henson has been working professionally as a web developer for nearly 10 years. When not coding in PHP, JavaScript or Actionscript, he can usually be found trying to refine his photography skills.






Brade
22 Jan, 2009
In related news, have you looked at bazaar? After working with SVN mainly over the years, I’ve tried bazaar recently (after trying and rejecting git) and it’s pretty dang great–I’d have to give it the edge over CVS.