## 11.3. Context diffs

The diff examples in Section 11.1 and Section 11.2 show compact formats with just the differences between the two files. But, in many cases, context diff listings are more useful. Context diffs show the changed lines and the lines around them. (This can be a headache if you're trying to read the listing on a terminal and there are many changed lines fairly close to one another: the context will make a huge "before" section, with the "after" section several screenfuls ahead. In that case, the more compact diff formats can be useful.) A related format, unified diff, shows context but doesn't take as much space.

Go to http://examples.oreilly.com/upt3 for more information on: rcs

The rcsdiff command shows differences between revisions in an RCS (Section 39.5) file (and will only be available if you have RCS installed). We'll use it here instead of diff -- but the concepts are the same. Incidentally, these examples would also work with cvs diff (Section 39.7), if you have CVS installed.

The -c option shows before-and-after versions of each changed section of a file. By itself, -c shows three lines above and below each change. Here's an example of a C file before and after some edits; the `-c2` option shows two lines of context. The -u option shows changed lines next to each other, not in separate before-and-after sections. Again, an option like `-u2` shows two lines of context around a change instead of the default three lines.

Start of a listing
  A diff -c listing starts with the two filenames and their last-modified dates ("timestamps"). The first filename (here, atcat.c revision 1.1) has three asterisks (`***`) before it; the second name (atcat.c revision 1.2) has three dashes (`---`). These markers identify the two files in the difference listings below:

  >     *** atcat.c 1987/09/19 12:00:44 1.1
  >     --- atcat.c 1987/09/19 12:08:41 1.2

  A diff -u listing also starts with the two filenames and their last-modified dates ("timestamps"). The first filename (here, atcat.c revision 1.1) has three minus signs (`---`) before it, meaning "from" or "before." The second name (atcat.c revision 1.2) has three plus signs (`+++`). Again, these markers identify the two files in the difference listings that follow:

  >     --- atcat.c 1987/09/19 12:00:44 1.1
  >     +++ atcat.c 1987/09/19 12:08:41 1.2

Start of a section
  Each difference section in a diff -c listing starts with a row of asterisks:

  >     ***************

  In a diff -u listing, each difference section starts with a line that has a pair of line numbers and line counts. This one means that the first version of the file (with a `-` before it) starts at line 14 and contains 5 lines; the second version of the file (with a `+`) also starts at line 14 and has 5 lines:

  >     @@ -14,5 +14,5 @@

Changes
  In a diff -c listing, changed lines that exist in both files are marked with an `!` (exclamation point) character in the left margin. So, one of the lines between lines 15-19 was changed. Other lines in the section weren't changed:

  >     *** 15, 19 ****
  >       #ifndef lint
  >       static char rcsid[ ] =
  >     !     "$Id: ch11_03.htm,v 1.3 2002/11/05 20:19:28 ellie Exp ellie $";
  >       #endif not lint
  >     --- 15,19 ----
  >       #ifndef lint
  >       static char rcsid[ ] =
  >     !     "$Id: ch11_03.htm,v 1.3 2002/11/05 20:19:28 ellie Exp ellie $";
  >       #endif not lint
  >       /* end of Identification */

  A diff -u listing always shows lines that are marked with a minus (`-`) only in the first version and lines marked with a plus (`+)` in the second version. Here, one line was changed:

  >     @@ -15,5 +15,5 @@
  >      #ifndef lint
  >      static char rcsid[ ] =
  >     -     "$Id: ch11_03.htm,v 1.3 2002/11/05 20:19:28 ellie Exp ellie $";
  >      static char rcsid[ ] =
  >     +     "$Id: ch11_03.htm,v 1.3 2002/11/05 20:19:28 ellie Exp ellie $";
  >      #endif not lint
  >      /* end of Identification */

Deletions
  In a diff -c listing, a line that exists in the first version but not the second version is marked with a minus sign (`-`). None of the lines from the second version are shown. So, line 62 in the first version (lines 64-68) was deleted, leaving lines 64-67 in the second version:

  >     *** 64,68 ****
  >       {
  >         int i;              /* for loop index */
  >     -   int userid;         /* uid of owner of file */
  >         int isuname;        /* is a command line argv a user name? */
  >         int numjobs;        /* # of jobs in spooling area */
  >     --- 64,67 ----

  A diff -u listing simply shows the deleted line with a minus (`-`) sign before it. The section started at line 64 and had 5 lines; after the change, it starts at line 64 and has 4 lines:

  >     @@ -64,5 +64,4 @@
  >      {
  >         int i;              /* for loop index */
  >     -   int userid;         /* uid of owner of file */
  >         int isuname;        /* is a command line argv a user name? */
  >         int numjobs;        /* # of jobs in spooling area */

Additions
  In a diff -c listing, lines that are added are marked with an exclamation point (!) and only appear in the second version. So, one of the lines between lines 111-116 was changed, and two other lines were added, leaving lines 111-118 in the second version:

  >     *** 111,116 ****
  >          * are given, print usage info and exit.
  >          */
  >     !   if (allflag && argc)
  >             usage( );

  >         /*
  >     --- 111,118 ----
  >          * are given, print usage info and exit.
  >          */
  >     !   if (allflag && argc) {
  >             usage( );
  >     +       exit(1);
  >     +   }

  >         /*

  In a diff -u listing, lines that are only in the second version are always marked with a `+`. Here, one line was changed, and two lines were added. The original version started at line 111 and had 6 lines; the changed version started at line 111 and has 8 lines:

  >     @@ -111,6 +111,8 @@
  >          * are given, print usage info and exit.
  >          */
  >     -   if (allflag && argc)
  >     +   if (allflag && argc) {
  >             usage( );
  >     +       exit(1);
  >     +   }

  >         /*

Context diffs aren't just nice for reading. The patch (Section 20.9) program reads context diff listings and uses them to update files automatically. For example, if I had the first version of atcat.c, someone could send me either of the previous diff listings (called a "patch"). From the original and the patch, patch could create the second version of atcat.c. The advantage of a context diff over the formats in Section 11.1 and Section 11.2 is that context diffs let patch locate the changed sections even if they've been moved somewhat. In this case, it's probably not a good idea to save space by reducing the number of context lines (with `-c2` or `-u2`, as I did here); giving all three lines of context can help patch locate the changed sections.

-- JP

Copyright © 2003 O'Reilly & Associates. All rights reserved.