How does Monticello merge?

There is a repeated confusion on how merging in Monticello works. This post tries to clear up the situation. In the following examples we always start from the same situation displayed below. P is the name of the package we are working with and the number behind P.1 signifies a specific version of that package. The Working Copy is the code we currently have in our Smalltalk image.

 P.0 --- P.1 --- P.2 --- P.3 --- Working Copy
              \- P.6 --- P.7

This shows us that we currently have all the changes from P.0, P.1, P.2 and P.3 in our image. P.6 and P.7 is a separate branch that we do not have in our image.

Load

What happens if we load P.7? If there are any changes in our Working Copy we lose those changes after a warning. Afterwards P.7 is loaded and a new Working Copy is ready to be changed. After this load operation we end up with the following situation:

 P.0 --- P.1 --- P.2 --- P.3 
              \- P.6 --- P.7 --- Working Copy

Merge

What happens if we merge P.7? First of all Monticello tries to figure out the closest common ancestor of the Working Copy and P.7. In our examples this is obviously P.1.

Before performing the actual merge Monticello needs to load the code in P.1 into memory. This can cause an error if P.1 has been moved or deleted from its original repository. If you run into troubles, you need to make sure that P.1 is in a repository known to Monticello, otherwise an automatic merge cannot be performed.

To perform the actual merge Monticello calculates the delta between the common ancestor and the two versions to be merged:

  • D.1 is the delta from P.1 to Working Copy. D.1 is also called the local change, because it is the delta from the common ancestor to the working copy.
  • D.2 is the delta from P.1 to P.7. D.2 is also called the remote change, because it is the delta from the common ancestor to the version you merge.

Monticello then inspects the two deltas D.1 and D.2. Source elements (class definitions, method definitions, variable definitions, etc.) that are added, removed or changed in both deltas are a conflict. In the merge browser the user needs to resolve these conflicts before proceeding:

  • The Keep button chooses the remote change from D.2 and ignores the change in D.1.
  • The Reject button chooses the local change from D.1 and ignores the change in D.2.

Next Monticello creates a patch-set of D.2 with the conflicting elements resolved as specified by the user. It then applies this patch-set onto the working copy and adopts the ancestry as follows:

 P.0 --- P.1 --- P.2 --- P.3 --- Working Copy
              \- P.6 --- P.7 -/

The Working Copy has now two ancestors P.3 and P.7. In most cases the user will then commit the merged version to the repository. Afterwards the ancestry looks like this:

 P.0 --- P.1 --- P.2 --- P.3 --- P.8 --- Working Copy
              \- P.6 --- P.7 -/

The merge operation performed by Monticello is called a three-way-merge, because it takes three versions into account: the working copy, the version to merge, and the common ancestor of the two versions.

Manual Merge

What happens if we start from the same situation, but the version of the closest common ancestor P.1 cannot be found. Being able to load P.0 doesn’t help here, because that would cause all the changes from P.0 to P.1 to conflict. Furthermore, if any of the changes between P.0 to P.1 were undone in either of the branches these changes would be lost.

What can we do if the common ancestor is missing? The simples thing is to do a manual merge. This means we calculate the changes from the Working Copy to P.7. This gives us a combined delta D.3 that undoes the changes from P.1 to Working Copy and that adds the changes from P.1 to P.7. Unfortunately Monticello cannot tell us from which branch these changes are coming from, so we have to go through D.3 one-by-one and apply the changes that we think belong to the delta of P.1 to P.7. At the end of the manual merge we can tell Monticello to adopt the version P.7, so that the ancestry looks again like this:

 P.0 --- P.1 --- P.2 --- P.3 --- Working Copy
              \- P.6 --- P.7 -/
Posted by Lukas Renggli at 24 March 2010, 9:16 pm with tags monticello, pharo, smalltalk link