Chapter 6. Working in a Parallel Development Environment

This chapter describes techniques for working in an environment where elements are to be branched and merged.

Parallel Development Using Branches

ClearCase supports parallel development, in which an element evolves simultaneously along several branches, with new versions being added to each branch independently. Parallel development has many uses:

  • It allows different projects — for example, different versions of a product — to use the same source tree(s) at the same time.

  • It isolates the work of developers whose changes should not (yet) be dynamically shared with others.

  • It isolates work that should never be shared with others — for example, a bugfix in a “retired” release.

  • It prevents roadblocks — development need not cease during a software integration period; it can proceed on branches, to be reintegrated later.

A version tree can have any number of branches, organized in a hierarchy of arbitrary depth. A checkout can be performed on the main branch in one view, on the bug404 branch in another view, on the motif branch in yet another view, and so on.

Branches are merely logical structures for organizing the versions of an element. The storage requirement for an element with 100 versions is the same whether the version tree has a single branch, or many branches organized into a deep hierarchy. (In either case, all the versions of an element of type text_file are stored as deltas in a single structured file.)

`Working on a Subbranch'

ClearCase keeps your work on a project organized by operating at two levels (and keeping the levels synchronized):

  • Version control — At the individual-element level, new versions created for a particular project go onto a dedicated branch, as discussed above. This isolates the project's changes from other concurrent work.

  • Configuration management — At the aggregate (“entire-set-of-sources”) level, all the branches created in individual elements' version trees must form a well-defined, isolated group. The simplest way (and the ClearCase-standard way) to accomplish this grouping is to require that all the branches have the same name.

All like-named branches are created as instances of a single object, the branch type. When you modify a set of elements for a project, you create a branch in each element's version tree (or, more typically, ClearCase creates the branches for you). All the branches are instances of the same branch type, and have the same name. Thus, working on the project is often termed “working on a subbranch”, an abbreviation for “working on a set of like-named subbranches”.


Note: Each VOB must have its own branch type object.


Setting Up a View for Parallel Development

Chapter 4, “Setting Up a View,” included a general discussion of setting up a view. This section presents a view-setup procedure for (perhaps) the most typical situation: launching a new project that will work “on a branch”, starting from a well-defined baselevel. Suppose that:

  • Your username is sakai.

  • The baselevel is defined as “all versions labeled PROJ_BASE”.

  • Work for the project is to take place on branches names koala.

The following steps set up a view to work on this project, assuming that the PROJ_BASE version labels are all in place.

  1. Create the branch type — By convention, names for branch types have lowercase letters only:

    % cleartool mkbrtype koala
    Comments for "koala":
    branch type  for KOALA project, from baselevel defined by label PROJ_BASE
    .
    Created branch type "koala".
    

  2. Create the view — See Chapter 4, “Setting Up a View,” for a discussion of selecting a view's storage location, its view-tag, and so on.

    % cleartool mkview -tag sakai_koala ~/view/koala.vws
    Host-local path: pluto:/home/sakai/views/koala.vws
    Global path:     /net/pluto/home/sakai/views/koala.vws
    It has the following rights:
    User : sakai    : rwx
    Group: user     : rwx
    Other:          : r-x
    

  3. Configure the view for your project — Establish the standard “working on a branch” config spec, using the particular version label and branch names for your project.

    % cleartool edcs -tag sakai_koala
      .
      .  use text editor to revise current config spec:
         element * CHECKEDOUT
         element * .../koala/LATEST
         element * PROJ_BASE -mkbranch koala
         element * /main/LATEST -mkbranch koala
    

This view is now ready to be used for project-specific work.

Automatic Creation of Branches

The last two config spec rules listed in Step 3 take advantage of ClearCase's auto-make-branch facility. Using this feature guarantees that all modifications you make to elements in this view will be made on a koala branch. It also simplifies your work, by automatically creating such branches, as needed — that is, the first time you checkout an element in this view.

The auto-make-branch facility hides the difference between “working on the main branch” and “working on a subbranch” — checkout and checkin are the only commands you need to modify sources on branches, and you do not even need to remember the branch name! For most purposes, you can “forget” about the special way in which your work is organized, leaving that job to ClearCase.

Working in a Multiple-View Environment

This section presents some useful techniques for working in a group environment where each user works in a separate view. Before accessing a view — in particular, one whose storage directory is located on a remote host — you may first need to activate the view on your host. You can check the ClearCase viewroot directory to determine whether the view is active. For example, this command determines whether view alpha is active on your host:

% ls /view | grep alpha

An active view appears as a subdirectory entry in the viewroot directory, /view.

Alternatively, enter an lsview command to determine whether a view is active on your host:

% cleartool lsview alpha
* alpha           /net/ccsvr01/shared_views/alpha.vws


Note: Asterisk (*) indicates view is active on the local host.

If a view is not active on your host, enter a startview command to activate it:

% cleartool startview alpha

Using a File in Another View

If you are set to a particular view, you may still occasionally wish to access data stored in (or merely visible in) other views. You can use a view-extended pathname access any object within another active view:

% grep 'order-dependent' /view/alpha/vobs/project/src/util.c

View-extended pathnames work no matter what your current view context: you can be set to another view, set to the same view, or not set to any view at all.

Comparing Your Version of an Element to Another View's

You may sometimes wish to compare a version selected by your view with the version of the same element selected by another view. If the element appears at the same pathname in both views, you can use the command substitution feature of UNIX shells:

% cleartool setview david
% cd /vobs/project/src
% cleardiff util.c /view/alpha/`pwd`/util.c

You could also use the standard diff(1) command, or access cleardiff with a cleartool diff command. Some variants of diff allow you to omit the redundant “util.c” at the end of the command.

Resolving Namespace Differences between Views

Sometime, the same element appears at different pathnames in different views. ClearCase can track directory-level changes, from simple renamings to wholesale reorganizations. In such situations, a colleague may direct your attention to a particular element, using a pathname that is not valid in your view. Given the “foreign” pathname to the object, you can use a describe -cview command to determine its pathname in your own view:

% cleartool describe -cview \
 /view/gordon/vobs/project/include/hello_base.h@@
file element "/vobs/project/src/hello.h@@"
  created 20-May-93.14:46:00 by rick.devt@saturn
  .
  .

You might then compare your version of the element with your colleague's version as follows:

% cleardiff hello.h \
 /view/gordon/vobs/project/include/hello_base.h

Merging Versions of an Element

In a parallel development environment, the “flip side” of branching is merging. In the simplest scenario, the changes made by a project “on a subbranch” are incorporated back into the main branch:

  • If there has been no activity on the main branch of an element in the meantime, this involves a trivial copy operation.

  • If an element's main branch has evolved, than an intelligent manual or (preferably) automated merge operation is required.

More generally, work from any branch can be merged into any other branch. ClearCase includes automated merge facilities for handling just about any scenario. Often, all of a project's work can be integrated with other work using a single command.

A merge involves computation of the “sum-of-pairwise-differences” of a set of files and/or versions (Figure 6-1).

Figure 6-1. ClearCase Merger Algorithm


Critical to this algorithm is the appropriate selection of one file to be the base contributor. Usually, ClearCase selects the base automatically, and can even take into account previous merges, in order to simplify and speed its work. For special

cases, you can specify a particular base contributor to the merge command; this command also has options (-insert and -delete) to implement common special cases.

The xcleardiff utility makes it easy to merge versions of an element, even when you need to make “manual” adjustments. Merge output appears in an edit panel, in which you can make minor edits directly; for more significant changes, you can pause the xcleardiff session to invoke your favorite text editor at any time. The current contents of the edit panel are channeled to your editor; when you return to xcleardiff, the changes you've made “externally” appear the edit panel, appropriately annotated (Figure 6-2).

Figure 6-2. xcleardiff Graphical Merge Utility


The following sections present a series of “merge scenarios” — situations that call for information on one branch of an element to be incorporated into another branch. In each scenario, we show the version tree of an element that requires a merge, and indicate the appropriate command to perform the merge.

Scenario: Merging All the Changes Made on a Subbranch

This is the simplest case (Figure 6-3). Bugfixes for an element named opt.c are being made on branch r1_fix, which was created at the baselevel version RLS1.0 (/main/4). Now, all the changes made on the subbranch are to be incorporated back into main, where a few new versions have been created in the meantime.

Figure 6-3. Version Tree of an Element Requiring a Merge


Set a view configured with the default config spec:

element * CHECKEDOUT
element * /main/LATEST

Go to the source directory and enter this command to perform the merge:

% cleartool findmerge opt.c -fversion .../r1_fix/LATEST

Scenario: Selective Merge from a Subbranch

This a variant of the preceding merge scenario. The project leader wants the changes in version /main/r1_fix/4 (and only that version — it's a particularly critical bugfix) to be incorporated into new development. In performing the merge, you specify which version(s) on the r1_fix branch to be included as shown in Figure 6-4.

Figure 6-4. Selective Merge of a Version from a Subbranch


In a view configured with the default config spec, enter these commands to perform the selective merge:

% cleartool checkout opt.c
% cleartool merge -to opt.c -insert -version /main/r1_fix/4

You can also specify a range of consecutive versions to be merged. For example, this command merges selects only the changes in versions /main/r1_fix/2 through /main/r1_fix/4:

% cleartool merge -to opt.c -insert -version /main/r1_fix/2 \
/main/r1_fix/4

Scenario: Removing the Contributions of Some Versions

The project leader has decided that a new feature, implemented in versions 14 through 16 on the main branch in Figure 6-5, will not be included in the product. You must perform a “subtractive merge” to remove the changes made in those versions.

Figure 6-5. Subtractive Merge


Enter these commands to perform the subtractive merge:

% cleartool checkout opt.c
% cleartool merge -to opt.c -delete -version /main/14 /main/16

Scenario: Merging an Unreserved Checkout

ClearCase allows the same version to have several checkouts at the same, each in a different view. At most one of the checkouts is reserved — all the others (or perhaps every one of them) is unreserved. This mechanism allows several users to work on the same file at the same time, without having to use separate branches.

To prevent confusion and loss of data in such situations, ClearCase imposes a constraint: if the version from which you performed an unreserved checkout (version 7 in Figure 6-6) is not the most recent version on the branch, then you cannot simply checkin your work — this would obliterate the contributions of the versions created in the interim (versions 8 and 9 in Figure 6-6). Instead, you must first merge the most recent version into your checked-out version, then perform the checkin.

Figure 6-6. Merge of an Unreserved Checkout


Enter these commands to merge your unreserved checkout:

% cleartool merge -to opt.c -version /main/9 
                                         (Step 3 in Figure 6-6)
% cleartool checkin opt.c                    
                                         (Step 4 in Figure 6-6)

Scenario: Merging All of a Project's Work

In the preceding scenarios, a merge was performed on a single element; now for a more realistic scenario. Suppose a team of developers has been working in isolation on a project for an extended period (weeks or months). Now, your job is to merge all the changes back into the main branch.

The findmerge command has the tools to handle most common cases easily. It can accommodate the following schemes for isolating the project's work.

All of Project's Work Isolated “On a Branch”

In the standard ClearCase approach to parallel development, all of a project's work takes place “on the same branch”. More precisely, new versions of source files are all created on like-named branches of their respective elements (that is, on branches that are instances of the same branch type). This makes it possible for a single findmerge command to locate and incorporate all the changes. Suppose the common branch is named gopher. You can enter these commands in a “mainline” view, configured with the default config spec:

% cd root-of-source-tree
% cleartool findmerge . -fversion .../gopher/LATEST \
-merge -xmerge

The -merge -xmerge syntax causes the merge to take place automatically whenever possible, and to bring up the graphical merge utility if an element's merge requires user interaction (see Chapter 7, “Comparing and Merging Files Graphically with xcleardiff.”) If the project has made changes in several VOBs, you can perform all the merges at once by specifying several pathnames, or by using the -avobs option to findmerge.

All of Project's Work Isolated “In a View”

Some projects are organized so that all changes are performed in a single view (typically, a shared view). For such projects, use the -ftag option to findmerge. Suppose the project's work has been performed in a view whose view-tag is goph_vu. These commands perform the merge:

% cd root-of-source-tree
% cleartool findmerge . -ftag goph_vu -merge -xmerge

Scenario: Merging a New Release of an Entire Source Tree

Here is another project-level merge scenario as shown in Figure 6-7. Your group has been using an externally-supplied source-code product, maintaining the sources in a VOB. The successive versions supplied by the vendor are checked into the main branch and labeled VEND_R1 through VEND_R3. Your group's fixes and enhancements are created on subbranch enhance. The views in which your group works are all configured to branch from the VEND_R3 baselevel:

element * CHECKEDOUT
element * .../enhance/LATEST
element * VEND_R3 -mkbranch enhance
element * /main/LATEST -mkbranch enhance

  • The version trees illustrated below shows three different likely cases:

  • an element that your group started changing at Release 1 (enhance branch created at the version labeled VEND_R1)

  • an element that your group started changing at Release 3

  • an element that your group has never changed

    Figure 6-7. Merge a New Release of an Entire Source Tree


Now, a tape containing Release 4 arrives, and you need to integrate the new release with your group's changes. After you add the new release to the main branch and label the versions VEND_R4, it will be easy to specify the merge process: “for all elements, merge from the version labeled VEND_R4 to the most recent version on the enhance branch; if an element has no enhance branch, don't do anything at all”

Here's a complete procedure for accomplishing the integration:

  1. Load the vendor's “Release 4” tape into a standard UNIX directory tree:

    % cd /usr/tmp
    % tar -xv
    

    Suppose this creates directory tree mathlib_4.0.

  2. As the VOB owner, run the UNIX-to-ClearCase conversion utility, clearcvt_unix, to create a script that will add new versions to the main branches of elements (and very likely, to create new elements, as well).

    % cd ./mathlib_4.0
    % clearcvt_unix
     . (lots of output)
     .
    

  3. In a view configured with the default config spec, run the conversion script created by clearcvt_unix, creating Release 4 versions on the main branches on elements:

    % cleartool setview mainline
    % cd /vobs/proj/mathlib
    % /usr/tmp/mathlib_4.0/cvt_dir/cvt_script
    

  4. Label the new versions:

    % cleartool mklbtype -c "Release 4 of MathLib \ 
            sources" VEND_R4 
    Created label type "VEND_R4".
    % cleartool mklabel -recurse VEND_R4 /vobs/proj/mathlib
     . (lots of output)
     .
    

  5. Go to a view that is configured with your group's config spec, selecting the versions on the enhance branch:

    % cleartool setview enh_vu
    

  6. Merge from the VEND_R4 configuration to your view:

    % cleartool findmerge /vobs/proj/mathlib -fver \
            VEND_R4 -merge -xmerge  
    

    The -merge -xmerge syntax says “merge automatically if possible; but if not possible, bring up the graphical merge tool”.

  7. Verify the merges, and checkin the modified elements.

  8. You have now established Release 4 as the new baselevel. Developers in your group can update their views' configurations as follows:

    element * CHECKEDOUT
    element * .../enhance/LATEST
    element * VEND_R4 -mkbranch enhance
    element * /main/LATEST -mkbranch enhance
    


    Note: VEND_R3 was changed to VEND_R4 in Step 8.

    Elements that have been active will continue to evolve on their enhance branches. Elements that are revised for the first time will have their enhance branches created automatically at the VEND_R4 version.

Scenario: Merging Directory Versions

One of ClearCase's most powerful features is versioning of directories. Each version of a directory element catalogs a set of file elements, directory elements, and VOB symbolic links. In a parallel development environment, directory-level changes are just as frequent as file-level changes. And with ClearCase, merging the changes to another branch is just as easy.

Let's take a closer look at the externally-supplied source tree scenario from the preceding section: suppose you find that in the vendor's new release (the one you've labeled VEND_R3), several changes have been made in directory /vobs/proj/mathlib/src:

  1. file elements Makefile, getcwd.c, and fork3.c have been revised

  2. file elements readln.c and get.c have been deleted

  3. a new file element, newpaths.c, has been created

When you use findmerge to merge the changes made in the VEND_R3 release out to the enhance branch (Step #6 in “Scenario: Merging a New Release of an Entire Source Tree”), both the file-level changes (Step #1 in this section “Scenario: Merging Directory Versions”), and the directory-level changes (Step #2 and #3 in this section “Scenario: Merging Directory Versions”), are handled automatically.

The following findmerge excerpt in Example 6-1 shows the directory-level merge activity.

Example 6-1. Directory -level Merge Activity


********************************
<<< directory 1: /vobs/proj/mathlib/src@@/main/3
>>> directory 2: .@@/main/enhance/1
>>> directory 3: .
********************************
----[ removed directory 1 ]----|----[ directory 2 ]----
get.c  19-Dec-1991 drp         |-
*** Automatic: Applying REMOVE from directory 2
----[ directory 1 ]----|----[ added directory 2 ]----
                      -| newpaths.c  08-Mar.21:49 drp
*** Automatic: Applying ADDITION from directory 2
----[ removed directory 1 ]----|----[ directory 2 ]----
readln.c  19-Dec-1991 drp      |-
*** Automatic: Applying REMOVE from directory 2
Recorded merge of ".".

Using Your Own Merge Tools

If you wish, you can create a merged version of an element completely manually, or with any available analysis and editing tools. Check out the target version, revise it, and check it back in. Just before (or just after) the checkin, be sure to record your activity, by using the merge command with the -ndata (“no data”) option:

% cleartool checkout -nc nextwhat.c
Checkout comments for "nextwhat.c":
merge enhance branch
.
Checked out "nextwhat.c" from version "/main/1".
% <Invoke your tools to merge data into checked-out version>
% cleartool merge -to nextwhat.c -ndata -version \
 .../enhance/LATEST
Recorded merge of "nextwhat.c".

This form of the merge command does not change any file system data — it merely attaches a merge arrow (a hyperlink of type Merge) the specified versions. After you've made this annotation, your merge is indistinguishable from one performed only with ClearCase tools.