Topics Map >

Branching and Merging in CVS

Instructions on branching and merging in CVS

Contents

Notes:

  • Replace NEW_FEATURE with what you're doing, duh. :)
  • Lines broken with "\" are continued: The \ should be removed and the line continued as a single line.
  • sandbox is your checked-out copy of some module. It is assumed that you are at the location that you want to branch.
  • If you forget to move to your branch, see Correcting Accidental Checkin

Creating the Branch

  1. Tag the root of the branch, so you can get back.
    sandbox$ cvs tag NEW_FEATURE_ADD_ROOT
  2. Actually create the branch, at the point that you just marked.
    sandbox$ cvs tag -b -r NEW_FEATURE_ADD_ROOT \                 NEW_FEATURE_ADD_BRANCH
  3. Actually move your working directory in to the branch.
    sandbox$ cvs up -r NEW_FEATURE_ADD_BRANCH

You are now in the new branch, do what you want.

Correcting Accidental Checkin

Occasionally, we all make mistakes and forget step 3 in Creating the Branch, and check things in on the HEAD revision instead of our new branch. Here are the steps to fix that.

  1. FIRST CHECK TO SEE IF SOMEONE ELSE HAS MADE CHANGES If they have, it is beyond this simple tutorial to untangle the problems. Seek assistance from your local CVS Guru.
  2. Gather the differences since you made the branch (and forgot to get on to it):
    sandbox$ cvs diff -u -r NEW_FEATURE_ADD_ROOT > accident.diff
    (Assuming that accident.diff doesn't exist already. If it does, choose a new name.)
  3. Undo the changes:
    sandbox$ patch -p0 -R    
  4. Check in these changes, to revert the HEAD back to the way you found it.
    sandbox$ cvs ci
  5. Update your working directory to be on the branch:
    sandbox$ cvs up -r NEW_FEATURE_ADD_BRANCH
  6. Apply the changes to the branch
    sandbox$ patch -p0    
  7. Check the changes in on the branch.
    sandbox$ cvs ci

Merging Back Together

Note: The tag names have changed slightly. It is very important to use the prefixes merge_ and from_ appropriately, or your branches won't align nicely in CVSWeb.

  1. Tag the end of your branch
    sandbox$ cvs tag merge_NEW_FEATURE_ADD
  2. Move back to the head.
    sandbox$ cvs up -A
  3. Actually merge the code.
    sandbox$ cvs up -j NEW_FEATURE_ADD_BRANCH

    This will list:

    • "A filename" for files that you added
    • "M filename" for files that you modified
    • "C filename" for files that have conflicts
    Conflicts are files that you modified and that were modified on the head revision as well.

    Files with conflicts will have conflict markers in them. Conflict markers look like:

    <<<<<<< filename    your lines=======    other person's lines>>>>>>> current version
    • filename is the name of the file
    • your lines is the lines of your file that conflict with the lines that exist.
    • other person's lines is the lines the other person added while you were working.
    • current version is the current version (ie, the one the other person checked-in.)
    See The CVS Manual for a more concrete example.

    The new updates are now in your working directory. Even if you didn't get any conflicts, you have to verify that the CVS merge process didn't incorrectly merge your changes. Remember that just because CVS didn't find a direct conflict doesn't mean that the code logic is correct or that the program compiles, CVS knows nothing about the program or the programming language.

    A quick way to open all the files that have conflicts (in Vim):

    $ vim `cvs up -d | & grep '^C' | sed -e 's/^C //'` 
  4. Make sure that the changes look right
    sandbox$ cvs diff -uw
  5. Make sure that the code still functions
    sandbox$ sudo make install
    (Or however you install and test your code)
  6. Commit changes back to CVS.
    sandbox$ cvs ci
  7. Tag where things came back together
    sandbox$ cvs tag from_NEW_FEATURE_ADD

Merging to/from a branch multiple times

So, by now you may have figured out the magic of the merge_ and from_ tags. If not, here it is: They give you an anchor on where the changes happened, and they tell CVSGraph which way to draw the arrows (merge_ is the start of the arrow, from_ is the pointy end.) The name after merge_ and from_ don't matter, as long as they make sense (for what the branch does) and match.

If you're working on a branch, inevitably someone else checks in a change on the head (or merges another branch) adding functionality you want, or substantially changing code that you are about to (or have already) change.

To merge from the HEAD to your branch. (You can, of course, merge between branches, but depending on the branch-points, that can be tricky.) Another common usage is to merge from the branch to HEAD repeatedly, which I leave as an excercise to the reader (hint: you reverse the sources and targets in every step).

  1. Move from your branch to HEAD:
    $ cvs up -A
  2. Tag the HEAD where you are going to merge.
    $ cvs tag merge_HEAD_NEW_FEATURE_ADD
    I use HEAD_NEW_FEATURE_ADD to signify that it is merging HEAD to NEW_FEATURE_ADD.
  3. Go back to your branch
    $ cvs up -r NEW_FEATURE_ADD_BRANCH
  4. Do the merge
    $ cvs up -j HEAD
  5. Resolve conlicts, test, check-in etc (See steps 3-6 in Merging Back Together )
  6. Tag your branch where the merge landed.

    VERY IMPORTANT -- This records where the merge happened and is essential for when you want to merge again.

    $ cvs tag from_HEAD_NEW_FEATURE_ADD

If you want to merge from HEAD again, you can, just use another tag name, for example HEAD_NEW_FEATURE_ADD2:

  1. Move from your branch to the HEAD:
    $ cvs up -A
  2. Tag the HEAD where you are going to merge.
    $ cvs tag merge_HEAD_NEW_FEATURE_ADD2
  3. Go back to your branch
    $ cvs up -r NEW_FEATURE_ADD_BRANCH
  4. Do the merge
    $ cvs up -j merge_HEAD_NEW_FEATURE_ADD -j HEAD

    NOTE: the tag following the first -j is the previous merge tag.

    This tells CVS to merge changes that were added between the two tags.

  5. Resolve conlicts, test, check-in etc (See steps 3-6 in Merging Back Together )
  6. Tag your branch where the merge landed.
    $ cvs tag from_HEAD_NEW_FEATURE_ADD2

    Now you probably realize why this tag is important, without it you have nowhere to anchor to in step 4.

Replacing one Branch with Another

One branch in CVS (even HEAD) can be replaced with another using a similar syntax to a merge.

  1. Tag the end of your branch
    sandbox$ cvs tag merge_NEW_FEATURE_ADD
  2. Move back to HEAD, or to the branch you want to REPLACE:
    • To HEAD:
      sandbox$ cvs up -A
    • To another branch:
      sandbox$ cvs up -r ANOTHER_BRANCH
  3. Do the replace. (Order is important. Note that the version that is being replaced comes first.)
    • Replacing HEAD:
      sandbox$ cvs up -jHEAD -j NEW_FEATURE_ADD_BRANCH
    • Replacing another branch:
      sandbox$ cvs up -jANOTHER_BRANCH -j NEW_FEATURE_ADD_BRANCH
  4. Commit changes back to CVS.
    sandbox$ cvs ci
  5. Tag where things came back together
    sandbox$ cvs tag from_NEW_FEATURE_ADD



Keywords: branching merging cvs replace branch merge   Doc ID: 4087
Owner: Jon M.Group: Middleware
Created: 2005-10-19 19:00 CDTUpdated: 2010-08-18 19:00 CDT
Sites: Middleware