© Copyright IBM Corp. 2003
 Eclipse Corner Article

 

Branching with Eclipse and CVS

Summary
This article presents a brief branch and merge scenario designed to quickly illustrate some branch and merge features of Eclipse's CVS integration. I assume the reader already appreciates the value of branching and merging in a source control environment. Little is said to justify it here. Rather, a step-by-step scenario illustrates the common branch and merge operations using Eclipse-based IDEs with CVS as the source control mechanism.

By Paul Glezen, IBM
July 3, 2003


Introduction

In any source control management (SCM) environment, branching is a powerful mechanism for controlled isolation. Despite being a simple concept, it is sometimes avoided because of its implementation complexities. This brief article demonstrates how to perform branching with Eclipse's CVS plug-in. The intended audience is software development professionals with an appreciation for the roles of branch and merge techniques in SCM.

The IBM® redbook, WebSphere® Studio Application Developer Programming Guide, contains a section entitled Streams in CVS. It addresses branching and merging using CVS with Eclipse. But many of the menu choices have changed since its publication. The Eclipse online documentation is accurate, but does not provide an end-to-end scenario. The intent of this article is to fill this gap. The version of Eclipse used for this article is 2.1.

The scenario is that of two programmers, Paul and Wing, working on separate branches of the same project. Paul will branch off main and modify some files while Wing continues to work on the main branch, also modifying files. Paul will then merge his branch back to the main branch. In doing so, Paul will address the resulting merge conflicts.

Elementary Branch Concept

Setup

The sample will use a few text files inside a simple project. In order to carry out the sample, you should already have a working connection to a CVS repository in your Eclipse workspace.

  1. Create a new simple project called brtest.

  2. Add a new file called f1.txt. Add the following contents.

    This file will only be edited
    by Paul
    
    This line will be changed later.
    
    The rest of this file will
    remain the same.
    

  3. Add a file called f2.txt with the following contents.

    This file will only be edited
    by Wing. 
    
    This line will be changed later.
    
    The rest of this file will
    remain the same.

  4. Add a file called f3trivial.txt with the following contents.

    This file will be edited by
    Paul and Wing.
    
    This line will be changed
    by Paul only.
    
    This line will be left alone.
    
    This line will be changed
    by Wing only.
    
    The rest of this file will
    remain the same.

  5. Add a file called f4conflict.txt with the following contents.

    This file will be edited by
    Paul and Wing.
    
    This line will be changed by
    by both Paul and Wing.
    
    The rest of this file will
    remain the same.

    After adding the above files, your workspace should look something like the screen shot below.

    Starting list of files in resource view

  6. Add the project to CVS. Right-click on the project folder and select Team --> Share Project. Select CVS as the project type and click Next. Choose a suitable respository and click Next. This creates an empty CVS project called brtest. We still need to add the files to source control and commit them.

  7. In the Synchronize - Outgoing Mode view, right-click the brtest folder and select Add to Version Control. Once again, right-click on the brtest folder and select Commit ... . Provide an initial comment such as "Initial Version."

This sets up the environment for Paul. Wing will work in her own workspace by retrieving the files from source control. For steps on setting up a new project from source control, see the following section in the Eclipse documentation: Workbench User's Guide --> Tasks --> Working in the team environment --> Checking out a project from a CVS repository.

Branch Method

When branching off a development stream, it is often advisable to rebase before merging the branch back to the main branch. To rebase means to merge the contents of the main branch to the subbranch. If any conflicts are to be resolved, they are done on the subbranch rather than the main branch. If the merge goes well, the subbranch is merged to the main branch. After having previously resolved all merge conflicts, this last merge would be a trivial one. The advantage of taking the extra rebase step is that it avoids having conflicts on the main branch.

For this simple example, Paul will simply merge his changes directly into the main branch. From the prospective of implementation details, the only difference is the merge target. Since this article is principally concerned with implementation details of the Eclipse branch support using CVS, the simplest branch method is sufficient.

Creating the Branch

