In preceding lessons, you performed two different development tasks, using two different views:
In Lesson 2, you did some new development using view USER_HOST_tut, starting from the source base for the REL2 release. Since this is a tutorial, not “real life”, the development involved changing a single source file, util.c.
In Lesson 5, you fixed a bug in the REL2 release, using view USER_HOST_fix. Once again, the change involved a single source file—and once again, it was util.c.
In this lesson, you'll resume your new development work, having fixed the bug. The diversion wasn't a waste of time, however. The bug in the time string still exists in your new-development version (the most recent version on the main branch). As you move the hello program into the future, you can (and should) also cleanse it of its past sins. ClearCase makes this easy—the process of merging changes made on subbranches (for example, rel2_bugfix) into the main line of development (the main branch) is highly automated.
The merge facility encourages frequent use of branches for development tasks, and frequent resynchronizing of the branches. This methodology allows people to keep working: for example, a release engineer might require that a file be “frozen” at a particular version. Furthermore, a developer might need the frozen version's branch for last-minute fixes or workarounds. In such situations, a developer can simply make a branch off the frozen version, and keep working. After the release engineer has relinquished control of the branch, the developer can merge his or her changes back into it.
At the end of the preceding lesson, you were in your original directory (we suggested that you start this tutorial in your home directory), in a shell that was not set to any view. Verify that you are still in the same situation.
% cleartool pwv -short ** NONE ** % pwd HOME |
If you've gotten lost, find out whether your current shell is set to a view:
cleartool pwv |
If you are set to a view, exit the shell process, in order to return to a shell that is not set to a view. (Try cleartool pwv again, to make sure!) Then return to the directory you were in when you started this tutorial (for example, with the command cd $HOME).
Let's suppose that the only new feature to be added is an enhancement to the env_user() function in file util.c—if the user happens to be root, an appropriately respectful message is to be substituted for the standard message:
Hello, Your Excellency. |
... instead of:
Hello, root. |
To resume your new development work, return to the USER_HOST_tut view, and go to the source directory.
% cleartool setview USER_HOST_tut % cd VOBTAG/src |
For each file with a rel2_bugfix branch, you must merge the changes on this branch back into the main branch. The introduction to this lesson indicated that the only such file is util.c. Let's make sure. The cleartool findmerge command provides the answer.
% cleartool findmerge . -fversion /main/rel2_bugfix/LATEST -print
Needs Merge "util.c" [to /main/2 from /main/rel2_bugfix/1 base /main/1]
A 'findmerge' log has been written to "findmerge.log.03-Apr-94.13:39:44"
% cat findmerge.log.03-Apr-94.13:39:44
cleartool findmerge ./util.c@@/main/2 -fver /main/rel2_bugfix/1
-log /dev/null -merge
|
This is an elegant way to answer the “what's changed” question. For each VOB element in the current directory, findmerge compared the version selected by the current view to the LATEST version on the rel2_bugfix branch (ignoring elements without a rel2_bugfix branch).
The log file produced by findmerge includes the actual command that would perform the required merge. In fact, we could have had findmerge go ahead and perform the merge, but we chose the -print option instead, as we have a change to make on the “mainline” before we merge in the bug fix changes.
Here are two additional ways to verify that only util.c has changed:
Derived object comparison--you've used this technique already. In Step 58, you compared two instances of hello:
cleartool diffcr hello /view/USER_HOST_tut/'pwd'/hello |
This command compared the derived object instance you had just built in view USER_HOST_fix (Step 55) with the instance you had built earlier in view USER_HOST_tut (Step 23). The comparison showed that the only source-level difference was in file util.c.
View-based source tree comparison--you can compare the views USER_HOST_fix and USER_HOST_tut (your current view) on the basis of what source versions they select.
% cleartool ls -vob_only -short Makefile@@/main/2 hello.c@@/main/3 hello.h@@/main/1 util.c@@/main/2 % cleartool ls -vob_only -short /view/USER_HOST_fix/'pwd' /view/USER_HOST_fix/VOBTAG/src/Makefile@@/main/2 /view/USER_HOST_fix/VOBTAG/src/hello.c@@/main/3 /view/USER_HOST_fix/VOBTAG/src/hello.h@@/main/1 /view/USER_HOST_fix/VOBTAG/src/util.c@@/main/rel2_bugfix/1 |
The listing corroborates the fact that only file util.c was changed for the bugfix. Similarly, we can use findmerge with the -ftag option (rather than -fversion) to find the files modified for the Rel2 bugfix. The -ftag argument compares versions in different views, rather than versions on different branches. (The -whynot option explains why the other files do not need to be merged.)
% cleartool findmerge . -ftag USER_HOST_fix -whynot -print
No merge "." [to/from same version /main/2]
No merge "./Makefile" [to/from same version /main/2]
No merge "./hello.c" [to/from same version /main/3]
No merge "./hello.h" [to/from same version /main/1]
Needs Merge "util.c" [to /main/2 from /main/rel2_bugfix/1 base /main/1]
A 'findmerge' log has been written to "findmerge.log.04-Apr-94.10:22:37"
% cat findmerge.log.04-Apr-94.10:22:37
cleartool findmerge ./util.c@@/main/2 -fver
/main/rel2_bugfix/1
-log /dev/null -merge
|
Let's go ahead and add the new development changes to util.c, then merge in the bugfix changes.
As always, the first step in modifying a source file is to perform a checkout. Since you have returned to a view with the default config spec, the checkout occurs on the main branch.
% cleartool checkout -nc util.c Checked out "util.c" from version "/main/2". |
Now, put in the change to the message displayed to a superuser.
% cp /usr/atria/doc/tutorial/ut.4 util.c
% cleartool diff -pred util.c
********************************
<<< file 1: VOBTAG/util.c@@/main/2
>>> file 2: util.c
********************************
---------[changed 7-8]--|-------[changed to 7-12]------
if (user_env) | if (user_env) {
return user_env; | if ( strcmp(user_env,"root") == +
-| return "Your Excellency";
| else
| return user_env;
| }
|-
|
You would typically compile and test this change, but let's go ahead and merge in the bugfix change first.
The merge compares three versions of the file element: the two versions to be merged and their “common ancestor”:
The versions to be merged are termed contributors. Their common ancestor is termed the base version--it is automatically determined by the merge or findmerge command.
The merge algorithm involves comparing each contributor with the base version separately. For a given section of code, if just one of the contributors differs from the base version, that change is adopted automatically. If each contributor has a different change from the base version (a conflict), you are prompted to decide which change to use.
The merge process typically overwrites the contents of contributor util.c with the merged result. The overwritten data is not lost, however; it is saved as util.c.contrib.
% cleartool findmerge . -fversion /main/rel2_bugfix/LATEST -merge -xmerge
Needs Merge "./util.c" [to /main/CHECKEDOUT from /main/rel2_bugfix/1 base /main/1]
********************************
<<< file 1: VOBTAG/src/util.c@@/main/1
>>> file 2: VOBTAG/src/util.c@@/main/rel2_bugfix/1
>>> file 3: util.c
********************************
(See Step 68 for the following)
---------[changed 7-8 file 1]--------|-------[changed to 7-12 file 3]-------
if (user_env) | if (user_env) {
return user_env; | if ( strcmp(user_env,"root") == +
-| return "Your Excellency";
| else
| return user_env;
| }
|-
*** Automatic: Applying CHANGE from file 3 [lines 7-12]
============
============
(See Step 22 for the following)
----------[after 15 file 1]----------|-------[inserted 20-21 file 3]--------
-| char *b,*c;
|
|-
*** Automatic: Applying INSERT from file 3 [lines 20-21]
============
============
--------[changed 19-20 file 1]-------|------[changed to 25-35 file 3]-------
else | else {
return home_env; | if ( strncmp("/net/", home_env, +
-| /* strip prefix from pathname +
| b = strchr(home_env+1, '/');
| c = strchr(b+1, '/');
| return c;
| } else {
| /* use pathname as-is */
| return home_env;
| }
| }
|-
*** Automatic: Applying CHANGE from file 3 [lines 25-35]
============
============
(See Step 54 for the following)
----------[after 25 file 1]----------|---------[inserted 26 file 2]---------
-| char *s;
|-
*** Automatic: Applying INSERT from file 2 [line 26]
============
============
---------[changed 28 file 1]---------|------[changed to 29-31 file 2]-------
return ctime(&clock); | s = ctime(&clock);
-| s[ strlen(s)-1 ] = '\0';
| return s;
|-
*** Automatic: Applying CHANGE from file 2 [lines 29-31]
============
============
Moved contributor "./util.c" to "./util.c.contrib".
Output of merge is in "./util.c".
Recorded merge of "./util.c".
(hyperlink of type Merge)
A 'findmerge' log has been written to "findmerge.log.22-Mar-94.10:27:31"
|
The -merge option says “do the merge.” The -xmerge option says to bring up the interactive X window system utility xcleardiff to process any conflicts that require human intervention.
In this case, all the changes are applied automatically, since there were no conflicts between the changes made on the rel2_bugfix branch and the changes made on the main branch. If you had changed the same section of code both on the main branch and on the rel2_bugfix branch, cleartool would prompt you to select one of the changes (or neither).
Note that these four commands (and some others) would have performed the merge as well:
cleartool findmerge . -ftag USER_HOST_fix /main/rel2_bugfix/LATEST -merge -xmerge cleartool xmerge -to util.c -ver /main/rel2_bugfix/1 cleartool merge -to util.c util.c@@/main/rel2_bugfix/LATEST cleartool findmerge ./util.c@@/main/CHECKEDOUT -fver /main/rel2_bugfix/1 -log /dev/null -merge |
Note, also, that the last of these commands is not identical to the one stored in the log file from our earlier findmerge (Step 66). Having checked out and modified util.c since then, merging to util.c@@/main/2 would have been a mistake.
The merge of data from the /main/rel2_bugfix/1 version to the currently checked-out version is recorded as a hyperlink of type Merge between the versions. Conceptually, a hyperlink is an arrow connecting two VOB objects. The describe command shows all meta-data attached to an object, including hyperlinks.
% cleartool describe util.c
version "util.c@@/main/CHECKEDOUT" from /main/2 (reserved)
checked out DATESTRING by USER.GROUP@HOST
by view: "HOST:HOME/tut/tut.vws"
element type: text_file
predecessor version: /main/2
Hyperlinks:
Merge@nnn@VOBTAGVOBTAG/src/util.c@@/main/rel2_bugfix/1 ->
VOBTAG/src/util.c@@/main/CHECKEDOUT.nnn
|
If you are running the X Window System, you can also use the command xlsvtree util.c to display a graphical version tree for util.c. The xlsvtree utility uses arrows to display hyperlinks. (To exit xlsvtree, use the Tool menu.)
To determine the effect of the merge, compare the new contents of util.c with its former contents, now stored in util.c.contrib.
% cleardiff util.c.contrib util.c
********************************
<<< file 1: util.c.contrib
>>> file 2: util.c
********************************
-----------[after 40]-------|----------[inserted 41]--------
-| char *s;
|-
----------[changed 43]------|---------[changed to 44-46]-----
return ctime(&clock); | s = ctime(&clock);
-| s[ strlen(s)-1 ] = '\0';
| return s;
|-
|
![]() | Note: If you are using X Windows, you might try: |
xcleardiff util.c.contrib util.c |
Let's see if the merge has produced a correct version of util.c.
% clearmake -v hello
Cannot reuse "util.o" - version mismatch for "util.c"
======== Rebuilding "util.o" ========
cc -c util.c
Will store derived object "VOBTAG/src/util.o"
========================================================
Must rebuild "hello" - due to rebuild of subtarget "util.o"
======== Rebuilding "hello" ========
cc -o hello hello.o util.o
Will store derived object "VOBTAG/src/hello"
========================================================
|
So far, so good—the program recompiles.
Now, let's see if the merged util.c has produced a hello program that executes correctly.
% ./hello Hello, USER! Your home directory is /home/USER. It is now DATESTRING. |
It does!
Recall that you put in a change that handles a superuser differently from an ordinary user. A look at the code (Step 68) indicates that you can fool the hello program into thinking you are a superuser simply by changing the value of the USER environment variable. Do it in a short-lived Bourne shell, to minimize the risk to the current shell.
% env USER=root hello Hello, Your Excellency! Your home directory is /home/USER. It is now DATESTRING. |
Everything is working fine.
You've enhanced the hello program, and you've integrated a bugfix change. Now, the boss says, “Ship it!”, so let's package your work as an official “release”.
As always, the first thing to do is to make sure all source files are checked in.
% cleartool lscheckout DATESTRING USER checkout version "util.c" from /main/2 (reserved) % cleartool checkin util.c Checkin comments for "util.c": special form of username message for root user merge in fix to time string from bugfix branch . Checked in "util.c" version "/main/3". |