Perforce 98.2 p4 User's Guide
<< Previous Chapter
Labels
Table of Contents
Index
Perforce on the Web
Next Chapter >>
Job Tracking

Chapter 9
Branching

Perforce's Inter-File BranchingTM mechanism allows any set of files to be copied within the depot, and allows changes made to one set of files to be copied, or integrated, into another. 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 synchronized 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 file files would be 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:

  • The members of the development group want to submit code to the depot whenever their code changes, whether or not it compiles; but the release engineers don't want code to be submitted until it's been debugged, verified, and signed off on. They would branch the release codeline from the development codeline; when the development codeline is ready, it would be integrated into the release codeline. Patches and bug fixes would be made in the release code; later, these changes could be integrated into the development code.

  • A company is writing a driver for a new multi-platform printer. They've written a UNIX device driver; they're now going to begin work on a Macintosh driver, using the UNIX code as their starting point. They create a branch from the existing UNIX code; they now have two copies of the same code, and these codelines can evolve separately. If bugs are found in either codeline, bug fixes can be propagated from one codeline to the other with the perforce integrate command.

  • At Perforce, we use branching to manage our releases. Development always proceeds in files located within //depot/main/... When a new release is ready, it's branched into another codeline, for example, the code for release 98.1 was copied from //depot/main/... into //depot/r98.1/... Bug fixes that affect both codelines will be made within //depot/main/..., and later integrated into the other codeline.

    Development of release 98.2 proceeded in //depot/main/..., when the new release was ready, it was branched into //depot/r98.2/..., and the process continues like this for all Perforce releases.

Perforce's Branching Mechanisms: Introduction


Perforce provides two mechanisms for branching. One method requires no special setup, but requires the user to manually track the mappings between the two sets of files; the second method remembers the mappings between the two file sets, but requires some additional work at the start. In the first method, the user specifies both the files that changes are being copied from and the files that the changes are being copied into. The command looks like this:

   p4 integrate fromfiles tofiles

In the second method, Perforce stores a mapping that describes which set of files get branched to other files, and this mapping, or branch specification, is given a name. The command the user runs to copy changes from one set of files to the other looks like this:

   p4 integrate -b branchname [tofiles]

These methods are described in the following two sections.

Branching and Merging, Method 1: Branching with File Specifications


Use p4 integrate fromfiles tofiles to propagate changes from one set of files (the donor files) to another set of files (the target files). The target files need to be contained within the current client workspace view; the donor files need not be, as long as the donor files are specified in depot syntax. If the target files do not yet exist, the entire contents of the donor files will be copied to the target files. If the target files have already been created, changes can be propagated from one set of files to the other with p4 resolve. In both cases, p4 submit must be used to store the new file changes in the depot. Examples and further details are provided below.

Creating Branched Files

To create a copy of a file that will be tracked for branching, use the following procedure:

  1. Determine where you want the copied (or branched) file(s) to reside within the depot and within the client workspace. Add the corresponding mapping specification to your client view.

  2. Run p4 integrate fromfiles tofiles. The donor files fromfiles will be copied into the client workspace to the target files tofiles.

  3. Run p4 submit. The new files will be created within the depot, and are now available for general use.

Example
Creating a branched file.
Version 2.0 of Elm has just been released, and work on version 3.0 is about to commence. Work on the current development release always proceeds in //depot/elm_proj/..., and it is determined that maintenance of version 2.0 will take place in //depot/elm_r2.0/... The files in //depot/elm_proj/... need to be branched into //depot/elm_r2.0/..., so Ed does the following:

He decides that he'll want to work on the new //depot/elm_r2.0/... files within his client workspace at /usr/edk/elmproj/r2.0. He uses p4 client to add the following mapping to his client view:

   //depot/elm_r2.0/... //eds_elm/r2.0/...

He runs

   p4 integrate //depot/elm_proj/... //depot/elm_r2.0/...

which copies all the files under //depot/elm_proj/... to the correct location in his client workspace. Finally, he runs p4 submit, which adds the newly created branched files to the depot.

Why Not Just Copy the Files?