At this point, Paul and Wing have the same version of all files. It is now time for Paul to create an independent branch on which to work.

  1. Right-click on the brtest project and select Team --> Branch .... A Create Branch dialog box is displayed. Enter a branch name like "p1test." Leave the check box checked for Start working in the branch. Notice that a version name is automatically filled in for you called "Root_p1test." You may choose a different name (so long as it doesn't conflict with an existing CVS tag). This will mark where the branch was created. It will be used later by the merge editor to determine what has changed since branch creation. Click OK.

    Dialog for creating a new branch

    You should be able to see the result of your branch in two ways. By right-clicking the project and selecting Properties and then CVS, you should see the p1test in the tag field. If you have the CVS label decorations enabled, you'll see the branch tag in the navigator view (see below).

    CVS labels indicating new branch

    To enable CVS label decorations, go to Window --> Preferences and navigate to Workbench --> Label Decorations. Check the CVS box.

  2. Paul will modify the first file using the p1test branch. Open the editor for f1.txt. Change line 4 from "This line will be changed later" to "This line has been changed." Save the change.

  3. Open the editor for f3trivial.txt. Change line 4 and 5 from "This line will be changed by Paul only" to "This line has been changed by Paul." Save the change.

  4. Open the editor for f4conflict.txt. Change lines 4 and 5 from "This line will be changed by both Paul and Wing" to "This line has been changed by Paul." Save the change.

  5. Right-click on the brtest project and select Team --> Synchronize with Repository. In the Outgoing Mode view, right-click the brtest project folder and select commit. Enter a comment such as "Changes made by Paul." Note that for files that have changed, the revision numbers are four digits. This is a CVS convention for branched revisions.

    Paul's CVS label decorations after commit

  6. Now it is Wing's turn. She will make her changes on the main branch. Since she already had the main branch loaded into her workspace, she doesn't need to perform a branch change. As Wing, begin editing f2.txt. Change "This line will be changed later" to "This line has been changed." Save the change.

  7. Edit f3trivial.txt in Wing's workspace. Change lines 9 and 10 from "This line will be changed by Wing only" to "This line has been changed by Wing." Save the change.

  8. Edit f4conflict.txt in Wing's workspace. Change lines 4 and 5 from "This line will be changed by Paul and Wing" to "This line was changed by Wing." Save the change.

  9. Commit Wing's changes. Notice her revisions numbers are all two digits. That's because her new revisions occur on the main branch.


The Merge

Now it is time for Paul to merge his changes into the main branch where Wing's work resides.

  1. The first step of the merge is to point the workspace to the target branch. In our case, the target of the merge is the main branch. To switch the project contents to that of the main branch, right-click on the brtest project in the Navigator view and select Replace with --> Branch or Version .... You should see a branch selection similar to the one below.

    Dialog for selecting new branch or version

  2. The p1test branch is the one Paul was working on. To switch back to the main branch, select HEAD. This is the CVS name for the main branch. Make sure Recurse into sub-folders is checked so that all the files in the project are replaced with the main branch contents. Then click OK.

    The resource view should look like the one below. Notice the version numbers correspond to what Wing committed. All the version numbers are two digits. The branch name is gone which implies the HEAD branch (or main).

    Resource view after switching back to main branch

  3. Right-click on the brtest project and select Team --> Merge .... This displays a panel allowing you to choose a "start point." For this example, the only start point available is Root_p1test, the one Paul made by creating the branch. Select it and click Next.

    Dialog for choosing a merge start point

  4. Next we specify from which branch to pull the changes. Expand the Branches node and select p1test. Click Finish.

    Dialog for selecting choosing a branch to merge

  5. This is where the fun begins. You will be presented with the Merge Editor's Structure Compare view with the following merge results.

    Merge tasks.

    f1.txt was not changed by Wing, so it will come in without a problem. But f3trivial.txt and f4conflict.txt were each modified by both Paul and Wing. These will require special attention during the merge.

  6. Right-click on the brtest folder and select Update from Repository. This action only operates on non-conflicting resources (those with no red marks) in the Structure Compare view. In our example, it pulls in the changes to f1.txt. This should leave your Structure Compare view with only two conflicts.

  7. Right-click f3trivial.txt in the Structure Compare view and select Merge changes into Local Copy. Since f3trivial.txt was a trivial merge, the merge editor automatically copies the changes from the p1test branch into our local copy of the main branch. Inspection of f3trivial.txt will reveal the changes made by both Paul and Wing.

    Note We haven't merged into main yet. That doesn't happen until we commit. For now we've just merged into our local copy; hence the name of the menu option.

    You should see an additional file, .#f3trivial.txt, in the resource view that isn't under source control. It contains a copy of the pre-merge contents for restoration purposes.

  8. Double-click f4conflict.txt to open the Structure Compare view of the merge tool. The left side of the Text Compare panel is the local copy of the main branch contents. The left side is the brtest branch contents. Since this is not a trivial merge, the color red is used to delineate the scope of each merge conflict. Blue would be used to denote trivial merges.

    Resolving conflicts with merge editor

    We can't resolve this conflict by simply using one side or the other. For this case, we edit the text in the left side to say "This line has been changed by Paul and Wing." Right-click in this same text window and select Save.

  9. Since we have finished manually merging f4conflict.txt, we no longer need to retain it in the Structure Compare view. Right-click f4conflict.txt in the Structure Compare view and select Remove From View. This only removes it from the view, not from the project.

  10. At this point, the merged copy only exists in our workspace. We still need to save it to the CVS respository. Select the brtets project in the Navigator view and select Team --> Synchronize with Repository. These changes should not present any conflicts. Right-click on the brtest folder in the Synchronize view and select Commit. A suitable comment would be "Merged prtest branch to main."

  11. A successful merge is often an occasion for a release. In CVS, this amounts to tagging all the files with a given tag. In this case, we'll tag it with "p12merge." Right-click the brtest project in the Navigator view and select Team --> Tag as version ... from its context menu. Enter the name "p12merge" for the tag name. Click Finish.


Summary

In this brief tutorial we illustrated the implementation steps for a simple branch and merge scenario. Several files were used to demonstrate different types of conflicts that arise during merge activity. In cases where two developers edited the same file, we saw the action taken by the Merge changes with Local Copy on a file with only trivial conflicts. We saw how to use the merge editor to manually resolve non-trivial conflicts. The appendix contains a re-run of steps 17 and 18 that use Merge changes with Local Copy on f4conflict.txt.

After the merge task was complete, we tagged the results to create a release. Others can then refer to this release using the name "p12merge." A summary of our actions for a single file is obtained by right-clicking on the file in the Navigator view and selecting Team --> Show in resource history. The resource history for f4conflict.txt is show below.

f4conflict.txt revision history

We can barely see the Root_p1test tag assigned to revision 1.1, the initial version. We see that Paul made changes that were committed to a branch while Wing made changes that were committed to main. Finally, the merge resulted in revision 1.3, which was tagged for posterity with the label "p12merge."

For a software developer, the task of merging ranks among status-reports and schedule-estimation in terms of loathing. It's not difficult to image how the seductively simple "trivial merge" can lead to subtle non-trivial problems in code. Eclipse's CVS integration strives to ease this burden by putting a friendlier face on branch and merge support.

Appendix

In steps 17 and 18, we chose to employ the manual merge facilities for the non-trivial merge. This appendix describes an alternative to these steps using the automated Merge Changes into Local Copy option. Upon encountering a non-trivial conflict, this option will insert merge markers in the file. The resource view will signify the merge conflict with a special icon marker.

This alternative works great for simple text files. For source code it can result in unexpected compilation behavior if incremental builds are enabled. For this reason, the manual merge step was chosen for steps 17 and 18 above. These steps are re-worked here using the automated approach for readers that prefer this method.

It is recommended that incremental compilation be disabled when using this method on source code files. This is done from the Windows --> Preferences dialog by selecting Workbench on the left side and unchecking Perform build automatically on resource modification.

  1. Right-click f4conflict.txt and select Merge changes into Local Copy. Since this is not a trivial merge, the result will contain merge markers that indictate where the conflict occurred. Markers in the resource view indicate which files were marged non-trivially.

    A merge conflict marker

    In the figure above, the non-trivial merge marker appears on f4conflict.txt.

    Note the presence of two additional files not under source control. .#f3trivial.txt and .#f4conflict.txt files contain copies of the pre-merge contents for restoration purposes.

  2. We now want to resolve the merge conflict for f4conflict.txt indicated in the resource view above. Open the f4conflict.txt in an editor.

    Merge markers in a file.

    Note the manner in which the merge editor calls attention to different versions of the same line. It is up to us to resolve the conflict and remove the markers. In this case, we replace the lines between ">>> f4conflict.txt" and "<<< 1.1.4.1", inclusive, to contain "This line has been changed by Paul and Wing." Then save the result.

    Notice that saving the result will change the merge conflict marker. The assumption is that the save action resolves the conflict.


References

Listed below are some references to which one can refer in addition to the Eclipse documentation.


IBM and WebSphere are registered trademarks of IBM Corp. in the United States, other countries, or both.