GNU Info

Info Node: (cvsbook.info)Tracking Third-Party Sources (Vendor Branches)

(cvsbook.info)Tracking Third-Party Sources (Vendor Branches)


Next: Exporting For Public Distribution Prev: Going Out On A Limb (How To Work With Branches And Survive) Up: Advanced CVS
Enter node , (file) or (file)node

Tracking Third-Party Sources (Vendor Branches)
==============================================

Sometimes a site will make local changes to a piece of software received
from an outside source.  If the outside source does not incorporate the
local changes (and there might be many legitimate reasons why it can't),
the site has to maintain its changes in each received upgrade of the
software.

CVS can help with this task, via a feature known as "vendor branches".
In fact, vendor branches are the explanation behind the puzzling (until
now) final two arguments to cvs import: the vendor tag and release tag
that I glossed over in Note: An Overview of CVS.

Here's how it works.  The initial import is just like any other initial
import of a CVS project (except that you'll want to choose the vendor
tag and release tag with a little care):

     floss$ pwd
     /home/jrandom/theirproj-1.0
     floss$ cvs import -m "Import of TheirProj 1.0" theirproj Them THEIRPROJ_1_0
     N theirproj/INSTALL
     N theirproj/README
     N theirproj/src/main.c
     N theirproj/src/parse.c
     N theirproj/src/digest.c
     N theirproj/doc/random.c
     N theirproj/doc/manual.txt
     
     No conflicts created by this import
     
     floss$

Then you check out a working copy somewhere, make your local
modifications, and commit:

     floss$ cvs -q co theirproj
     U theirproj/INSTALL
     U theirproj/README
     U theirproj/doc/manual.txt
     U theirproj/doc/random.c
     U theirproj/src/digest.c
     U theirproj/src/main.c
     U theirproj/src/parse.c
     floss$ cd theirproj
     floss$ emacs src/main.c src/digest.c
      ...
     floss$ cvs -q update
     M src/digest.c
     M src/main.c
     floss$ cvs -q ci -m "changed digestion algorithm; added comment to main"
     Checking in src/digest.c;
     /usr/local/newrepos/theirproj/src/digest.c,v  <--  digest.c
     new revision: 1.2; previous revision: 1.1
     done
     Checking in src/main.c;
     /usr/local/newrepos/theirproj/src/main.c,v  <--  main.c
     new revision: 1.2; previous revision: 1.1
     done
     floss$

A year later, the next version of the software arrives from Them, Inc.,
and you must incorporate your local changes into it.  Their changes and
yours overlap slightly.  They've added one new file, modified a couple
of files that you didn't touch, but also modified two files that you
modified.

First you must do another import, this time from the new sources.
Almost everything is the same as it was in the initial import - you're
importing to the same project in the repository, and on the same vendor
branch.  The only thing different is the release tag:

     floss$ pwd
     /home/jrandom/theirproj-2.0
     floss$ cvs -q import -m "Import of TheirProj 2.0" theirproj Them THEIRPROJ_2_0
     U theirproj/INSTALL
     N theirproj/TODO
     U theirproj/README
     cvs import: Importing /usr/local/newrepos/theirproj/src
     C theirproj/src/main.c
     U theirproj/src/parse.c
     C theirproj/src/digest.c
     cvs import: Importing /usr/local/newrepos/theirproj/doc
     U theirproj/doc/random.c
     U theirproj/doc/manual.txt
     
     2 conflicts created by this import.
     Use the following command to help the merge:
     
            cvs checkout -jThem:yesterday -jThem theirproj
     
     floss$

My goodness - we've never seen CVS try to be so helpful.  It's actually
telling us what command to run to merge the changes.  And it's almost
right, too!  Actually, the command as given works (assuming that you
adjust yesterday to be any time interval that definitely includes the
first import but not the second), but I mildly prefer to do it by
release tag instead:

     floss$ cvs checkout -j THEIRPROJ_1_0 -j THEIRPROJ_2_0 theirproj
     cvs checkout: Updating theirproj
     U theirproj/INSTALL
     U theirproj/README
     U theirproj/TODO
     cvs checkout: Updating theirproj/doc
     U theirproj/doc/manual.txt
     U theirproj/doc/random.c
     cvs checkout: Updating theirproj/src
     U theirproj/src/digest.c
     RCS file: /usr/local/newrepos/theirproj/src/digest.c,v
     retrieving revision 1.1.1.1
     retrieving revision 1.1.1.2
     Merging differences between 1.1.1.1 and 1.1.1.2 into digest.c
     rcsmerge: warning: conflicts during merge
     U theirproj/src/main.c
     RCS file: /usr/local/newrepos/theirproj/src/main.c,v
     retrieving revision 1.1.1.1
     retrieving revision 1.1.1.2
     Merging differences between 1.1.1.1 and 1.1.1.2 into main.c
     U theirproj/src/parse.c
     floss$

Notice how the import told us that there were two conflicts, but the
merge only seems to claim one conflict.  It seems that CVS's idea of a
conflict is a little different when importing than at other times.
Basically, import reports a conflict if both you and the vendor modified
a file between the last import and this one.  However, when it comes
time to merge, update sticks with the usual definition of "conflict" -
overlapping changes.  Changes that don't overlap are merged in the usual
way, and the file is simply marked as modified.

A quick diff verifies that only one of the files actually has conflict
markers:

     floss$ cvs -q update
     C src/digest.c
     M src/main.c
     floss$ cvs diff -c
     Index: src/digest.c
     ===================================================================
     RCS file: /usr/local/newrepos/theirproj/src/digest.c,v
     retrieving revision 1.2
     diff -c -r1.2 digest.c
     *** src/digest.c        1999/07/26 08:02:18     1.2
     -- src/digest.c        1999/07/26 08:16:15
     ***************
     *** 3,7 ****
     -- 3,11 ----
      void
      digest ()
      {
     + <<<<<<< digest.c
        printf ("gurgle, slorp\n");
     + =======
     +   printf ("mild gurgle\n");
     + >>>>>>> 1.1.1.2
      }
     Index: src/main.c
     ===================================================================
     RCS file: /usr/local/newrepos/theirproj/src/main.c,v
     retrieving revision 1.2
     diff -c -r1.2 main.c
     *** src/main.c  1999/07/26 08:02:18     1.2
     -- src/main.c  1999/07/26 08:16:15
     ***************
     *** 7,9 ****
     -- 7,11 ----
      {
        printf ("Goodbye, world!\n");
      }
     +
     + /* I, the vendor, added this comment for no good reason. */
     floss$

From here, it's just a matter of resolving the conflicts as with any
other merge:

     floss$ emacs  src/digest.c  src/main.c
      ...
     floss$ cvs -q update
     M src/digest.c
     M src/main.c
     floss$ cvs diff src/digest.c
     cvs diff src/digest.c
     Index: src/digest.c
     ===================================================================
     RCS file: /usr/local/newrepos/theirproj/src/digest.c,v
     retrieving revision 1.2
     diff -r1.2 digest.c
     6c6
     <   printf ("gurgle, slorp\n");
     --
     >   printf ("mild gurgle, slorp\n");
     floss$

Then commit the changes

     floss$ cvs -q ci -m "Resolved conflicts with import of 2.0"
     Checking in src/digest.c;
     /usr/local/newrepos/theirproj/src/digest.c,v  <--  digest.c
     new revision: 1.3; previous revision: 1.2
     done
     Checking in src/main.c;
     /usr/local/newrepos/theirproj/src/main.c,v  <--  main.c
     new revision: 1.3; previous revision: 1.2
     done
     floss$

and wait for the next release from the vendor.  (Of course, you'll also
want to test that your local modifications still work!)

-------------------------------------------------------------


automatically generated by info2www version 1.2.2.9