Perforce's Inter-File Branching mechanism allows any set of files to be copied within the depot. By default, the new file set (or codeline) evolves separately from the original files, but changes in either codeline can be propagated to the other with the
p4 integrate
command. When to Create a Branch
Create a branch whenever two sets of code have different rules governing when code should be submitted, or whenever a set of files needs to evolve along different paths. For example:
integrate
command.
p4 branch
branchname. Use the view in the resulting form to indicate which files are to be included in the branch, and where the branched codeline will be stored within the depot's file tree.
p4 client
view of the client workspace that will hold the new files.
p4 integrate
to open the new files for branching. The new files are listed in a changelist; the associated operation is branch
.
p4 submit
to submit the changelist to the perforce server. This creates the new files in the depot.
p4 get.
The original code is stored in the depot under its
elm_project
subtree; Kurt decides to call the branch elm_r1
, and will store the branched codeline in the depot under an elm_release1
subdirectory. He types
p4 branch elm_r1
and sees the following:
Branch: elm_r1 Date: 05/25/1997 17:43:28 Owner: kurtv Description: Created by kurtv. View: //depot/... //depot/... |
The default
View
above would map the entire depot to itself in a branch, which is useless. The View
needs to map the original codeline's files on the left to branch files on the right; Kurt changes the View
field as follows:
Branch: elm_r1 Date: 05/25/1997 17:43:28 Owner: kurtv Description: Created by kurtv. View: //depot/elm_proj/... //depot/elm_release1/... |
This maps all the files in the depot's
elm_proj
file tree to a new depot file tree called elm_release1
. All files from the source subtree will eventually be copied to the branch subtree; these files will be the contents of the branch.Kurt quits the editor; the branch is created.
The
p4 branch
command does not copy files into the branch; it simply specifies which original file will correspond to which branched file.Exclusionary mappings may be used within a branch view.
Kurt will be working with the branched files. His client is
kurtv_cli
; he types p4 client
, and adds a line to his client view:
Client: kurtv_cli Date: 05/25/1997 18:34:58 Owner: kurtv Description: Created by kurtv. Root: /usr/kurtv View: //depot/elm_release1/... //kurtv_cli/elm.r1/... |
There might be other mappings within the client view; the only crucial factor is that the files in the depot's elm branch directory be mapped to some location in Kurt's client workspace. The mapping shown here accomplishes this.
p4 integrate
followed by p4 submit
. When the branch files don't yet exist in the depot, integrate
simply tells the server that the branch files are to be copied from the original files described in the branch mapping. The integrate
command, like add
, edit
, and delete
, does not actually do the operation it describes; instead, it adds the affected files to a changelist, which must be submitted with p4 submit
. This keeps the integrate
operation atomic: either all the named files are affected at once, or none of them are.The basic syntax of the
integrate
command is
p4 integrate -b branchname [filepatterns]If the filepatterns are left off, all the files in the branch are affected. When included, the filepatterns must describe branch files, and these files must be visible through the client view.
Kurt has created the branch
elm_r1
as above, and he's ready to create the branched copies in the depot. He types p4 integrate -b elm_r1
, and sees
//depot/elm_release1/Changes#1 - branch from //depot/elm_proj/Changes#6 //depot/elm_release1/NOTICE#1 - branch from //depot/elm_proj/NOTICE#23 <etc.> |
The instructions to branch these files have been added to his default changelist. He types
p4 submit
, and sees
Change: new Client: kurtv_elm User: kurtv Status: new Description: <enter description here> Files: //depot/elm_release1/Changes # branch //depot/elm_release1/Configure # branch <etc.> |
He changes the description and quits the editor; the branched files are created within the depot.
p4 get
.Kurt wants to retrieve the branched copies of the Elm source into his workspace so he can work with them. He types
p4 get //depot/elm_release1/...and sees
//depot/elm_release1/Changes#1 - added as /usr/kurtv/elm.r1/Changes //depot/elm_release1/Configure#1 - added as /usr/kurtv/elm.r1/Configure <etc.> |
All the branched files are copied into his workspace, he can proceed to work with them as he normally would.
p4 integrate
, the branched files are treated exactly like non-branched files, with the normal use of get
, edit
, delete
, submit
, etc. Evolution of both codelines proceeds separately; new commands come into play only when changes to one codeline needs to be propagated to the other.
resolve
command. Only one additional step needs to be performed: before resolving, the integrate
command is used to schedule the merge between the original files and the branched files.A bug has been fixed in the original codeline's
src/elm.c
file. Kurt wants to propagate the same bug fix to the branched codeline he's been working on. He types
p4 integrate -b elm_r1 ~kurtv/elm.r1/src/elm.cand sees
//depot/elm_release1/src/elm.c#1 - |
The file has been scheduled for resolve. He types
p4 resolve
, and the standard merge dialog appears on his screen.
/usr/kurtv/elm.r1/src/elm.c - merging //depot/elm_proj/src/elm.c#2 Diff chunks: 0 yours + 1 theirs + 0 both + 0 conflicting Accept(a) Edit(e) Diff(d) Merge (m) Skip(s) Help(?) [at]: |
He resolves the conflict with the standard use of
p4 resolve
. When he's done, the result file overwrites the file in his branched client, and it still must be submitted to the depot.In Perforce terminology, changes are always propagated from donor files to target files. In the above example, the original codeline provided the donor files and the target files were located in the branched codeline, but changes can be propagated in the other direction as well.
There is one fundamental difference between resolving conflicts in two revisions of the same file, and resolving conflicts between the same file in two different codelines. The difference is that Perforce will detect conflicts between two revisions of the same file and then schedule a resolve, but there are always differences between two versions of the same file in two different codelines, and these differences usually don't need to be resolved. Perforce that text in one file needs to be propagated to its branch with
p4 integrate
. If the codelines evolve separately, and changes never need to be propagated, you'll never need to integrate or resolve the files in the two codelines.
p4 integrate
only acts on files that are the intersection of target files in the branch view and the client view. If file patterns are given on the command line, integrate
further limits its actions to files matching the patterns. The donor files supplied as arguments to integrate
need not be in the client view.To run the
p4 integrate
command, write
access is needed on the target files, and read
access is required on the donor files.
-r
flag to p4 integrate
.Ed wants to integrate a change in Kurt's branched
src/screen.c
file to Ed's original version of the same file. He types p4 integrate -r -b elm_r1 //depot/elm_proj/src/screen.c
; and then p4 resolve
. The change in the branched file is propagated to his source file.When the
-r
flag is used to propagate changes from branched donors to original targets, the original source files must be visible through the target view.
p4 branch -d branchname
integrate
command will integrate into the target all the revisions of the donor since the last donor revision that integrate
was performed on. A revision range can be specified when integrating; this prevents unwanted revisions from having to be manually deleted from the merge while editing. In this case, the revision used as base is the first revision below the specified revision range.The syntax here is a little strange: although the file provided as an argument to
p4 integrate
is the target, the file revision specifier is applied to the donor.Ed has made two bug fixes to his file
src/init.c
, and Kurt wants to integrate the change into his branched version, which is called newinit.c.
Unfortunately, init.c
has gone through 20 revisions, and Kurt doesn't want to have to delete all the extra code from all 20 revisions while resolving.Kurt knows that the bug fixes he wants were made in revisions
31
and 32
of Ed's init.c
file. From the directory of his newinit.c
file in his branched workspace, he types
p4 integrate -b elm_r1 src/newinit.c#31,32
The target file is given as an argument, but the file revisions are applied to the donor. When Kurt runs p4 resolve
, only revisions 31
and 32
of Ed's file are scheduled for resolve, that is, Kurt only sees the changes that Ed made to init.c
between revision 31
and revision 32
. The 30
th revision is used as base
.
p4 integrate
will give the error message All revisions already integrated
. But integration of a particular donor can be forced, even when integration has already been performed, by providing the -f
flag to p4 integrate
.A target file that has been resolved, but not yet submitted, can be re-resolved with
p4 reresolve
. By the time reresolve
is called, the original client target file has been replaced with the result file of the resolve process; thus, when re-resolving, yours will be the new client file, which is the result of the original resolve.
There are two methods by which this can be done. The easiest way is to call
p4 integrate
with two file arguments and without the -b branch
flag, as in
p4 integrate donor_file target_fileWhen
p4 integrate
is called this way, it will perform the integration between the two named files. The first file argument provides the donor; the second provides the target. A second method would be to set up a new branch that includes the donor and target files on each side of the same mapping within the branch view, and then integrate on this branch with the
-b
flag.This process may be surprising when first seen, but it is a natural by-product of Perforce's branching mechanism. Creating a branched codeline merely makes copies of the files in the original codeline; these files evolve entirely separately from each other, and are not considered `related' until
p4 integrate
is called upon with the -b
branch flag to find the common bloodline.The integration process is slightly different when integrating two previously unrelated files. Since the two file revisions did not begin their lives at a common, older file revision, there can be no base file, so
p4 resolve
can't do a three-way merge. In this case, p4 resolve
will do a two-way merge, in which yours is also used as base. In a two-way merge, all changes appear as theirs, and there can be no conflicts.
The Integration Algorithm
p4 integrate
performs the following steps:
When the
-r
flag is not provided to p4 integrate
, the original codeline provides the donor files, and the branched codeline provides the targets. When the -r
flag is given, the branched codeline is the donor, and the original files are the targets. Integration Reporting
There are five branching-related reporting commands: