July 8, 2014

Merge/Integrate (Part 1) - What Happens Under the Covers

Traceability

This is the first in a series of blog posts looking at what happens when you merge or integrate changes between branches (or streams) in Perforce. The goal of this series is to help you understand Perforce’s merge capabilities better. Most of the time it “just works” and does the right thing, so people can go a long time without worrying about the gory details. However a better understanding of the details can help you gain further benefits and support more complex merge requirements quickly and easily.

This article builds on some of the basics described in the Knowledge Base article, Determining Revisions to Integrate. In summary, if you ask Perforce to merge or integrate one branch (the source) to another (the target):

  • It pairs up all corresponding source and target files in the two branches, and then for each pair of files:
    • It considers all source revisions as potential candidates for integration
    • It removes any source revisions that have already been integrated
    • Any revisions left over are candidates for integrating and can be resolved (merged)

This ignores complications such as adds, deletes, renames, etc., which we will cover in later articles.

To illustrate this point, let’s consider the file cat.txt which has been edited several times on the MAIN branch and then a couple of times on (my personal) ROBERT branch.

In this augmented screenshot from P4V’s Revision Graph, you can see that //depot/MAIN/cat.txt#3 (where #3 means revision 3) has the same contents as //depot/ROBERT/cat.txt#1, which then has been further modified a couple of times.

Revisions vs. file contents

There is a conceptual difference between a revision and the contents of the file at that revision, although they are related. So what is in revision //depot/ROBERT/cat.txt#3 shown above?

In that revision, the line “B” was changed to “B1”. If we open the file in an editor we will see that the file contents include “A1”, but that line was actually modified in the previous revision (2).

So, a revision can be defined as a set of modifications (deltas) to the previous revision (it can be quite educational to review the contents of the RCS files on the server which is how Perforce stores text files normally–this makes it really clear how the deltas for each revision are stored). The content of the file at a particular revision is the sum of all the deltas (revisions) from when the file was added to the repository until that revision.

Merge/integrate by revision rather than just contents

Under the covers Perforce first looks at revisions that need integrating, and only secondly at the contents of the files that are being merged. This is an important distinction to understand.

Remember that when deciding what to merge/integrate, Perforce ignores all revisions that have been previously merged/integrated—unless the user has used the force option which should be a very rare occurence.

The revisions to be merged/integrated

The following screenshots show P4V’s Merge/Integrate dialog and the results of the Preview button.

The revisions to be integrated from the source (ROBERT) to the target (MAIN) are revisions 2 and 3. Revision 1 was just a copy of the original revision and therefore is not a candidate to be integrated.

I can automatically resolve changes and submit. To understand what’s going on, let’s look at these steps in a bit more detail.

What safe automatic merge does

If I click the Merge button, then right click on the pending changelist and select Resolve… I get the following dialog (note this is effectively a two-tab view controlled by the radio buttons at the top of the form).

In the screenshot to the left, choosing Auto resolve and the Safe automatic resolve option, ("p4 resolve -as" on the command line) will work for this scenario, because there have only been changes in the source.

In the screenshot to the right, if you Accept Source ("p4 resolve -at" on the command line), it copies the source file to the target.

You can resolve the file using either of these two options.

If you are interested in the command line options, then “p4 help resolve” will be useful, or the section in the Command Reference Guide.

The history after the merge/integrate

To review, the Integrations tab in Revision Graph below shows that source revisions 2 and 3 were integrated as part of a single changelist to create target revision 4. The contents of revision 4 are hopefully what you expected–the source file has been copied to the target. In Revision Graph you can also drag and drop one revision onto another to perform a diff.

When automatic merge is required

Let’s consider a slightly more complex merge scenario below.

Revision 3 on ROBERT has been merged/integrated to revision 5 on MAIN, and revision 4 on MAIN was an edit that modified line D1.

To resolve, a merge is required (not just Accept Source or Safe automatic resolve) because both the source and target have been modified. In this case, Automatic resolve or Accept Merged (“p4 resolve –am” on the command line) gives the correct result.

Clean merges don’t need to be merged/integrated the other way

Below, I have performed a slightly different scenario, and merged revision 4 on MAIN down to revision 4 on ROBERT.

Having done this, if I attempt to integrate revision 5 on MAIN down to ROBERT, P4V will tell me that there is nothing to do. Since revision 5 was a clean merge it doesn’t need to be propagated in the other direction.

Summary

So for now I’ve laid out the basics for understanding merge/integrate. Future articles in this series will look at more complex scenarios such as:

  • When and why you should ignore a merge
  • When and why to overwrite the target
  • Merge with edit—sometimes called a “dirty merge”
  • Selective integrations or “cherry picking”
  • What happens when you back out a change which contains integration records and the problems this can create

COMING SOON: Merge/Integrate (Part Deux) - Resolving and Cherry Picking