« It's a tie... VeriSign wins! | Main | Get a reprieve from RFID passports »

April 1, 2005

Curse you, CVS merging!

CVS has many annoying behaviors, but yesterday I attempted one of the activities CVS users fear most: merging a branch back into the Head of Tree (H-O-T). Now, this works OK in the simple case where you haven't done anything on H-O-T, but if you've changed the same files in the branch and H-O-T, then you can get conflicts.

Now, in theory you only get conflicts if you've changed the same section of the file in both branches, but in practice I always get burned. It's standard practice to include a version id in your code. For instance:

static char *RCSSTRING __UNUSED__ ="$Id: tcpconn.c,v 1.22.2.2 2005/02/03 21:25:57 ekr Exp $";

When you do checkins and checkouts, CVS automatically modifies this string to reflect the current version, date, etc. This lets you instantly look at any code fragment and determine which versions it corresponds to, which can be very helpful in debugging customer problems. Here's when things start to go wrong. Say you've been working on file foo.c in both branches. So, in H-O-T you've got version number 1.23. In the branch you have version number 1.22.2.2. This means you have different version IDs, and since the same line of code has changed, CVS decides you've got a conflict. It marks it up in the source code like this:

<<<<<<< tcpconn.c
static char *RCSSTRING __UNUSED__ ="$Id: tcpconn.c,v 1.23 2004/07/16 00:08:58 ekr Exp $";
=======
static char *RCSSTRING __UNUSED__ ="$Id: tcpconn.c,v 1.22.2.2 2005/02/03 21:25:5 7 ekr Exp $";
>>>>>>> 1.22.2.2

Now, here's the baffling part: CVS controls these lines. It wrote them in the first place, so you'd think it could figure out that they're not real conflicts and just fix them up. But nooooo.... You have to go in and remove the conflicts manually. Yeah, yeah, I know that I could fix this myself, but wouldn't it be nice if I didn't have to?

Posted by ekr at April 1, 2005 7:01 AM | Filed under:

Comments

Subversion replaces keywords on checkout, not on checkin -- the repository stores the un-replaced keyword, and so it doesn't have these conflicts. I would highly recommend switching any CVS repos over to SVN. Another benefit of SVN is that it know about the common ancestry of 1.23 and 1.22.2.2, so it's doing a 3-way diff during a merge, and not a 2-way diff, which almost always massively reduces the number of conflicts you have to manually resolve.

As a bonus incentive, there are cvs2svn scripts out there which will automagically suck all your project history over to the new repo and everything. Plus you can do more useful access control stuff on branchs in the repo, have atomic commits, use HTTP/WebDAV as a network transport, use regular HTTP GETs to browse/fetch the latest version of any file, etc, etc. As I said, highly recommended for anyone still using CVS.

Posted by: Craig Hughes at April 1, 2005 10:08 AM

I'm still iffy on the idea of migrating to SVN, although I'm using both it and CVS regularly these days. There are a lot of nice things about it, to be sure.

Regarding the strings, CVS (well, RCS) also replaces the strings on checkout, not checkin. You can use -ko to ge tthe old string, or (more usefully for ekr's problem) use -kk to get empty strings. (The man page says "This option is useful to ignore differences due to keyword substitution when comparing different revisions of a file.")

Arguably CVS merge should do this automatically…

Posted by: Wim L at April 1, 2005 12:52 PM

I'm an advocate of SVN also. Even if it doesn't fix this problem, at least you can justify a departure from CVS citing spite, and then get the features that actually *do* work better from SVN.

Posted by: Blake at April 2, 2005 9:23 PM

Remove unwanted spyware fast and easy Spyware Removal Tools - About Blank Remover.

Posted by: Anti Spyware Dude at April 7, 2005 2:08 AM