It is certainly possible to accomplish everything that has been done thus far by copying the files within the client workspace and using p4 add to add the files to the depot. But when you do this with p4 integrate, Perforce tracks the connections between related files in an integration record, allowing easy propagation of changes between one set of files and another.

Propagating Changes Between Branched Files

Once a file has been branched from another with p4 integrate, Perforce can track changes that have been made in either set of files and merge them into the corresponding branch files. The procedure is as follows:
Reference
You'll find a general discussion of file resolution in the File Conflicts chapter, and branching and file resolution are discussed in more detail later in this chapter.
  1. Run p4 integrate fromfiles tofiles to tell Perforce that changes in the donor files need to be propagated to the target files.

  2. Use p4 resolve to copy changes from the donor files to the target files. The changes will be made to the target files in the client workspace.

  3. Run p4 submit to store the changed target files in the depot.

Ed has created a release 2.0 branch of the Elm source files as above, and has fixed a bug in the original codeline's src/elm.c file. He wants to merge the same bug fix to the release 2.0 codeline. From his home directory, Ed types

   p4 integrate elm_proj/src/elm.c //depot/elm_r2.0/src/elm.c

and sees

//depot/elm_r2.0/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/edk/elm_r2.0/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.

Reference

Protections are discussed in Chapter 9.
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. In their day-to-day use, there is no difference between branched files and non-branched files; the standard Perforce commands like sync, edit, delete, submit, etc. are used with all files, and evolution of both codelines proceeds separately. When changes to one codeline need to be propagated to another, you must tell Perforce to do this 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.

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 branched files as the donor files, and the original files as the target files.

Ed wants to integrate some changes in //depot/elm_r2.0/src/screen.c file to the original version of the same file. He types

   p4 integrate //depot/elm_r2.0/src/screen.c //depot/elm_proj/src/screen.c

and then runs p4 resolve. The changes in the branched file can now be merged into his source file.

Branching and Merging, Method 2: Branching with Branch Specifications


In the method described above, the user must manually track which donor files go with which target files. A slightly different branching mechanism allows Perforce to track this for you; the target files are mapped to donor files in a branch specification, and the name of the branch specification is provided as an argument to p4 integrate.The downside is that the initial setup is slightly more complicated; the benefit is that the user no longer needs to remember the exact mappings between target files and donor files. To create and use a branch specification, do the following:
  1. Use p4 branch branchname to create a view that indicates which target files map to which donor files.

  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 -b branchname to create the new files.

  4. To propagate changes from donor files to target files, use p4 integrate -b branchname [tofiles]. Perforce will use the branch specification to determine which files the merged changes come from.

  5. Use p4 submit to submit the changes to the target files to the depot.

The following example demonstrates the same branching that was performed in the example above, this time using a branch specification.

Example
Creating a branch.
Version 2.0 of Elm has just been released, and work on version 3.0 is about to commence. Work on the current development release always proceeds in //depot/elm_proj/..., and it is determined that maintenance of version 2.0 will take place in //depot/elm_r2.0/... The files in //depot/elm_proj/... need to be branched into //depot/elm_r2.0/..., so Ed does the following:

Ed creates a branch specification called elm2.0 by typing p4 branch elm2.0. The following form is displayed:

Branch: elm2.0
Date: 05/25/1997 17:43:28
Owner: edk
Description:
   Created by edk.
View:
   //depot/... //depot/...

The default View: above would branch the entire depot into itself, which is useless. The view should map the original codeline's files on the left to branched files on the right. Ed changes the View: and Description: fields as follows:

Branch: elm2.0
Date: 05/25/1997 17:43:28
Owner: edk
Description:
   Elm release 2.0 maintenance codeline
View:
   //depot/elm_proj/... //depot/elm_r2.0/...

Ed wants to work on the new //depot/elm_r2.0/... files within his client workspace at /usr/edk/elmproj/r2.0. He uses p4 client to add the following mapping to his client view:

   //depot/elm_r2.0/... //eds_elm/r2.0/...

He runs p4 integrate -b elm2.0, which copies all the files under //depot/elm_proj/... to the correct location in his client workspace; then he runs p4 submit, which adds the newly branched files to the depot.

Once the branch has been created and the files have been copied into the branched codeline, changes can be propagated from target files to donor files with p4 integrate -b branchname.

