[Top] [Prev] [Next]

Branching

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.

What is Branching?

Branching is a method of keeping in sync two or more sets of similar, but not identical, files. Most software configuration management systems have some form of branching; we believe that Perforce's mechanism is unique in that it mimics the style in which users create their own file copies when no branching mechanism is available.

Suppose for a moment that you're writing a program and are not using an SCM system. You're ready to release your program: what would you do with your code? Chances are that you'd copy all your files to a new location. One of your file sets would become your release codeline, and bug fixes to the release would be made to that file set; your other files would become your development file set, and new functionality to the code would be added to these files.

What would you do when you find a bug that's shared by both file sets? You'd fix it in one file set, and then copy the edits that you made into the other file set.

The only difference between this homegrown method of branching and Perforce's branching methodology is that Perforce manages the file copying and edit propagation for you. In Perforce's terminology, copying the files is called making a branch; each file set is known as a codeline, and copying an edit from one file set to the other is called integration. The entire process is called branching.

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:

Branching's First Action:
Creating a Branch

As described above, two separate actions comprise branching: first, a branch is created (e.g., files are copied); second, edits are copied from one codeline to the other as needed. This section describes the first of these actions.

The steps to creating a branched codeline are:

  1. Create the new branch view with 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.
  2. Make sure that the new files and directories are included in the p4 client view of the client workspace that will hold the new files.
  3. Use p4 integrate to open the new files for branching. The new files are listed in a changelist; the associated operation is branch.
  4. Use p4 submit to submit the changelist to the perforce server. This creates the new files in the depot.
  5. Copy the new files from the depot to the client workspace with p4 sync.

The following example demonstrates each of these steps.

Step 1: Create the Branch View

The first step is to create the branch view. Creating a branch view does four things:

  1. Assigns the branched codeline a name;
  2. Describes which files will be copied from;
  3. For each original file, describes where the new copy will be stored within the depot;
  4. Maintains a mapping between each original and branch file, so that changes to one can be easily propagated to the other.

A version of Elm is ready for release, and a potential problem is foreseen: the developers will be submitting code to the depot for the next version of Elm, but the release engineers will be submitting fixes to the released version. The two policies are clearly incompatible; so a branched codeline, with duplicate Elm files, needs to be created. Kurt, one of the release engineers, is assigned to create the branch for the release engineers.

The original code is stored in the depot under its elm_proj 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

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.

Step 2: Include the Branched Files in the Client View

In order to work with branched files, the branched files must be accessible through the client 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.

Steps 3 & 4:
Use `p4 integrate' and `p4 submit'
to Create the Target Files

To create the new branch files, use p4 integrate followed by p4 submit. When the branch files don't yet exist in the depot, integrate creates the branched files in the client workspace and 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 affect the depot immediately; 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

If the filepatterns are left off, all the files in the branch are affected. When included, the filepatterns must describe the new files, not the original 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/sync from //depot/elm_proj/Changes#6
//depot/elm_release1/NOTICE#1 - branch/sync from //depot/elm_proj/NOTICE#23
      <etc.>

The branched files have been created in his client workspace, and 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 and are copied into the client workspace.

If Kurt wanted the files to be created in the depot but not synced to the client workspace, he could have used the -v flag with the integrate command. If he did this, the files would later need to be copied to the client workspace with p4 sync.

Editing Newly Branched Files

By default, a file that has been newly created in a client workspace by p4 integrate cannot be edited before its first submission. To make a newly-branched file available for editing before submission, simply p4 edit the file.

Working With Branched Files

Once a branch has been created and the files have been copied into the branched codeline with p4 integrate, the branched files are treated exactly like non-branched files, with the normal use of sync, edit, delete, submit, etc. Evolution of both codelines proceeds separately; additional Perforce commands are used only when changes to one codeline need to be propagated to the other.

Branching's Second Action:
Propagating Changes from One Codeline
to the Other

It is worth repeating that two separate actions comprise branching: first, one set of files is copied from one location in the depot to another location, and second, changes made to one codeline can be copied to the branched codeline as needed. The steps needed to accomplish the first action have been described above; now we'll discuss how to accomplish the second action.

Edits to a file in either codeline can be propagated to the corresponding file in the other codeline with the 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. In its normal use with branched files, p4 integrate takes the form p4 integrate -b branchname files, where the specified files are the branched files rather than the original 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

and sees

//depot/elm_release1/src/elm.c#1 - integrate from //depot/elm_proj/src/elm.c#9

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. You must tell 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. Protections are discussed in Chapter 9.

Propagating Changes from Branched Files
to the Original Files

A change can be propagated in the reverse direction, from branched files to the original files, by supplying the -r flag to p4 integrate. In this case, the names of the original files are provided as arguments to p4 integrate -r.

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.

Branching and Merging
Without a Branch View

Thus far, we have been describing the two actions that comprise branching: copying a set of files from one location in the depot to another, and propagating edits of one of the codelines to the other codeline. It is possible to use p4 integrate to perform both of these steps without ever having created a branch view. This is accomplished by calling p4 integrate with two file arguments and without the -b branch flag, as in

When 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. The donor file must already exist; the target file needn't. There are three possible combinations of donor and target:

