by June 13, 2007

CVS Annotate, or "What the heck were they thinking?"

The cvs annotate command (and its sister, svn blame) is the "tattle-tale" of the development world. For every single line of code in a file, it will tell you:

and want to know where point that look of scorn? If so, the cvs annotate command is just what you've been looking for!

The cvs annotate command (and its sister, svn blame) is the "tattle-tale" of the development world. For every single line of code in a file, it will tell you:

  • Who was the last person who touched it?
  • What date was it last changed?
  • In what precise version of the file was it last changed?

Like so:

1.85         (dries    22-Jun-05): require_once './includes/';
1.86         (dries    23-Jul-05): drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
1.67         (dries    28-Sep-03):
1.83         (dries    24-Apr-05): $return = menu_execute_active_handler();
1.91         (unconed  12-Dec-06):

Sound handy? It sure is! And you don't even need to be a command-line geek to benefit!

For example...

Right now, Drupal 6.x-dev spits out a fatal error if the database connection fails:

Fatal error: Call to undefined function file_directory_path() in /Applications/MAMP/htdocs/head/includes/ on line 1769

Darn you, line 1769! Why must you mock me so?!

So I know this had to be introduced at some point relatively recently, since in 5.x, this would give me a nice "Could not connect to database" message, themed with the lovely, smiling Druplicon. Let's take a closer look.

CVS annotate - command-line version

Bring up a command prompt and punch in the following:

$ cvs annotate includes/ > blame.txt
$ vim blame.txt # or pico, if you're like a total wuss. ;)

I redirect this to a file because this sucker is loonnng.

If I head down to line 1769, I see:

1.649        (unconed  01-Jun-07):   $directory = file_directory_path();

Ah-HA! So now I can blame Steven. ;) Let's see what was actually done during that commit:

$ cvs log -r1.649 -N includes/ 

(-r1.649 limits the list of log messages to only that revision, and -N stops it from printing a huge list of tags. See the manual for additional cvs log options.)

The output of this command is:

(snip a bunch of unrelated stuff)
#119441: JavaScript aggregator/compressor by m3avrck and others.

Since the #number corresponds to a node ID on, I now know that this bug originated from the JS aggregation patch, and I also know that I should harras Ted next time I see him, and not Steven. ;)

CVS annotate - web version

It's also possible to use the power of this command without using CVS at all! provides a handy web-based CVS browser and you can use the same technique with it.

  1. Browse to includes/ to view a list of log messages for that file. (incidentally, you can use the "Sticky tag" drop-down at the bottom to view previous versions of the files [DRUPAL-5 = Drupal 5, DRUPAL-4-7 = Drupal 4.7...])
  2. Click the annotate link next to the first revision in the list.
  3. Hit Ctrl/Cmd+F to use your browser's search to find the line in question (1769). This will show you output like the following:

CVS Annotate - Web style

As you can see, this still has the same information as the command-line version, just is laid out a bit differently.

  • Take note of the revision number (1.649). Incidentally, you can click that number to get a "diff" of the changes that were made during that commit.
  • Go back to the top and click Revision log to go back to the initial screen showing all the commit messages.
  • You should be automatically skipped down to the place where that change was introduced. And here you go, the same result as we discovered in the command-line version:

    CVS log - Web style

  • Head over to the referenced issue and read up on why the change happened for hints on how to fix it.
  • So there you have it!

    Two ways to get at some really useful information for whatever ails you!