GNU Info

Info Node: (cvsbook.info)Multiple Merges

(cvsbook.info)Multiple Merges


Next: Creating A Tag Or Branch Without A Working Copy Prev: Merging Changes From Branch To Trunk Up: Branches
Enter node , (file) or (file)node

Multiple Merges
---------------

Sometimes a branch will continue to be actively developed even after the
trunk has undergone a merge from it.  For example, this can happen if a
second bug in the previous public release is discovered and has to be
fixed on the branch.  Maybe someone didn't get the joke in random.c, so
on the branch, you have to add a line explaining it

     floss$ pwd
     /home/whatever/myproj_branch
     floss$ cat b-subdir/random.c
     /* Print out a random number. */
     #include <stdio.h>
     void main ()
     {
       printf ("A random number.\n");
       printf ("Get the joke?\n");
     }
     floss$

and commit.  If that bug fix also needs to be merged into the trunk, you
might be tempted to try the same update command as before in the trunk
working copy to "re-merge":

     floss$ cvs -q update -d -j Release-1999_05_01-bugfixes
     RCS file: /usr/local/cvs/myproj/hello.c,v
     retrieving revision 1.5
     retrieving revision 1.5.2.1
     Merging differences between 1.5 and 1.5.2.1 into hello.c
     RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
     retrieving revision 1.2
     retrieving revision 1.2.2.2
     Merging differences between 1.2 and 1.2.2.2 into random.c
     rcsmerge: warning: conflicts during merge
     floss$

As you can see, that didn't have quite the desired effect-we got a
conflict, even though the trunk copy hadn't been modified there and,
therefore, no conflict was expected.

The trouble was that the update command behaved exactly as described: It
tried to take all the changes between the branch's root and tip and
merge them into the current working copy.  The only problem is, some of
those changes had already been merged into this working copy.  That's
why we got the conflict:

     floss$ pwd
     /home/whatever/myproj
     floss$ cat b-subdir/random.c
     /* Print out a random number. */
     #include <stdio.h
     void main ()
     {
     <<<<<<< random.c
       printf ("A random number.\n");
     =======
       printf ("A random number.\n");
       printf ("Get the joke?\n");
     >>>>>>> 1.2.2.2
     }
     floss$

You could go through resolving all such conflicts by hand-it's usually
not hard to tell what you need to do in each file.  Nevertheless, it is
even better to avoid a conflict in the first place.  By passing two -j
flags instead of one, you'll get only those changes from where you last
merged to the tip instead of all of the changes on the branch, from root
to tip.  The first -j gives the starting point on the branch, and the
second is just the plain branch name (which implies the tip of the
branch).

The question then is, how can you specify the point on the branch from
which you last merged? One way is to qualify by using a date along with
the branch tag name.  CVS provides a special syntax for this:

     floss$ cvs -q update -d -j "Release-1999_05_01-bugfixes:2 days ago" \
                          -j Release-1999_05_01-bugfixes
     RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
     retrieving revision 1.2.2.1
     retrieving revision 1.2.2.2
     Merging differences between 1.2.2.1 and 1.2.2.2 into random.c
     floss$

If the branch tag name is followed by a colon and then a date (in any of
the usual CVS date syntaxes), CVS will include only changes later than
that date.  So if you knew that the original bug fix was committed on
the branch three days ago, the preceding command would merge the second
bug fix only.

A better way, if you plan ahead, is to tag the branch after each bug fix
(just a regular tag - we're not starting a new branch here or anything
like that).  Suppose after fixing the bug in the branch and committing,
you do this in the branch's working copy:

     floss$ cvs -q tag Release-1999_05_01-bugfixes-fix-number-1
     T README.txt
     T hello.c
     T a-subdir/whatever.c
     T a-subdir/subsubdir/fish.c
     T b-subdir/random.c
     floss$

Then, when it's time to merge the second change into the trunk, you can
use that conveniently placed tag to delimit the earlier revision:

     floss$ cvs -q update -d -j Release-1999_05_01-bugfixes-fix-number-1 \
                          -j Release-1999_05_01-bugfixes
     RCS file: /usr/local/cvs/myproj/b-subdir/random.c,v
     retrieving revision 1.2.2.1
     retrieving revision 1.2.2.2
     Merging differences between 1.2.2.1 and 1.2.2.2 into random.c
     floss$

This way, of course, is much better than trying to recall how long ago
you made one change versus another, but it only works if you remember to
tag the branch every time it is merged to the trunk.  The lesson,
therefore, is to tag early and tag often! It's better to err on the side
of too many tags (as long as they all have descriptive names) than to
have too few.  In these last examples, for instance, there was no
requirement that the new tag on the branch have a name similar to the
branch tag itself.  Although I named it
`Release-1999_05_01-bugfixes-fix-number-1', it could just as easily
have been `fix1'.  However, the former is preferable, because it
contains the name of the branch and thus won't ever be confused with a
tag on some other branch.  (Remember that tag names are unique within
files, not within branches.  You can't have two tags named `fix1' in
the same file, even if they refer to revisions on different branches.)


automatically generated by info2www version 1.2.2.9