Part one of this article introduced the compare support for UML models in IBM® Rational® Software Architect (IRSA), and the smaller IBM® Rational® Software Modeler (IRSM) product variant. We looked at the Compare With Local History command, exploring the following:
- The compare editor for models
- How differences are summarized and highlighted
- View modes
- And so on
This part of the article will continue exploring Eclipse compare and merge scenarios. For the other parts in this series, see Resources.
Eclipse compare support workflows
Eclipse compare and merge facilities are used in two common work flows:
- Compare or replace with local history, which may be invoked from the context menu of any selected resource. A dialog shows all previously saved states for the resource, and when you click on a date stamp, the current resource state is compared with the selected saved state. The replace variant allows the current artifact to be overwritten with any previously saved version of the artifact. This use case is covered in Part 1 of this series.
- Compare with each other, which may be invoked from a navigator view context menu when two or three resources are selected. You would use this workflow to compare or merge artifacts that are managed manually in the workspace. The models must be of common ancestry in order for comparison to work. The two-way and three-way merging use cases are covered in this article.
The following terms are used without further explanation in the rest of this article. Please review these before proceeding.
Ancestor: an artifact that is the common parent for other models. In a three-way merge, the ancestor is compared against each of the contributors to generate lists of differences. The differences are then compared to generate a list of conflicts.
Artifact: any file that is stored in an Eclipse project. An artifact may contain a whole model, or it may be one of several physical artifacts that constitute a larger logical model. In Eclipse, artifacts are often called resources.
Automatically resolvable conflict: any conflict where the result of accepting the change in either contributor is identical.
Base: same as ancestor.
Composite difference group: a group of related differences. All diagrams are represented by composite difference groups so that the user can operate on the whole diagram as a group, and so that clutter is reduced when several diagrams have changed. Composite difference groups can be atomic, where accepting or rejecting one member difference automatically performs the same operation on the whole group. Furthermore, a single difference can be a member of more than one composite difference group.
Conflict: two differences that are incompatible with each other. This can only occur during a three-way merge. Some examples are: (1) each contributor changed a class's name; (2) one contributor moved a class to another package while the other deleted the target package entirely; (3) one contributor added an operation to a class and the other contributor deleted the class. When both contributors make identical changes, a conflict is noted but is automatically resolved.
Contributor: one participant in a two-way or three-way merge. A contributor is compared to an ancestor (base) model to generate a list of differences. The two contributors in a three-way merge are never directly compared.
Cross-model reference: a reference that crosses the boundary between two physical artifacts. In IRSA, a good example of this is a reference from a class's view on a diagram in one model artifact to the semantic class object in a package in a different model artifact.
Custom profile: a meta-model extension that is created and managed locally.
Diagram: one specific pictorial view into a model's semantic data (for example, a class diagram or sequence diagram). A model (*.emx) may contain many diagrams.
Diagram (2): the output of a visualization operation, usually stored in an artifact with a .dnx, .tpx, .iex or .idx extension.
Delta: same as difference.
Difference: one change between an ancestor artifact and a contributor artifact. The five differences that are recorded are: add, change, delete, move and reorder. Reorder is actually a specialized move from one position to another inside the same list.
EMF: Eclipse Modeling Framework. This is the low-level modeling format in which you develop and store your UML models in IBM's Rational software products. A single UML construct may require multiple EMF constructs. This shows up in compare and merge sessions because all underlying changes to the model must be accounted for in the difference list.
Model: a UML model created by IRSA. The file extension for a model is .emx.
Profile: an extension to a UML meta-model, stored in an artifact with a .epx extension.
Reference: a pointer from one element in a model to another. The classic example is a class's view on a diagram pointing to the actual class object in a package in the model.
Compare with Each Other
The compare with each other command allows for comparison between two or three versions of a model in your Eclipse workspace. In the IRSA model compare support, a merge session is always started for compare commands (because the compare always generates a separate merged model). You can write the merged model to any location at any time using the Save a Copy button in the top right corner of the merged model pane. Also in that area of the merged model pane are buttons to save over each contributor. These are enabled when their respective contributors are writable.
For comparison to function, the models must come from a common ancestor at some point - which really means that the root model element in each of the files must have the same identity, or the error shown in Figure 1 will occur.
Figure 1. Failure when models do not have the same ancestor
The primary reason for comparing two or three models is so that you can understand and perhaps combine changes that have been made in parallel. The examples in this article, therefore, are all based on a desire to do some parallel development on your model with a co-worker. Say you send a copy of the model to a co-worker and continue working on it yourself. When your co-worker sends back the modified copy, you want to merge his or her changes with yours.
To accomplish this result, you can perform a two-way merge on the two changed models, applying the changes from your co-worker's copy to your copy. Alternately -- if you saved a copy of the original model before you made your changes -- you can run a three-way merge and accept changes from each side, resolving conflicting changes along the way. Three-way comparison provides more information as to what was changed by each of you, and allows you to accept or reject changes from either modified model with great precision. The saved copy is, of course, the common ancestor for the two changed models. The two flows look like Figure 2.
Figure 2. Two-way and three-way parallel development work flows
Starting with the model (hw1.emx) from Part 1 of this article, make a copy (hw2.emx) for your co-worker and make changes to each copy independently. In order to be able to contrast the two-way and three-way scenarios, you're actually going to make two copies (adding an hw3.emx) and then compare hw2 (co-worker's copy) to hw3 (your copy) in two-way mode. You'll later compare all three of them in three way mode (hw1 will be the ancestor.)
Copy the models
Copying the models is a simple workspace operation, accomplished by right-clicking the model and using the appropriate commands from the context menu. Figures 3 through 6 show one flow to make this clear.
Figure 3. Copy the model
Figure 4. Paste the new model
Figure 5. Rename on paste
Figure 6. Workspace with three identical copies
Change both copies independently
In hw2, add a comment on one of the classes and rename the other, as shown in Figure 7.
Figure 7. hw2 after "co-worker's" changes
In hw3, rename the same class as you did in hw2, and then change the background color of the other class (the one with the added comment in hw2.). Figure 8 illustrates these changes.
Figure 8. hw3 after your changes
As mentioned previously, you'll simulate the case where you change the ancestor directly without saving a copy by comparing hw2 (representing your co-worker's changes) and hw3 (representing your own changes). The compare editor shows the following deltas, as seen in Figure 9.
Figure 9. The compare editor displays your changes
Here are a few things that you should know about this compare editor:
The left contributor is your co-worker's version, and the right contributor is your version. Remember that the comparison is always performed left minus right, which means that the deltas treat the right contributor (your version) as the base (or ancestor) model.
Note: The actual order of display in the navigator view does not consistently determine which model becomes left and which becomes right in the compare editor. It could have come up with hw2 on the right. The order actually depends on the order of the file names in the selection provided to compare support by the navigator from which the compare session was launched. If the files do not come up in your preferred order, you might try renaming one of them to change their appearance order, or changing the sort order on the navigator (this is possible in the model explorer.) You might also try running the comparison from the Eclipse resource navigator view instead of the model explorer.
- The header for the right contributor appears dimmed, which
indicates that it is unavailable. There is also no blue border
around the right contributor (as there is around the left
contributor), which also indicates that the pane is unavailable.
You would expect the right contributor pane to be, in fact,
available, since there is a delta highlighted in the structural
difference viewer. Clicking the first delta makes the right pane
available again, as shown in Figure 10:
Figure 10. After clicking on the first delta
- A merged result pane has appeared beside the structural differences viewer. This version of the model starts out as a copy of the base or ancestor model, which is always in the right contributor in a two-way merge session. In this case the base version is your version (hw3). The merged model changes in real time as you accept or reject changes made by your co-worker.
Accepting and rejecting changes
Each change in a two-way merge session must be examined very carefully before accepting or rejecting it. If the other person changed the element, then accepting the change will take the other person's new value. But if the delta exists because you changed the value and the other person did not, then accepting the change will actually revert the value back to the ancestor value.
This is the key flaw with two-way merging. When comparing contributors without the base model, it is impossible to tell which contributor actually made a change to the value. In order to understand the difference in context, it is necessary to open the ancestor model (if it is available) and look at the original value. This is much more cumbersome than three-way merging, as we'll see later.
The icons on each delta in the structural differences viewer are undecorated when the merge starts, as shown in Figure 11.
Figure 11. Delta icons
This simply means that they are considered unresolved -- neither accept nor rejected at this time. When you accept one (by right-clicking the delta and clicking Accept on the context menu), the icon changes to the accepted state and the merged model is updated. Figures 12 through 14 show this flow for the first delta.
Figure 12. Accept command
The accept command marks the delta with a small green check box, indicating that it is resolved as accepted.
Figure 13. After the accept command
The merged model has also been updated with the value from the left contributor.
Figure 14. Merged result after the accept command
Shortcuts for accepting multiple differences
From here, you could accept each individual change, which would be tedious were there dozens of differences, much less hundreds. IRSA provides a couple of useful short hands to save you this trouble. If you are confident in the changes, you can use the Accept All Differences from Left button, as shown in Figure 15.
Figure 15. Accept all differences from left button
Alternatively, you can Accept all the differences in individual difference groups, as shown in Figure 16.
Figure 16. Accept all differences in a difference group
The end result of both of these shortcuts is that all of the differences from your co-worker are accepted, as shown in the structural difference decorations seen in Figure 17.
Figure 17. Differences marked as accepted
Losing changes in a two-way merge
Now you need to consider whether the result is what you actually meant to happen? The two kinds of changes you need to be careful with are:
- Conflicting changes, which are not flagged but which you should try to look for as you explore the deltas.
- Changes that are made only in our base contributor. These are flagged as deltas, but they revert to the ancestor value if accepted. In other words, you will lose your changes if those deltas remain accepted.
You dealt with the only conflict previously. But there is a change in your contributor that does not have an equivalent in the other contributor: the background color change for class1. By accepting that change, you actually lose your change in favor of the original value from your co-worker's version of the model. This happens because your contributor is used as the base. Thus, all change differences are relative to your value as the from value. Your coworker's value is the to value in this case.
This is easier to see when the change is displayed in the diagram view mode (see Figures 18 and 19), since color values are otherwise displayed cryptically as numbers representing a combination of the red, green, and blue values.
Figure 18. Left contributor retains ancestor value
Figure 19. Merged result currently has ancestor value
To fix this, we have to reject the delta on the background color, as shown in Figure 20.
Figure 20. Reject command on background color delta
The result is that this delta is decorated with a small blue unchecked box (Figure 21) -- indicating resolution by rejection -- and the merged model has your value for the background color of class1 (Figure 22).
Figure 21. Rejected delta
Figure 22. Rejected color change leaves your value in place
Saving the merged result
We have successfully retained all of the changes from both contributors. The merged model is now complete. The next step is to save it. Because each of your models is writable, you have three choices. There are three buttons in the top right-hand corner of the merged model pane that allow you to save over the left or right contributors, or to save a copy of the current model to a separate target file. This is illustrated in Figure 23.
Figure 23. Save as Left Contributor, Save as Right Contributor, and Save a Copy buttons
You can save intermediate copies of the merged model as often as you want without damaging the contributors themselves. Remember that you can always use Replace With Local History to restore the model if you make a mistake and save over the wrong contributor.
The following represents the Save a Copy work flow. After you click the far right-hand button, this dialog appears. In Figure 24, you've drilled down to the workspace project directory and entered a name for the file ? hw1_merged.
Figure 24. Save a copy dialog
After clicking save and refreshing the Eclipse workspace (can't forget to do that) your workspace contains the fourth file, as shown in Figure 25.
Figure 25. Merged model in the workspace
Next, this article will discuss the same models in a three-way merge session. You saved the original hw1 version of the model to serve as the common ancestor of your two changed models. Now, by selecting all three, you can use the Compare With Each Other command, which will result in the window shown in Figure 26.
Figure 26. Three-way compare session
Following are some notable additions in the three-way merge compare editor (as opposed to the two-way merge compare editor):
- A Conflict tab in the structural differences viewer. A three-way merge compares contributors separately against the ancestor version and then compares the two delta sets to find conflicts -- changes that cannot be accepted together. The only conflict that we created was the rename of Class2 in both contributors.
- Two Differences tabs in the structural differences viewer. It is possible to explore all model differences independently on the left and right sides of the merge session.
- A split ancestor pane (between the two contributors). Each of the contributors has a slaved ancestor pane so that its deltas can be properly highlighted. The reason for the existence of the split pane is that conflicts can affect different ancestor elements, or require different default view modes. An example of a situation where both reasons exist is the renaming of a diagram (which affects the diagram element and requires a property viewer) and the deletion of the diagram's parent package (which affects the package element and requires a tree viewer). This cannot be rendered correctly with a single ancestor pane.
When resolving a conflict, you can choose the left, the right, or the original value. Figure 27 shows you choosing the left value.
Figure 27. Conflict resolution choices
Once you do this (Figure 28), the conflict node is marked as resolved (a green checked box), the left (top) delta is marked as accepted (also a green checked box), and the right (bottom) delta is marked as rejected (a blue box with an "X"). The change is rendered in the merged model pane as well.
Figure 28. Resolved to the left contributor
Note that there are other ways of obtaining the same result. For instance, the deltas shown in the conflicts pane can be accepted and rejected individually. They can also be accepted or rejected in the contributor windows themselves. Furthermore, the deltas are state aware, meaning that only valid commands are available to you. Finally, their effect cascades to all related deltas. For example, with the left conflicting delta accepted already, the only available command in the left contributor itself is the reject command, as shown in Figure 29:
Figure 29. Reject command in the left contributor
Left and right differences panes
Moving along, you can now examine the Left Differences pane, detailed in Figure 30.
Figure 30. Left differences
Note that the conflicting name change is shown here as accepted, and there is an alternate view of the conflicting change in the other contributor, which is shown as rejected. You would normally leave the conflict collapsed in a differences view.
The differences associated with the diagram have been grouped here, and you can accept them all because there are no conflicts (you would see expansion plus signs if there were.) After accepting the diagram differences, move on to the Right Differences pane detailed in Figure 31.
Figure 31. Right differences
You made only one change on the diagram, and it does not conflict with any other change (again, no expansion marker for a conflict) so simply accept it. The final result of the merged diagram is shown in Figure 32.
Figure 32. Final merged result
This is exactly where you ended up in the two-way merge scenario. But here all you had to do was accept all the differences from each side (pretty much without thinking), and choose which side you wanted to accept on the conflicts pane, and you were done. You'll save another copy of the merged result under a similar name.
When dismissing the compare session, you find out that the session is still considered dirty (unlike the two-way merge scenario, which acted more like a compare session.) You are offered the choice to save (Figure 33):
Figure 33. Save offered when dirty merge session is dismissed
Clicking Yes launches a second dialog, as shown in Figure 34.
Figure 34. Choose where to save when dirty merge session is dismissed
The left and right contributors are both writable, so you are offered the choice of save targets. Since you have already saved a copy of the merged result, you decide to cancel the save operation here, which dismisses the merge session completely. The merge session would have continued had you cancelled at the save choice stage instead of the target choice stage. After refreshing your workspace, you'll see your new model (as illustrated in Figure 35).
Figure 35. Workspace contains both merged models
Two-way merging of changed models requires that you perform some mental gymnastics to figure out where the conflicts are, and to avoid losing your own changes (caused when a change exists only on the base side). Although two-way merging is very common with text, it does not scale well with structured data.
On the other hand, three-way merging clearly denotes every change, and attributes it accurately to the left or right contributors. All conflicts are also clearly indicated. The merge is straight-forward, and you need not worry about losing any changes once the conflicts have been resolved. Three-way merging is the preferred merge mode for parallel development of models.
One last thing: let's compare the two merge results to see if these two different techniques produced exactly the same final model. Figure 36 displays the conclusion.
Figure 36. Result of comparing the two merge result models with each other
Future articles will explore advanced merge topics such as merging multi-part models, composite groups and atomicity, in depth diagram merging, merging with ClearCase and CVS, and so on.
- Participate in the discussion forum.
- Part 1 in this series, Comparing models with local history (developerWorks, July 2005).
- Part 3 in this series, A deeper understanding of model merging (developerWorks, July 2005).
- Part 4 in this series, Parallel model development with CVS (developerWorks, August 2005).
- Part 5 in this series, Model management with IBM Rational ClearCase and IBM Rational Software Architect Version 7 and later (developerWorks, July 2007).
- Part 6 in this series, Parallel model development with custom profiles (developerWorks, August 2005).
- Part 7 in this series, Ad-hoc modeling – Fusing two models with diagrams (developerWorks, March 2007).
- The article Introducing IBM Rational Software Architect: Improved usability makes software development easier (developerWorks, February 2005) is a basic introduction to the Rational Software Architect product.
- Get the evaluation version of Rational Software Architect from the Trials and betas page
- For technical resources about Rational's products, visit the developerWorks Rational content area . You'll find technical documentation, how-to articles, education, downloads, product information, and more. For specific information about Rational Software Architect, visit the RSA technical resources page.
- For details and more information about the Eclipse 3.0 platform, visit the Eclipse home page.
- Ask questions about Rational Software Architect in the Rational Software Architect, Software Modeler, Application Developer and Web Developer forum.