A bug has been fixed in the original codeline's src/elm.c file. Ed wants to propagate the same bug fix to the branched codeline he's been working on. He types

   p4 integrate -b elm2.0 ~edk/elm_r2.0/src/elm.c

and sees

//depot/elm_r2.0/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/edk/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.

Branch Specification Usage Notes

  • Creating or altering a branch specification has absolutely no immediate effect on any files within the depot or client workspace! The branch specification merely specifies which files will be affected by subsequent p4 integrate commands.

  • Branch specifications may contain multiple mappings, just as client views can. For example, the following branch specification branches the Elm 2.0 source code and documents to two separate locations within the depot:

    Branch: elm2.0
    Date: 05/25/1997 17:43:28
    Owner: edk
    Description:
        Elm release 2.0 maintenance codeline
    View:
        //depot/elm_proj/src/...  //depot/elm_r2.0/src/...
        //depot/elm_proj/docs/...  //depot/docs/2.0/...

  • Exclusionary mappings may be used within branch specifications.

  • Integration Usage Notes

    • 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.

    • The basic syntax of the integrate command when using a branch specification is

         p4 integrate -b branchname [tofiles]

      If the filepatterns are left off, all the files in the branch are affected. Except as noted below, when the tofiles argument is included, it must describe the original source files, not the branched files; and these files must be visible through the client view.

      • The direction of integration through a branch specification may be reversed with the -r flag. For example, to integrate changes from a branched file to the original source file, use p4 integrate -b branchname -r [sourcefiles]

      • The p4 integrate command, like p4 add, p4 edit, and p4 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 actual action performed by p4 integrate is determined by particular properties of the donor files and the target files:

        If the target file doesn't exist, the target file is opened for branch, and Perforce will begin tracking the integration history between the two files. Subsequent merges of the two files will treat this donor revision as base.

        If the target file exists, and was originally branched from the donor file with p4 integrate, then a three-way merge is scheduled between the target and the donor.

        If the target file exists, but was not branched from the donor, then these two file revisions did not begin their lives at a common, older file revision, so there can be no base file, and p4 resolve can't do a three-way merge. In this case, p4 resolve will perform 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.

      • 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.

      • To run the p4 integrate command, write access is needed on the target files, and read access is required on the donor files.

    • Deleting Branches


      To delete a branch, use

         p4 branch -d branchname

      Deleting a branch deletes only the branch specification, making the branch specification inaccessible from any subsequent p4 integrate commands. The files themselves can still be integrated with p4 integrate fromfiles tofiles, and the branch specification can always be redefined. 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.

      Example
      Integrating Specific File Revisions
      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 containing his newinit.c file in his branched workspace, he types

         p4 integrate -b elm_r1 newinit.c@30,@30

      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

      Reference
      yours, theirs, and base are first discussed in the conflict resolution chapter.
      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.

      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 change number, operation (add, edit, delete, branch, integrate), client name, user name, and changelist description are reported. 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 sixth command provides a complete history of any file, and is incredibly useful.

      For More Information


      Although Perforce's branching mechanism is relatively simple, the theory of branching can be very thorny. When should a branch be created? At what point should code changes be propagated from one codeline to another? Who is responsible for performing merges? These questions will arise no matter what SCM system you're using, and the answers are not simple. Three on-line documents can provide some guidance in these matters.

      A white paper on InterFile Branching, which describes Perforce's branching mechanism in technical detail, is available from

      Christopher Seiwald and Laura Wingerd's Best SCM Practices paper provides a discussion of many source configuration management issues, including an overview of basic branching techniques. This paper is available at

      Streamed Lines: Branching Patterns for Parallel Software Development is an extremely detailed paper on branching techniques. As of this writing, you'll find it at

      This paper is a work-in-progress, and is not meant for beginners!


      Perforce 98.2 p4 User's Guide
      << Previous Chapter
      Labels
      Table of Contents
      Index
      Perforce on the Web
      Next Chapter >>
      Job Tracking
      Please send comments and questions about this manual to [email protected].
      Copyright 1997, 1998 Perforce Software. All rights reserved.
      Last updated: 08/11/98