Merging Changes Between Unrelated Codelines
How do you merge changes between codelines that aren't branched from each other?
PROBLEM
How do you merge changes between codelines that aren't branched from each other?
SOLUTION
Consider the following situation. You have two codeline paths, "B" and "C", each of which was originally branched from the same path, "A". The files in paths B and C are therefore not directly related to each other by branching, although they do share a common ancestor:
B +---------------------------
/
A ---+-----+-----------------------
\
C +---------------------
How do you integrate (merge) changes between files in these sibling paths? The simplest answer is that you run the p4 integrate command. For example:
p4 integ B/... C/...
However, the first time you do this you may not get the desired result. Perforce uses integration history created by previous integration commands to know which file revisions to integrate. Since C was not branched from B, there is no integration history between these two paths. So what happens when you try to integrate between them? The answer depends on whether you are using Release 2004.2 (or later), Release 2002.2 to 2003.2, Releases 99.2 through 2002.1, or a pre-99.2 release.
Release 2004.2 (or later)
Nothing extra need be done as 'p4 integrate' now always considers indirect integrations through intermediate branches when determining that files are related and what changes need to be integrated. The direct/indirect option in branch specifications has been removed as all integrations will be considered indirect. Also, 'p4 integrate' may select a base for merge resolution from a common ancestor which is neither the source nor the target file.
Release 2002.2 to 2003.2
When you attempt to integrate between source and target paths, no files will be opened for integrate unless previous source-to-target history exists. By default, Perforce will not open a file for integrate unless it can find a base revision to use for a 3-way merge. Base revisions are chosen according to integration history, so when there's no integration history Perforce detects a "baseless" merge. As of Release 99.2, baseless merges are not permitted. To override this default, use the -i flag, for example:
p4 integ -i B/... C/...
The -i flag "enables indirect integration" -- it causes Perforce to search indirect integration history, attempting to find a suitable common ancestor in the source codeline. If it fails to find a suitable common ancestor, it falls back on the behavior of releases 99.2 through 2002.1.
In P4Win 2002.2 (or later), use the "Enable indirect merges" option of the Integrate dialog.
p4 integ -i and Releases 99.2 through 2002.1
In releases 99.2 through 2002.1, the -i flag "enables baseless merges" -- it makes Perforce open the target file for integrate, if it exists, and if no integration history exists between the source and the target, the starting integration revision of the source file will be used as the base revision for a 3-way merge.
In our example, when you use -i, the C files will be opened for integrate and, for each B-C file pair, B#1 will be used as the base revision in a 3-way merge. After you resolve and submit, integration history will show that revision B#1 is already integrated into C -- that's all Perforce needs in selecting a base revision for future B-to-C integrations. (Actually, it's a simplification to say that B#1 is the key factor -- see Determining Revisions to Integrate for more information.)
In P4Win 99.2 through 2002.1, use the "Enable baseless merges" option of the Integrate dialog.
Pre-99.2 releases
When you integrate between source and target paths in pre-99.2 releases, the target file -- if it exists -- is opened for integrate regardless of previous source-to-target integration history. However, unless history shows that revision #1 of the source file was already integrated, the scheduled resolve will do a 2-way merge, not a 3-way merge. In a 2-way merge there is no base, and although you can diff the two files ("theirs" and "yours") you can't tell which changes were made by whom.
So, in the B-to-C example, the C files will be opened for integrate, and a resolve will be scheduled for each B-C file pair. When you resolve, you'll have to choose to keep either B#head or C#have. After you submit, integration history will show that B#head was integrated into C. But there is still no integration record for B#1 into C, so the next time you integrate, you'll be faced with the same problem.
There are ways to:
- Make integrate do a 3-way merge even when revision #1 of the source has not been previously integrated, and
- Set the base revision permanently so that integration history shows #1 was integrated, and subsequent integrations behave normally.
The remainder of this note explains how to perform the above tasks. Please refer to Determining Revisions to Integrate for background information about how Perforce determines which revisions need integrating.
Making "integrate" do a 3-way merge
In Release 99.2 and later you can simply use integrate -i to coerce a 3-way merge. In earlier releases, the only way to coerce a 3-way merge is to supply a revision range to the integrate command. Perforce uses the revision range to compute the starting and ending source revisions to integrate. Once it knows the starting revision, it can determine which source revision to use as a base for a 3-way merge.
Going back to the example above, say two changelists, 555 and 556, have been submitted into the B codeline path since it was branched from A. To integrate those changes directly into the C path, you can use the syntax:
p4 integrate B/...@555,@556 C/...
p4 resolve
p4 submit
Perforce identifies all the B files affected by changelists 555 and 556, and opens the corresponding C files for integrate. When you do the resolve, Perforce will do a 3-way merge. For each B file merged into a corresponding C file, the base used for the 3-way merge will be revision @554 -- that is, the predecessor to the starting revision being integrated is used as the merge base.
Alternatively, if you want to integrate all changes from B into C and you know the first changelist submitted into B was 555, you can use:
p4 integrate B/...@555, C/...
p4 resolve
p4 submit
Note the trailing comma in the revisions spec -- this syntax is short for:
p4 integrate B/...@555,#head C/...
Setting the base revision permanently
Unless integration history shows that the #1 revisions of the B files have already been integrated into C, you'll always have to use revision ranges every time you integrate from B to C. In pre-99.2 releases, you have to first integrate just the #1 revisions, and submit those, to permanently set the base revisions to use for subsequent integrations.
Here's one way to accomplish this task. Say, for example, the files in the A path were branched into B in changelist 500. In other words, the B/...@500 files are all at their #1 revisions. To set the starting revision to use for future integrations from B to C, you can do an "ignore integrate" of B/...@500 into C:
p4 integrate B/...@500 C/...
p4 resolve -ay
p4 submit
The above integrate command restricts the ending revision of each source file to @500. Using resolve -ay ("accept yours") satisfies the resolve by ignoring any diffs; the contents of the target file are unchanged. Neverthess, for each C file submitted, Perforce records the fact that its corresponding B#1 file has been integrated. The next time you integrate, the B#2 file will be used as the starting revision, and the B#1 file will be used as the base in a 3-way merge.
If you also plan to integrate changes from C back into B, you can set permanent base revisions to use for future integrations in that direction as well. For example, if C were branched from A in changelist 600, you'd use:
p4 integrate C/...@600 B/...
p4 resolve -ay
p4 submit
"#1" vs. changelist number as starting revision
You might be asking yourself why you can't set a permanent base revision using "#1" instead of a changelist number in the integrate command. In other words, why not use:
p4 integrate C/...#1 B/...
p4 resolve -ay
p4 submit
The above might work just as well for you, depending on how your codelines evolved, and what you are trying to accomplish. The difference between the two revision specification syntaxes is that C/...@600 includes only the files that were originally branched from A into C in changelist 600, whereas C/...#1 includes all the files that were ever submitted into the C path, including those added directly, and those branched from other codelines.