Deleting Branches

To delete a branch, use

Deleting a branch deletes only the branch view description, making the branch inaccessible from any subsequent p4 integrate commands. If the files in the branched codeline are to be removed, they must be deleted with p4 delete.

Advanced Integration Functions

Perforce's branching mechanism also allows integration of specific file revisions, the re-integration and re-resolving of already integrated code, and merging of two files that were previously not related.

Integrating Specific File Revisions

By default, the 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 to file revisions submitted in changelist 30. From the directory of his newinit.c file in his branched workspace, he types

The target file is given as an argument, but the file revisions are applied to the donor. When Kurt runs p4 resolve, only the revision of Ed's file that was submitted in changelist 30 is scheduled for resolve, that is, Kurt only sees the changes that Ed made to init.c in changelist 30. The file revision that was present in the depot at changelist 29 is used as base.

Re-Integrating and Re-Resolving Files

Once a particular revision of a donor file has been integrated into a particular target, that particular revision is usually skipped in subsequent integrations with the same target. If all the revisions of a donor have been integrated into a particular target, p4 integrate will give the error message All revisions already integrated. But integration of a particular donor can be forced, even though integration has already been performed, by providing the -f flag to p4 integrate.

Similarly, a target file that has been resolved but not yet submitted can be re-resolved by providing the -f flag to p4 resolve, which forces re-resolution of already resolved files. When this flag is used, the original client target file will already have been replaced with the result file of the original resolve process; thus, when re-resolving, yours will already be the new client file, the result of the original resolve.

How Integrate Works

The preceding material in this chapter was written from a user's perspective. This section makes another pass at the same material, this time describing the mechanism behind the integration process.

p4 integrate's Definitions of yours, theirs, and base

The values of yours, theirs, and base in a three-way merge are quite different when propagating changes between two codelines:

yours


The file that changes are being propagated to (also known as the target file). This file is in the client workspace, and it is overwritten by the result once the resolve process is complete.

In a forward integrate, this is a file in the branched codeline. When the -r flag has been provided to integrate, this is a file in the original codeline.


theirs


The file revision that changes are being read from (also known as the donor file). This file revision comes from the depot, and is unchanged by the resolve process.

In a forward integrate, this is a file revision from the original codeline. When the -r flag has been provided to integrate, this is a file in the branched codeline.


base


The last integrated revision of the donor file. When a new branch is created and integrate is used to create the branched copy of the file in the depot, the newly-branched copy is base.

Yours, theirs, and base are first discussed in chapter 5.

The Integration Algorithm

p4 integrate performs the following steps:

  1. It applies the branch view to any target files provided on the command line to produce a list of donor/target file pairs. If no files are provided on the command line, a list of all donor/target file pairs is generated. It notes individually each revision of each donor file that is to be integrated.
  2. It discards any donor/target pairs for which the donor file revisions have been integrated in previous changes. Each revision of each file that has been integrated is remembered individually, in order to avoid making the user merge changes more than once.
  3. It discards any donor/target pairs whose donor file revisions have integrations pending in files that are already opened in the client.
  4. All remaining donor/target pairs will be integrated. The target file is opened on the client for the appropriate action (see below), and merging is scheduled.

Integrate's Actions

The integrate command will take one of three actions, depending on particular characteristics of the donor and target files:

Action

Meaning

branch


If the target file does not exist, it is opened for branch. The branch action is a variant of add, but Perforce keeps a record of which donor file the target file was branched from. This allows three-way merges to be performed between subsequent donor and target revisions with the original donor file revision as base.


integrate


If both the donor and target files exist, the target is opened for integration, which is a variant of edit. Before a user can submit a file that has been opened for integration, the donor and target must be merged with p4 resolve.


delete


When the target file exists but no corresponding donor file is mapped through the branch view, the target is marked for deletion. This is consistent with integrate's semantics: it attempts to make the target tree reflect the donor tree.

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

The branching-related reporting commands are:

Command

Function

p4 integrate
-n [filepatterns]

Reports what integrate would do without actually doing it. Any of the usual parameters to integrate can be specified as well.


p4 resolve
-n [filepatterns]

Reports files that have been scheduled for resolve by p4 integrate, but that have not yet been resolved. Reports what p4 resolve would do without actually doing it. Any of the usual parameters to resolve can be provided as well.


p4 resolved

Lists those files that have been resolved, but have not yet been submitted.


p4 integrated
[filepatterns]

Describes all integrated and submitted files that match the filepattern arguments.


p4 branches

Display a list of all branches known to the system.


p4 filelog
[filepatterns]

Describes the revision history of the named files. For each revision of the named files, the following is reported:

· change number;

· operation (edit, add, delete, branch, integrate)

· client name;

· user name; and

· description.

If the operation was branch or integrate, the names and revisions of the corresponding branch files are reported as well.

There is an ordering to the first four of these commands: the first is performed before integrate; the second is done after integrate and before resolve; the third is given after resolve but before submit, and the fourth is performed after submit. The fifth command provides a complete history of any file, and is incredibly useful.



[Top] [Prev] [Next]

Command Line User's Guide for PERFORCE
Copyright 1997 Perforce Software. Comments to [email protected].
Last updated: November 20, 1997