BUY THIS BOOK
Add to Cart

Print Book $39.95


Add to Cart

Print+PDF $51.94

Add to Cart

PDF $31.99

Safari Books Online

What is this?

Add to UK Cart

Print Book £28.50

What is this?

Looking to Reprint or License this content?


Practical Perforce
Practical Perforce By Laura Wingerd
November 2005
Pages: 358

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Files in the Depot
This chapter describes how Perforce stores files and directories in its repository, the depot. It starts by introducing the syntax that allows you to work with depot files and follows with examples of how to browse the depot and get information. Finally, it touches on file properties and their effect on how Perforce handles file content internally.
You may be happiest using a GUI (graphical user interface) for your day-to-day work. This book, however, bases most of its examples on P4, the Perforce Command-Line Client. One reason we stick with P4 is simply that it's easier to create and write about text examples than it is to create and write about screenshots. So don't take our bias toward P4 as a snub of the Perforce GUI programs. In fact, we'll point out some P4V features that show you at a glance what P4 would take thousands of lines of output to tell you. On the other hand, the GUIs are somewhat limited—only P4 offers the complete lexicon of Perforce commands. So, while you are encouraged to use a GUI, expect to use the command line from time to time to do the things the GUIs don't do.
Perforce is widely used partly because it is so portable, and part of that portability comes from the platform-independent file syntax it provides. While native platform syntax can be used to refer to workspace files, Perforce provides its own uniform syntax for referring to workspace and depot contents. This syntax is known as a file specifier, or "filespec." A filespec can refer to a single file or a collection of files, to a specific revision or a range of revisions, and to depot files or workspace files. More importantly, the filespec syntax applies to all operating systems; Perforce converts filespecs to native file references for local operations.
Depots, where Perforce keeps master file content, and workspaces, where users work on files, are hierarchical structures of directories and files. A filespec uses "//" to indicate the root of the hierarchy, and "/" as a directory path and file name separator. For example:
//depot/projectA/doc/index.html
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Perforce Filespec Syntax
Perforce is widely used partly because it is so portable, and part of that portability comes from the platform-independent file syntax it provides. While native platform syntax can be used to refer to workspace files, Perforce provides its own uniform syntax for referring to workspace and depot contents. This syntax is known as a file specifier, or "filespec." A filespec can refer to a single file or a collection of files, to a specific revision or a range of revisions, and to depot files or workspace files. More importantly, the filespec syntax applies to all operating systems; Perforce converts filespecs to native file references for local operations.
Depots, where Perforce keeps master file content, and workspaces, where users work on files, are hierarchical structures of directories and files. A filespec uses "//" to indicate the root of the hierarchy, and "/" as a directory path and file name separator. For example:
//depot/projectA/doc/index.html
Although we often refer to an entire repository as "the depot", there can be multiple depots in a Perforce repository. The filespec root identifies the name of the depot. The filespec //depot/projectA/doc/index.html refers to a depot named "depot" (Figure 1-1.)
Figure 1-1: Filespecs and the depot hierarchy
A filespec can express a relative path as well as an absolute path. An unrooted filespec is a relative reference to the current directory (if you're using a command shell) or the current folder (if you're using a GUI). Depending on the context, doc/index.html or even just index.html could indicate the same file. In the chapter 2 section "Local Syntax, Wildcard Expansion, and Special Characters" you'll find out how to use relative references to files and directories.
When filespecs contain wildcards , they define entire collections of files instead of single files. For example, the "*" wildcard matches characters in filenames at a directory level. Depending on what files are actually present, a filespec like projectA/d*/*.html, for example, can define a collection of files like:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Browsing Depot Files
You can do extensive browsing in a Perforce depot without having to set up a workspace of your own. In fact, there is very little reason to reproduce depot files locally just to see their contents. You can explore the depot hierarchy, peruse file history, read change descriptions, examine file content, and compare depot files, all without going to the trouble of setting up a workspace.
Many of the examples that follow are from the Perforce Public Depot. You, too, can browse the Public Depot by connecting to public.perforce.com:1666. (See Appendix A). However, some of the outputs shown here have been somewhat abridged to shorten line lengths and reduce clutter. If you connect to the Public Depot and try these commands for yourself, you'll get more verbose results.
The depot is a file tree, and the easiest way to navigate it is with a GUI. With P4V, for example, all you have to do is point and click to step down the tree and expand its subdirectories (or folders, as they're called in P4V). A P4V depot tree is shown in Figure 1-6.
Figure 1-6: Navigating the depot tree in P4V
However, you can also navigate from the command line, using P4. To list the topmost levels of the tree, for example, use this dirs command:
p4 dirs "//*"
//guest
//public
Notice that the dirs argument is quoted—that's so the command shell won't expand the asterisk before passing it to the p4 command.
Another way to show the top level of the depot hierarchy is with the depots command:
p4 depots
Depot guest  'Depot for guest users. '
Depot public 'Perforce's open source depot. '
The dirs command can be used at any level of the depot tree to list the subdirectories at that level. For example:
p4 dirs "//public/*"
//public/jam
//public/perforce
//public/revml
The changes command shows the history of a directory, listing the most recent changes first:
p4 changes -m5 //public/revml/...
Change 4971 on 2005/05/21 ... '- Added test to make sure big_r'
Change 4970 on 2005/05/21 ... '- Allow sdbm files to handle la'
Change 4969 on 2005/05/21 ... '- Added a special command line '
Change 4968 on 2005/05/21 ... '- Use module name instead of lo'
Change 4967 on 2005/05/21 ... '- Removed "-d", leaving only "-'
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
File Types at a Glance
Perforce does most of the hard work for you when it comes to storing and managing file content. However, there are some aspects of file storage and behavior that you can control. These aspects are a factor of a file's type; in this section we'll take a brief look at the common file types and their properties. In the next chapter we'll see examples of how to set and change file types.
Perforce supports several types of file content, text and binary being the most common. A file's content type dictates how Perforce will handle it in future operations:
Text files
Text files are stored in the depot as deltas. That is, a revision of a file is not stored in its entirety; only the lines that have changed are stored. Consequently, umpteen revisions of a very large text file don't take much depot space if only a small part of the file changes at each revision. Delta storage is completely transparent to the user, of course—the server takes care of constructing a specific file revision from deltas when you synchronize your workspace.
As it transfers text files to and from workspaces, Perforce translates them so that their line-end delimeters match the local filesystem's format. If your workspace is on Unix, for example, Perforce makes sure lines in text files end with the LF character. If you workspace is on Windows, Perforce makes sure lines end with the CR/LF character pair.
Binary files
Binary files are stored in the depot their entirety. Each revision is stored as a compressed copy of the file. The Perforce client program gets the file revision you need and uncompresses it when you synchronize your workspace. Other than compression, no modification is made to binary files when they are transferred between workspace and server.
Perforce can compare and merge text files. It can't do that with binary files, beyond simply pointing out that the files are different and letting you choose one or the other. (If you have programs that can compare and merge binary files, however, Perforce can invoke them for you. In Chapter 3 we'll take a closer look at this.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Working with Files
In this chapter, we'll survey the Perforce commands you're most likely to use for basic software development. We'll discuss creating and managing a workspace, working on files , and finding out who did what when. If you're already using Perforce, this chapter will be a review. You can skim through it—maybe you'll find something here you didn't know about—or skip it now and come back to it later if you care to.
If you're new to Perforce, this chapter will introduce you to a variety of useful commands. What's more, this chapter will serve as a quick reference to many common tasks. There's more to each of the commands introduced here, of course. You'll find the complete inventory of commands and command options in the P4 Command Reference.
You may wish to experiment with these commands as you read along. See Appendix A if you don't already have Perforce installed.
Whether you're a Perforce user or not, you'll need at least a glancing familiarity with the basic commands described in this chapter so that you can make sense of them as they appear throughout the book.
In Perforce, working on files involves setting up and synchronizing a workspace, adding and working on files, resolving parallel changes (if necessary), and submitting changes to the depot:
Setting up a workspace
The first thing you do before you can work on files is define a client workspace for yourself. A client workspace specification, or client spec, tells Perforce where in your local filesystem you want your workspace to be rooted. It has a view that defines the areas of the depot you want access to, and maps them to directories beneath the workspace root. Once you've set up your workspace, you can work on files.
Adding new files
If you have files in your workspace already—files that you created or moved there yourself—you can add them to the depot. In Perforce, any change you make—adding files , for example—involves two Perforce operations. First you
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
An Overview
In Perforce, working on files involves setting up and synchronizing a workspace, adding and working on files, resolving parallel changes (if necessary), and submitting changes to the depot:
Setting up a workspace
The first thing you do before you can work on files is define a client workspace for yourself. A client workspace specification, or client spec, tells Perforce where in your local filesystem you want your workspace to be rooted. It has a view that defines the areas of the depot you want access to, and maps them to directories beneath the workspace root. Once you've set up your workspace, you can work on files.
Adding new files
If you have files in your workspace already—files that you created or moved there yourself—you can add them to the depot. In Perforce, any change you make—adding files , for example—involves two Perforce operations. First you open your workspace files, indicating whether you want to add, change, or delete them. Then, after making changes locally, you submit files to the depot.
Don't confuse Perforce's idea of open with the idea of opening files in applications. In Perforce, an open file is a file you intend to change. Opening a file with Perforce does not launch an application. And an application—Word or Vim, for example—can open a workspace file whether or not Perforce considers it open.
Synchronizing your workspace
To work on files that are already in the depot, you must first synchronize your workspace (see Figure 2-1). This step gets local copies of the latest depot files. Your workspace is considered to be "in sync" when all the files in it match their depot counterparts.
Figure 2-1: Synchronizing a workspace
Working on files
By default, Perforce creates nonwritable files in your workspace. This is meant as a gentle reminder to you that these files are under its control. Although you're free to do what you want in your workspace, including changing file permissions, the preferred method is to let Perforce know what you're up to by opening files first. You open files with commands that indicate what you plan to do—
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating A Workspace
A Perforce workspace has a physical part and a conceptual part. The physical part is the area on your local disk where Perforce will read and write files. The conceptual part of your workspace is the client object that represents it in the Perforce database. The client object has to exist before you can do any work on files. You create it by editing a client spec .
The Perforce database models many non-file objects, including workspaces, users, user groups, depots, and so forth. The interface to these non-file objects is what Perforce calls a spec form. Perforce gives you a spec form to edit when you run commands like:
p4 client
To command line users, the spec form will be simply a text file that looks something like this:
Client: testws
Owner:  bill
Root:   c:\workspace\test
View:
    //depot/proj/...   //testws/proj/...
    //depot/utils/...  //testws/utils/...
Fields in the form start in the left-hand column. (In this example, the fields are Client, Owner, Root, and View.) The value in each field follows the field name. Single-line values can be placed on the same line as the field name. Multi-line values start on the line following the field name; each line in the value is indented by tabs or spaces.
The Perforce GUI programs (P4V and the rest) give you an actual form to fill out, so you don't have to worry about field names and indentation.
There will be plenty of references to spec forms in this book. We'll use a format for them that looks like this:
Client             testws
Owner              ron
Root               c:\workspace\test
View               //depot/proj/...   //testws/proj/...
                   //depot/utils/...  //testws/utils/...
This format is not what you'll see either in the GUI programs or in your editor. It's the same information, however; it's simply formatted for easy reading.
In this book, we'll often preface the spec form by the P4 command that launches it in your editor. If you're using a GUI, look for the equivalent command in the application menus. (In P4V, for example, a command that lets you edit a workspace client spec is Connection → Edit Current Workspace.)
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Synchronizing a Workspace
The next step after configuring a workspace and making it the current workspace is to synchronize it. When you synchronize your workspace. Perforce does two things. First, it copies files from the depot to your local disk. Second, it makes an internal record of the file revisions you have on disk.
If you want a preview of the files you need to synchronize, or if you're simply interested in seeing which depot files have been updated since the last time you synchronized, use the sync command with the -n option:
p4 sync -n
Use the sync command to synchronize your workspace:
p4 sync
Without arguments, the sync command synchronizes your entire workspace. It copies the latest versions of depot files to their corresponding locations on your local disk. (Assuming there are files in the depot, of course. If you're using a virgin Perforce installation there won't be anything to synchronize with yet.)
If you're synchronizing for the first time, be sure to preview the operation first! In other words, run the following command first:
p4 sync -n
A common mistake is to start synchronizing before realizing that your workspace view is too large. This is not an irreparable situation, of course, but you can save yourself some grief by making sure you know what's going to be synchronized before Perforce starts filling up your disk.
You can run sync as often as you like—it refreshes only the files that have changed. Perforce is smart enough not to recopy files that are already present in your workspace.
Normally, commands like sync operate on your entire workspace. But you can also synchronize your workspace in bits and pieces. Just supply a filespec to the sync command. For example, this command effectively synchronizes the //depot/dev/www directory:
p4 sync //depot/dev/www/...
Another useful way to limit the scope of synchronization is with wildcards that match to only certain files:
p4 sync "//.../*.png"
This command synchronizes only the *.png files, rather than the entire workspace. (The
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Local Syntax, Wildcard Expansion, and Special Characters
Once you have files in your workspace, refering to them with Perforce filespec syntax may be a bit confusing. However, you can also use the syntax native to your local machine to refer to workspace files. If your workspace is on Windows, for example, you can refer to a file with local syntax like:
c:\ws\projectA\www\index.html
For its internal operations, Perforce translates that to a depot filespec like:
//depot/projectA/www/index.html
(The actual location of the file in the depot is determined by the workspace view.)
If your current directory is beneath your workspace root, you can also use relative filenames. For example, if you're in the workspace directory mapped to the depot's //depot/projectA/www directory, you can use a command like:
p4 have index.html
to refer to the //depot/projectA/www/index.html file.
You can mix and match local syntax with filespec syntax. Usually you do this when you want to use Perforce revisions or wildcards with local file names. For example:
p4 sync c:\ws\projectA\...@Rel2.4
This hybrid of local syntax and filespec is acceptible. In this example, it identifies the collection of depot files that are mapped to the c:\ws\projectA path. The sync command shown here will copy the depot file revisions labeled @Rel2.4 to the workspace.
As you saw earlier, spaces in filenames and pathnames have to be quoted when they are referenced in views. The same goes for commands. Anywhere you enter a filespec—on a command line, or in a spec form—a space in a file or pathname is likely to be misunderstood. To prevent this, put quotes around the filespec. For example:
p4 have "My Dog.jpg"
With quotes as shown, P4 assumes there is one file argument, as you intended. Without quotes, P4 assumes you mean two files, My and Dog.jpg.
When you use P4 commands in a command shell, by the way, you should be aware that the shell is likely to expand special characters it recognizes before passing your file arguments to the P4 program. When you type:
p4 sync *.html
for example, the command shell may actually be invoking:
p4 sync index.html contacts.html
Thus, Perforce never sees your wildcard character and never gets a chance to expand it to the depot files it matches. To slip Perforce wildcard characters past the command shell, use quotes. For example:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Working with Local Files
When you synchronize your workspace with depot files, Perforce normally puts read-only files on your local disk. To make files writable, you have to open them. You also have to open files you plan to add to or delete from the depot.
Remember, in Perforce, an "open file" is a file you plan to submit to the depot. Don't confuse Perforce's meaning of "open" with the idea of opening files in an application.
The basic flow of work in Perforce is that you open files as you work, then submit all your opened files at once when you have completed a unit of work. In this section we'll concentrate on ways to open files. In the next section we'll look at various ways to submit them.
Use the edit command to open files for editing. For example:
p4 edit index.html locations.html
Opening files for editing makes them writable so you you can edit them or otherwise modify them locally. None of your local changes are visible to other users, of course, until you submit your files to the depot:
p4 submit
Files you haven't submitted yet can be listed with the opened command:
p4 opened
//depot/dev/www/index.html#1  - add default change (text)
//depot/dev/www/prices.html#1 - add default change (text)
Each line of opened output shows a file revision, the reason it was opened (add), the pending changelist it belongs to (default change), and the file's type (text).
You can check to see who's working on any files at any time with opened -a:
p4 opened -a contacts.html
//depot/dev/www/contacts.html#3 - edit by tina
Also, you'll notice that as you open files, Perforce informs you if anyone else is working on them as well:
p4 edit contacts.html
//depot/dev/www/contacts.html#3 - opened for edit
... - also opened by tina@tina-web-prep
Just because you've opened files for editing doesn't mean you've gotten around to changing them. To list the opened files you've really changed, use:
p4 diff -sa
If you want to see the actual text diffs, use diff with no flags:
p4 diff
Because the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Working with Pending Changelists and Submitting Files
As you open files, they are associated with a pending changelist. Your local changes don't affect the depot until you submit your files. What you submit to the depot is not individual files, really, but the entire pending changelist.
Use the submit command to submit a changelist:
p4 submit
By default, submit operates on the default pending changelist. (You can have more than one changelist, as you'll see in a moment.) Like the client command, submit launches an editor so that you can fill out a form. The form comes prefilled with the list of files in the changelist. All you really have to fill out for submit is the Description field. For example:
p4 submit
 
Description        Added feature and price list pages for the new web site.
Files              //depot/dev/www/index.html#1 - add
                   //depot/dev/www/price.html#1 - add
Once you save and exit the editor, Perforce begins sending your new and changed files to the depot. Submitting files goes very quickly—about as quickly as the files can be transfered over the network to the server. When all content has reached the server, and assuming you ran into no problems with permissions or triggers, new file revisions are created in the depot and your changelist description is recorded permanently.
It often comes as a surprise to new users that all the files in their changelists are submitted, even the ones that haven't been changed. New revisions whose contents are the same as their unchanged predecessors are created in the depot. If this behavior strikes you as unacceptible, you can revert your unchanged files before submitting them with:
p4 revert -a
Note that even though a file's content is unchanged, revert -a won't revert a file if you've resolved it or done anything to change its type.
Changelists are meant, among other things, to document files changed together as a single unit of work. However, it's easy to end up with unrelated files in your default pending changelist. If that happens, consider splitting your files into changelists that can be submitted separately.
You can create additional changelists with the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Removing and Restoring Files
Removing files can mean a number of things in Perforce. Let's look at removing files—and restoring them, when possible—in three different contexts.
In the first context, you're removing Perforce-managed files from your workspace. In this case, you don't want to affect the depot files in any way—you simply want your workspace to be rid of them. You could remove them yourself, of course, since you have control over them. But it you did that, Perforce would be unaware that they're no longer there. Your have list would be out of kilter. You can prevent that by using Perforce commands to remove files from your workspace.
In a GUI like P4V this is simply a matter of selecting files or folders and clicking File → Remove from Workspace. With P4, however, removing files from your workspace is a little less intuitive. You do it by synchronizing to the symbolic revision #none. For example:
p4 sync c:\ws\dev\www\...#none
This command removes files previously synchronized, but only if they are not open. The open files produce a warning—to remove them you must revert first, then synchronize to #none.
To restore previously removed files to your workspace, simply resynchronize:
p4 sync c:\ws\dev\www\...
The next meaning of removing files is to delete them from the depot while keeping a history of their prior revisions intact. This operation does affect depot files, of course, and because it's a depot change, it requires you to synchronize the files, open them to be deleted, then submit a changelist. For example:
p4 sync c:\ws\dev\wwww\...
p4 delete c:\ws\dev\www\...
p4 submit
...
Change 4933 submitted
Perforce creates new head revisions of deleted files when you submit them—deleted revisions. Deleted file revisions have special properties. When people synchronize deleted revisions, Perforce removes the files from their workspaces. Deleted revisions also behave differently in resolve and integration operations, as we'll see in subsequent chapters.
You can restore deleted files by synchronizing with nondeleted revisions and adding them again. For example, we just saw a set of files deleted in changelist 4933. To restore this set of files, use:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Useful Recipes
There are a couple of Perforce command recipes you may find yourself using often. One is the recipe for reconciling your workspace after working offline. The other is the recipe for backing out changes.
Once you've synchronized your workspace, you can do your development work completely offline. You could, for example, synchronize a workspace on your laptop before leaving the office, then work offline while riding the train home.
But your offline changes can't be submitted unless the files they involve are opened in a pending changelist. Once your laptop is back online you'll have to reconcile your offline changes—the state of your local files, in other words—with your pending changelist.
Reconciling offline changes is simply a matter of opening files after the fact. The formula is:
  1. Find the files that were changed and open them for editing:
    p4 diff -se | p4 -x- edit
  2. Find the files that were removed and open them for deleting:
    p4 diff -sd | p4 -x- delete
  3. Find the files that are new and open them for adding. Assuming that you're in the top-level directory of your workspace, the Windows command to find files and add them is:
    dir /s/b/a-d | p4 -x- add -f
    On Unix that's:
    find . -type f | p4 -x- add -f
    (These dir and find commands list all the files in your local workspace tree and pipe them to P4's add command. The files that are truly new are opened for adding; the rest generate warnings but are ignored by add.)
Having done this, you can either submit your pending changelist or continue working on your opened files.
A change that has been submitted to the depot can be backed out by submitting another change that reverses it. There's a simple recipe for backing out a change. Assuming C is the change number, the recipe is:
  1. Synchronize with the pre-@C files.
  2. Open C's deleted files for adding.
  3. Open C's edited or integrated files for editing.
  4. Synchronize with the latest files.
  5. Open C's added or branched files for deleting.
  6. Resolve files.
  7. Submit changelist.
This sequence of steps assures that the new change restores added, deleted, and edited files to their pre-C content and type.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Resolving and Merging Files
The previous chapter blithely mentions that you may have to resolve and merge files before submitting them. Resolving instructs Perforce to take care of files that been changed in parallel; merging is one way to resolve files. Resolving files is usually easy, and the result is usually exactly want you want, whether you understand how it came about or not. However, there are times when you do need to know exactly how files are resolved and merged. That is what this chapter is about.
This chapter starts out with a review of the Perforce resolve operation:what it's for, when you do it, and what you do with it. It nails down the meanings of "yours" and "theirs," the often-puzzling names Perforce gives to files being resolved. Next, it describes how Perforce actually merges text files. It shows how a merged file is constructed, and explains where and why conflicts are detected. (Merge results that seemed random to you before you read this chapter will seem completely predictable to you once you have read it.) This chapter also explains how to reconcile files that can't be resolved because they've been added, deleted, renamed, or moved. It offers tips for developers to resolve, merge, and reconcile files. Finally, it closes with a bit of arcana, including information about configuring alternate merge tools.
You must resolve files when:
  • You have files opened for editing, and you synchronize them with newer revisions.
  • You have files opened for editing, and your attempt to submit them fails because you aren't synchronized with the head revisions.
  • You are integrating changes between branched files.
The first two cases will be the focus of this chapter. However, most of what you will read here applies to the third case as well, so consider it prerequisite reading for the next chapter, Chapter 4.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Resolving: When, What, and How
You must resolve files when:
  • You have files opened for editing, and you synchronize them with newer revisions.
  • You have files opened for editing, and your attempt to submit them fails because you aren't synchronized with the head revisions.
  • You are integrating changes between branched files.
The first two cases will be the focus of this chapter. However, most of what you will read here applies to the third case as well, so consider it prerequisite reading for the next chapter, Chapter 4.
To lay the groundwork for resolving and merging, let's take another look at what it means to be in sync with the depot. When you synchronize, Perforce fetches files from the depot. For example:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
How Perforce Merges Text Files
Any two files can be compared to reveal diffs. Three files are necessary to merge content, a starting version and two modified versions.
Three-way file merging is an operation you'll find in many content-management tools. Perforce itself implements a three-way merge that operates on lines of text , not on characters, words, or other context-specific syntax. Some three-way merge tools can operate on characters, words, paragraphs, XML structures, HTML markup, programming language syntax, and so forth. If line-by-line merging isn't suitable for the kinds of files you're working with, you can configure Perforce to use another merge tool when resolving files. See "Configuring an alternate merge tool."
In Perforce's three-way merge, the "base" is the starting version and "yours" and "theirs" are the two modified versions of the file. Yours and theirs are each compared to the base so that lines in the three files can be grouped into "chunks ." Each chunk in the base is determined to be changed or unchanged with respect to yours and theirs. Chunks that are added or deleted are considered changed. Perforce constructs a merged file from the chunks using these rules:
  • When a chunk is the same in all three files, it goes into the merged file.
  • When a chunk has been changed in either yours or theirs, but not in both, the changed chunk goes into the merged file.
  • When a chunk has been changed in both yours and theirs, and the change is identical, the changed chunk goes into the merged file.
  • When a chunk is different in all three files, a conflict marker is placed at that location in the merged file. It will be up to you to decide what goes there.
Figure 3-8 shows a simple file merge. When the base file is compared to yours and theirs, six chunks are detected. The merged file consists of:
  • Chunks 1, 3, and 5 from the base. These are chunks of text neither you nor they changed.
  • Chunk 2 from yours. (Or theirs—both of you made the identical change.)
  • Chunk 4 from theirs. You made no change in that spot, but they did, so their chunk goes into the merged file.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Reconciling Structural Changes
Parallel changes that affect depot structure can't be resolved in the same way as can parallel changes to file content alone. Among the changes that can't be resolved are changes where files have been added, deleted, renamed, moved, or combined. Perforce won't schedule files for resolving when:
  • You have files opened for editing and you synchronize with newer depot revisions that are deleted. (In other words, someone else has deleted files you are working on.)
  • You have files opened for deleting and you synchronize with newer, edited depot revisions. (In other words, someone else has edited the files you are about to delete.)
  • You have files opened for adding or branching, and you synchronize with non-deleted depot revisions of files with the same names. (In other words, someone else has already added or branched files before you.)
Perforce does warn people who are opening files if other users have the same files opened. And people should heed these warnings, especially if they're opening files for refactoring or other structural changes. But sometimes they just don't realize that structural changes can't be resolved, and sometimes they have reasons to submit their changes anyway. All is not lost—there are ways to reconcile structural changes.
The advice that follows works best if you make a habit of synchronizing, resolving, and reconciling changes incrementally, as described in "Tips for Smoother Collaboration" later in the chapter.
Let's start with a simple case: You opened some files for adding, and in the meantime, someone else has added files with the same names to the depot. You have resynchronized, but that doesn't affect these files in your workspace. You still have them opened for adding, and you won't be able to submit them.
To detect files in this state, look for files that are both opened for adding and already in the depot:
p4 opened diag04.gif
//depot/dev/www/img/diag04.gif#1 - add default change
 
p4 files diag04.gif
//depot/dev/www/img/diag04.gif#1 - add change 4761
Here, for example, you were going to add
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Tips for Smoother Collaboration
An SCM tool can do only so much to make collaborative development possible. The rest is up to developers. Here are some things developers can do to keep collaboration going smoothly.
When you're working on files in parallel with other developers, resynchronize your workspace regularly. The longer you put off resynchronizing, the harder it is to get caught up. And if you're not caught up, you can't submit files.
Also, instead of resynchronizing individual files, resynchronize all the files in the scope of your work. (The scope could be a directory, several directories, or even your entire workspace.) This keeps your files in sync with each other and assures that when you try to compile or test, you'll have a set of files known to work together.
When you're working in a heavily concurrent environment, it's easier to resolve or otherwise reconcile changes before you attempt to submit files than it is after a submit command fails. So, before you submit, check to make sure you're synchronized:
p4 sync -n
If you're not, synchronize and resolve one changelist at a time, as described in the next section, then submit your files.
If resynchronizing regularly is going to make it difficult for you to do your work, consider working in a private branch. See Chapter 10.
We tend to speak of synchronizing as a way to get caught up with the current state of the depot. But in fast-moving, parallel development projects, many changes can occur in a short time. Simply synchronizing to the latest revisions puts you in a position of having to resolve many peoples' changes at once. This can be confusing, if not downright hellish.
If smooth collaboration is your goal, synchronize, resolve, and reconcile one changelist at a time. Here's a recipe for changelist-by-changelist synchronization. Run these commands from the root of the file tree that encompasses the scope of your work:
  1. First, determine the changelist you're currently synchronized with:
    p4 changes -m1 ...#have
    Change 9284 on 2004/03/01 by jim 'Swap project names'
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Arcana of Merging
What you've read so far may be all you need to know about resolving and merging files for your day-to-day work. In this section we'll take a look at a few advanced and arcane topics that may prove useful in special situations.
Earlier you read that when you auto-resolve files with merging, Peforce skips files if it finds parallel changes that conflict. There is a way to force Perforce to auto-resolve all files with merging even when there are conflicts. Use:
p4 resolve -af
The -af flag makes resolve work the same way as -am, but instead of skipping files with conflicts, it goes ahead and merges changes, leaving conflict markers in the resulting files. Forcing a merge of the files in "A simple file merge," earlier in this chapter, for example, writes this result to your workspace file, as:
cats
dogs
pigs
horses
sheep
cows
>>>> ORIGINAL
aunts
=  ==  = THEIRS
=  ==  = YOURS
ants
<<<<
The advantage of forcing merges is that you can resolve everything at once and edit the conflicts later. But this small advantage may be outweighed by several disadvantages:
  • Forced merging overwrites your workspace files with files that are never syntactically correct. Until you edit them, they won't compile or behave properly in any way.
  • Once you've resolved a file by forcing a merge, the file is ready to submit, as far as Perforce is concerned. There's nothing in Peforce that warns you that you've left conflict markers in files you are submitting.
  • If you forget to edit the conflict markers in a file before resynchronizing and merging newer changes to it, the conflict markers will themselves be treated as file content. And if these lines conflict with the newer changes, the result will be very, very confusing.
You can't undo a resolve. Once you've resolved a file, it's resolved:
p4 resolve -am index.html
c:\ws\doc\index.html
- merging //depot/projectA/doc/index.html#17,#18
merging from //depot/projectA/doc/index.html
 
p4 resolve -am index.html
No file(s) to resolve.
Even if you synchronize a resolved file to a newer revision, it stays resolved with respect to previously resolved revisions.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: Branching and Integration
In the course of software development, we branch files to do concurrent, parallel work on them, and we integrate files to combine the results of such work. In this chapter, we'll look at how to do branching and integration with Perforce.
This chapter won't dwell on reasons to branch, what to branch, or how to work with different kinds of branches, Not that those things aren't important—they are, and they'll be given due consideration in Part II. But for now, we'll limit our discussion to the mechanics of branching and integrating.
Of all the uses for branching , the one best understood is that of branching recently developed software for a product release. For example, assume that we are Ace Engineering and that we've been working on a software product called Ace. We're gearing up to make the first release of Ace available. Our plan is to release Ace Version 1.0 while simultaneously developing new features for a future release. For this, we're going to have to make a branch.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Classic Case for A Branch
Of all the uses for branching , the one best understood is that of branching recently developed software for a product release. For example, assume that we are Ace Engineering and that we've been working on a software product called Ace. We're gearing up to make the first release of Ace available. Our plan is to release Ace Version 1.0 while simultaneously developing new features for a future release. For this, we're going to have to make a branch.
So far, there's one tree of files that constitutes the Ace product. It's in the //Ace/MAIN directory path of our depot. Until now, we've all worked together on the files in the //Ace/MAIN tree, shown in Figure 4-1.
Figure 4-1: One tree of files
With Perforce, we can simply clone the //Ace/MAIN file tree into a new //Ace/V1 file tree. This allows us to continue working on new features in the //Ace/MAIN tree. Meanwhile, those of us testing and stabilizing the 1.0 release can work in the //Ace/V1 tree. The two file trees are shown in Figure 4-2.
Figure 4-2: Cloning //Ace/V1 from //Ace/MAIN
At the outset, every file in the //Ace/MAIN tree has an identical counterpart in the //Ace/V1 tree. Over time, content diverges between the two trees as new development proceeds. The //Ace/V1 tree holds the stable, 1.0 version of the product, and the //Ace/MAIN tree holds the bleeding-edge, unreleased version.
This notion of cloning a tree of files from another is the essence of branching in Perforce. We clone a tree of files so that we can make changes to either tree—or branch—without affecting the other. The two file trees are peers in the depot hierarchy. Moreover, every file is a full-fledged file in its own right. Files in either branch can be edited, added, deleted, renamed, or moved. And changes made in one branch can be merged or otherwise integrated to the other.
Behind the scenes, Perforce keeps track of branching. Although every branched file is a file in its own right, its lineage is stored in the Perforce database. Perforce keeps track of a file's integration history as well. As we successively integrate changes between a pair of branches, Perforce uses file history to keep us from having to re-merge changes we've already merged.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating Branches
As with all operations that affect depot files, creating a branch is a two-step process in Perforce. First you use integrate to open files for branching , then you use submit to make them appear in the depot.
So, back to our Ace example. We can think of the evolution of //Ace/MAIN as a single timeline, punctuated by submitted changelists. (see Figure 4-3.)
Now it's time to branch //Ace/MAIN into //Ace/V1. (We'll call these branches MAIN and V1, for short. See Figure 4-4.)
Figure 4-3: The evolution of //Ace/MAIN
Figure 4-4: Branching V1 from MAIN
Making the branch is simply a matter of using integrate to clone one directory from another:
p4 integ //Ace/MAIN/... //Ace/V1/...
//Ace/V1/db/Jamfile#1 - branch/sync from //Ace/MAIN/db/Jamfile#1,#32
//Ace/V1/db/dbAcc.cpp#1 - branch/sync from //Ace/MAIN/db/dbAcc.cpp#1,#3
//Ace/V1/db/dbDefN.cpp#1 - branch/sync from //Ace/MAIN/db/dbDefN.cpp#1,#7
...
(What's integ? An alias of integrate.) The integrate command takes two filespecs as arguments. The first identifies the donor files and the second identifies like-named target files—the files that will be created, in this case.
Whether it's used to branch, rename, or integrate files, the higher calling of integrate is to propagate change. Change comes from "donor files" and flows to "target files." Thus the integrate command always involves a pair of filespecs, one being the donor and the other the target.
As you can see, every file in MAIN is branched to a corresponding file in V1. For example, donor file //Ace/MAIN/db/Jamfile#32 is branched to target //Ace/V1/db/Jamfile#1. From integrate's output, we can infer that #32 is the head revision of the donor. The message branch/sync ... Jamfile#1,#32 lets us know that revisions #1 through #32 of the donor are going on record as having been integrated into revision #1 of the target.
Perforce bootstraps the new branch by copying donor files from the depot into target files in your workspace. (That's what the branch/sync messages in the output of
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Integrating Changes from Branch to Branch
So, Ace Engineering now has two branches, V1 and MAIN. New development continues in MAIN as bugs are fixed and last-minute changes are submitted in V1. When and why to integrate are topics we'll discuss later in the book. For now, we'll focus on how it's done. In this case, let's assume we're interested in integrating V1's changes into MAIN.
The changes command tells us how the V1 branch has evolved:
p4 changes //Ace/V1/...
Change 3470 on 2004/10/05 by rob 'New threshold for...'
Change 3459 on 2004/10/05 by pete 'Fix titles of...'
Change 3456 on 2004/10/04 by rob 'Delete junk files...'
Change 3372 on 2004/10/04 by bill 'Branch V1...'
Not all of these changes need integrating to MAIN. Changelist 3372, as you recall, was the change that created the branch. To find out which changes do need integrating, we can use interchanges:
p4 interchanges //Ace/V1/... //Ace/MAIN/...
Change 3456 on 2004/10/04 by rob 'Delete junk files...'
Change 3459 on 2004/10/05 by pete 'Fix titles of...'
Change 3470 on 2004/10/05 by rob 'New threshold for...'
Whereas changes shows all changes to a branch, interchanges shows only the changes that are not accounted for in a target branch. (See "What interchanges really tells us" later in the chapter.) In this example we see that of the three changes made to V1 since it was created, none have been integrated to MAIN. Figure 4-11 shows these changes.
Figure 4-11: V1 changes not yet accounted for in MAIN
A very practical way to integrate changes between branches is incrementally—changelist by changelist, in order. This method preserves logical changes as they're propagated from branch to branch. It also keeps the problems of reconciling, resolving, and merging files to a minimum. It's a good technique to start off with, if you're not sure how to go about integating changes between branches.
Incremental integration is similar to branching from a point in time, using a changelist number instead of a date. Each time we integrate, we use interchanges to find out which changelist number to use.
Returning to the scenario in the previous example, here are the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Reconciling Structural Changes
Earlier we said that files can evolve independently in their own branches. This is completely true. Files can be added, deleted, moved, renamed, split, or combined in one branch without affecting any other branch. However, structural changes like these can't be resolved during integration. In fact, when you use the integrate command, Perforce simply matches donor and target files by name. The state of each donor file, whatever it is, is imposed upon the like-named target file. If the donor file was deleted, integrate deletes the target file. If the target file doesn't exist, it branches the donor file into it.
Matching donor and target files by name is normally quite effective for propagating structural changes. For example, say MAIN/readme#8 was branched into V1/readme#1 when you created the V1 branch . Since then, the V1/readme file has been renamed to V1/readme.txt and edited a couple of times.
Now, as you integrate from V1 to MAIN, here's what happens:
p4 integ //Ace/V1/... //Ace/MAIN/...
//Ace/MAIN/readme.txt#1 - branch/sync from //Ace/V1/readme.txt#3
//Ace/MAIN/readme#11 - delete from //Ace/V1/readme#3
So far, so good. Although Perforce gave you no choice in the matter, and nothing is left for you to resolve, the outcome is exactly what you wanted. When you submit your changelist, Perforce will delete MAIN/readme and branch V1/readme.txt into MAIN, effectively propagating both the content change and the structural change from V1 to MAIN.
But what if you wanted to merge the content change and ignore the structural change? What if the structural change had occured in MAIN instead of V1? Neither integrate nor resolve offers a way for you to handle these cases. However, as with files you're editing, there are several ways to reconcile structural changes. One way is to provide Perforce with some guidance as to how branches correspond structurally. This is where branch views come in.
To save you from having to jot down your frequently used donor and target filespecs on a cocktail napkin, Perforce lets you save them in named, reusable
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Arcana of Integration
(Heavens, it's all rather arcane, isn't it?)
It's worth noting that there are ways to reconcile branches so that changes can be integrated between them even when files have been split or combined in one of them. Reconciling split and combined files is a bit of a parlor trick, but that it can be done at all is a distinguishing feature of Perforce.
Consider this case: after V1 was branched from MAIN, MAIN's parse.cpp was split into two files, parse.cpp and eval.cpp. Meanwhile, change 3472 has been submitted in V1 which affects parse.cpp.
As is your custom, you integrate change 3472 from V1 to MAIN thus:
p4 integ -b V1toMAIN @3472
...
//Ace/MAIN/parse.cpp#5 - integrate from //Ace/V1/parse.cpp#2
...<