Background

Merging is not yet part of the Vesta core tools. However, there is a prototype merge script that has been in development for a while and is actively used by a variety of people. This page gives some advice on how best to plan your work around merging and how to avoid potential problems.

In order to understand this page, you should already know the basics of Vesta and the repository tools. If you don't know:

Then you should probably back up and start with LearningVesta, or at least make sure you understand the diagrams on the man pages for vcreate, vbranch, vcheckout, vadvance, and vcheckin.

For even more information on merging in Vesta, you may also want to look at MergingFuture.

For ideas about ways to use branching and merging that are independent of the version control system, you might find Streamed Lines to be useful.

Merging Advice

This section lists some guidelines which can help you avoid trouble. They're not hard and fast rules, by they are useful rules of thumb.

Resolve Conflicts Right Away

When you perform a merge operation, the merge tool may report conflicts. These are cases where it felt it could not determine the right choice without human intervention. Whenever a merge operation results in conflicts, you should resolve them right away. You should always resolve conflicts before you:

Many merge tools (and certainly the vmerge script) handle conflicts in text files by placing conflict markers around sections of the files. Conflict markers usually look like this:

<<<<<<<
changes
made
on
one
side
=======
mofidications
performed
in
another
branch
>>>>>>>

This allows you to use you favorite text editor to examine the conflicts and figure out how choose between, combine, or otherwise reconcile them.

The main reason to resolve conflicts right away is to avoid confusion for humans.

Merge With Checked-In Versions

When choosing the version to merge into your working directory, you should use a checked in version if at all possible rather than a snapshot in a session directory. Merging with checked in versions will help avoid conflicts.

Snapshots in session directories are not part of the normal progression of version history. To a merge tool, they appear to be separate changes off to the side. Version N of a package is based on version N-1 of the package. A snapshot in a session directory is based on a version chosen at checkout time, but usually nothing is based on such snapshots.

The following diagram illustrates what the version history looks like to a merge tool. Main-line versions (which are good to merge with) are shown in blue, and snapshots in session directories (which you should avoid merging with) are shown in red.

The important thing to remember about this difference is that merging with snapshots in session directories makes conflicts on future merges more likely. See SessionHistoryMentalModel for more about this.

The obvious exception to this is if you are merging in changes made in a non-exclusive checkout (aka scribble). This is fine as long as you only merge from a single snapshot in the session. Normally, you would merge the last snapshot in the session and you would delete the working directory after performing the merge operation.

Either Merge or Edit During Each Checkout, but not Both

It's easier for everyone to understand the version history if each checkin contains either a new change made by the user or a merge operation. When you mix the two, it can be difficult to make sense of what happened.

If you have an active checkout with edits you've been making and you want to perform a merge, check in your changes first and then check out again before merging.

If you've just done a merge but you're not 100% satisfied with the merged version (maybe you spotted a typo or a logical/semantic error), check in before making further edits. Of course if the merge produced any conflicts you should resolve those first before checking in. Also, if the merged version fails to compile or pass tests, you should probably make edits to resolve those problems before checking in. (In some cases it may be a bit of a judgment call whether an edit is resolving a conflict or other post-merge problem or making a new edit.)

Limit to One Merge per Checkout

It's easier to understand the version history if you perform and most one merge in each checkout operation. It is possible to merge multiple merges between checking out and checking in, but it's best to avoid doing so.

Suppose you have two separate changes in two separate branches and you want to merge both of them into the main-line of your package. This is what you should do:

  1. Check out the package main line
  2. Merge in the changes from first branch
  3. Resolve any merge conflicts
  4. Check in the merged version (creating a new version on the main line)
  5. Check out the package main line again
  6. Merge in the changes from second branch
  7. Resolve any merge conflicts
  8. Check in the merged version (creating a new version on the main line)

Another reasonable approach would be:

  1. Check out the first branch
  2. Merge in the changes from second branch
  3. Resolve any merge conflicts
  4. Check in the merged version (creating a new version on the first branch)
  5. Check out the package main line
  6. Merge in the changes from first branch (which now includes the changes from the second branch)
  7. Resolve any merge conflicts
  8. Check in the merged version (creating a new version on the main line)

Never Merge From Multiple Sanpshots in a Single Checkout Session

If you must merge a snapshot from a checkout session into your working copy, never merge with any other snapshot from that session directory. Merging with multiple snapshots from the same session directory will make conflicts very likely.

This is why we recommend that if you are merging in a change from a non-exclusive checkout (sometimes called a "scribble"), that you only merge in the last snapshot in the session. It might even be a good idea to remove the working directory before you merge.

It's tempting to think of a non-exclusive checkout as a micro-branch, but there are important differences between branches and non-exclusive checkouts. If your change will go take some time and go through multiple revisions, you may want to use an actual branch (created with vbranch). Again, see SessionHistoryMentalModel for more about this.

Use Throw-away Merges When Violating These Guidelines

There may be times when you have a legitimate need to violate these guidelines. Perhaps you want to try combining several changes that are still works in progress to see how many conflicts they will cause or even to try compiling and testing a preliminary combination. If you want to do that, do it in a non-exclusive checkout that you use temporarily and then discard.

As an example, suppose we have several users working on different changes:

Another user, Dave, is going to be responsible for integrating these changes when the three users finish with their work. He wants to find out how much trouble he's going to have by merging the current state of these three changes. He performs a non-exclusive checkout:

% vchekcout -N /vesta/example.com/foo/pkg
Creating session /vesta/example.com/foo/pkg/checkout/14.djones_example.com.1
Making working directory /vesta-work/djones/pkg

He then merges in each of the three versions:

After these merges Dave builds and tests the changes, possibly going through more edits. He notes his final snapshot (pkg/checkout/14.djones_example.com.1/6) which may help remind him later how he dealt with certain differences which may come up when he does the real merges. Then he deletes /vesta-work/djones/pkg.

Specific Usage Plans

This section suggests a couple ways to use merging that help you follow the above guidelines and keep out of trouble.

Work in Branch, Then Merge Up

When you start working on a change, create a branch. Check it out, make changes, and check it in. Build and test as appropriate. Repeat until you (and anyone else involved) are satisfied with the change.

When you're satisfied with your branch, check out the main-line of your package, merge in the latest version from your branch, resolve any conflicts, and check in a new main-line version.

In the following illustration of this method, the branch is shown in turquoise, and the merge operation is shown as a dashed red arrow.

This is the pattern we follow for development of Vesta itself.

Merge Forward to New Branch

If the main-line gets significantly ahead of the point where your branch started, you can merge newer main-line versions down into your branch.

However you might find that it's easier to understand the version history if you create a new branch and merge the changes from your older branch forward.

A Note About Sub-Branches

Since you can create branches inside branches, you could use this to further sub-divide really complex changes and merge them up just one level (from a sub-branch into a branch).

Work in Non-Exclusive Checkout, Then Merge Up

When you start working on a change, do it in a new non-exclusive checkout (aka scribble). When you're satisfied with your changes, take a final snapshot of your working directory and remove it. Then exclusively check out the main-line of your package, merge in the latest snapshot from your non-exclusive checkout, resolve any conflicts, and check in the new main-line version.

This model is essentially the way CVS works.

Merge Forward to New Non-Exclusive Checkout

If the main-line gets significantly ahead of the point where your non-exclusive checkout started, you may want to create a new non-exclusive checkout and merge your changes forward into it.

(Note that in the above diagram every snapshot in the session directory of the second non-exclusive checkout is shown as being merged with the last snapshot in the first. That's how the merges would be recorded, and that's how the merge algorithm would perceive the history. Again, see SessionHistoryMentalModel for more about this.)

You can also merge newer main-line versions into your non-exclusive checkout, but you will probably find it easier to understand the version history if you merge your changes forwared into a new non-exclusive checkout.

A Small Cautionary Note

Automatic merging is an attempt to implement a "do what I mean" algorithm. We endeavor to make such tools involve the user with merge conflicts when appropriate. However, there's an inherent tension between the desire to automatically handle as much as possible without involving the user and the desire to avoid mistakes by asking the user to resolve conflicts.

While the results of a conflict-free merge are often considered correct by users, you probably shouldn't trust them implicitly. You should use at least some method for testing their correctness such as:

Of course, it never hurts to read the diff of the changes made by a merge before checking in.