PERFORCE is a source management system, which means it facilitates the controlled sharing of source and related files among many people. Despite the name, files can be of any types, not just source files.
PERFORCE's source management encompasses version control and some "software configuration management" (SCM) functions. Version control means tracking each revision and variant of each file managed by the system. SCM means tracking how the source files have been arranged and used collectively. For example, revision control would track all the bug fixes to a single file, while SCM would track which versions of what files were part of a release.
Other functions which are sometimes considered part of SCM are build management, automated testing, defect tracking, life cycle management, and release management. PERFORCE can assist in defect tracking, life cycle management, and release management, and when necessary it can work with third-party tools that provide full support for these functions. PERFORCE has a companion freeware build tool called "Jam - Make(1) Redux" that shares PERFORCE's high-performance, low-overhead approach.
PERFORCE has a client/server architecture. A PERFORCE client is a workspace on a UNIX, Windows, or Macintosh host. A client workspace is a collection of source files managed by PERFORCE. The PERFORCE server is the master repository (here called the "depot") and metadata on a central UNIX or Windows/NT host. All of the client workspaces access this same, central server.
The only interaction PERFORCE requires between the client and server hosts is the ability of the client program to talk via TCP/IP to the server program. PERFORCE does not require the client host to have network filesystem access to the server host.
The PERFORCE client workspaces may be distributed around a local area network, wide area network, dialup network, or any combination of these. There can also be PERFORCE client workspaces on the same host as the server.
PERFORCE has a single program called p4 that users invoke to manage their client workspaces. This program talks via TCP/IP to the PERFORCE server, mediating the interaction between the managed files in the client workspace and the master repository and metadata on the server host. The p4 program is invoked from the command line and is installed someplace where all users can access it (such as /usr/local/bin on UNIX).
The p4 client program may run other programs on the client host (such as the user's editor or a diff program), but otherwise it is solely responsible for maintaining a client workspace.
PERFORCE has a single program called p4d that manages the repository and metadata on the server. The p4d program has a built-in file librarian and database.
The p4d program is a server that waits on a well-known TCP/IP port for a connection from the client program. On UNIX, p4d is a server in the daemon sense: on receipt of a connection it forks off a copy of itself, and returns waiting. The forked copy handles the user's request and exits when the client program exits. On Windows/NT, p4d is single-threaded: it handles the request itself and then returns waiting.
PERFORCE users never access the server directly. All interaction is via the p4 client program.
A PERFORCE client workspace is a collection of source files managed by PERFORCE on a host. Each such collection is given a name which identifies the client workspace to the PERFORCE server. The name is by default simply the host's name but that can be overridden by the environment variable $P4CLIENT.
There can be more than one PERFORCE client workspace on a client host, but client workspaces with names other than the host's name must be accessed with the $P4CLIENT variable set.
All files within a PERFORCE client workspace share a common root directory, called the client root. In the degenerate case, the client root can be the host's root (/ on UNIX), but in practice the client root is the lowest level directory under which the managed source files will sit. On Windows/NT, the PERFORCE client workspace must reside entirely on a single logical drive, as there is no universal root directory.
PERFORCE manages the files in a client workspace in a few direct ways. It creates, updates, or deletes the files when the user requests PERFORCE to synchronize the client workspace with the depot; it turns on write permission when the user requests to edit a file; and it turns off write permission and submits updated versions back to the depot when the user is finished editing the file.
The entire PERFORCE client workspace state is tracked by the PERFORCE server. The server knows what files a client workspace has, where they are, and which files have write permission turned on.
PERFORCE's management of a client workspace requires a certain amount of cooperation from the user. Since client files are just plain files with write permission turned off, willfull users can circumvent the system by turning on write permission, directly deleting or renaming files, or otherwise modifying the file tree supposedly under PERFORCE's control. PERFORCE counters this with two measures: first, PERFORCE has explicit commands to verify that the client workspace state is in accord with the server's recording of that state; second, PERFORCE tries to make using PERFORCE at least as easy as circumventing it. For example: to make a temporary modification to a file, it is easier to use PERFORCE than it is to copy and restore the file manually.
Files not managed by PERFORCE may also be under a client's root, and they are largely ignored by PERFORCE. For example, PERFORCE may manage the source files in a client workspace, while the workspace also holds compiled objects, libraries, executables, as well as a developer's temporary files.
In addition to accessing the the client files, the p4 client program sometimes creates temporary files on the client host. Otherwise, PERFORCE neither creates nor uses any files on the client host.
The PERFORCE server comprises all versions of all files ever submitted to the server (the "depot"), metadata about those files, metadata about the current state of all client workspaces, and metadata about the some of the past state of client workspaces. (The latter is saved at the explicit request of the user.)
Each source file stored in the PERFORCE depot has an associated revision number. When the file is first added this number is 1, and PERFORCE assigns sequential numbers to each updated revision of the same file submitted to the depot. The highest numbered revision of each file is called the head (or "tip") revision. Unless the user requests a specific revision number, when a user asks for a file they get the head revision.
Each revision of a source file in the PERFORCE depot has an associated action. The action of revision number 1 is "add" and of subsequent revisions is normally "edit". But a revision may also have an action of "delete", which means that the user that submitted a new revision in order to delete the file. For the most part, when users ask for a revision of a file that has an action of "delete", it appears as if the file does not exist. A user may subsequently add the file again, in which case the new revision has the next revision number and the action is "add".
PERFORCE handles variants of source files, where the evolution of a file is not along a single line, with a mechanism called Inter-file branchingTM. This mechanism allows the revision numbers to remain simple, sequential integers, while a user-selected part of the file name selects the variant. This branching mechanism is discussed below.
PERFORCE supports files with any content, but it distinguishes several types of files:
PERFORCE associates a type with each revision of each file. For example, it is possible to have one revision be a text file and the next be binary.
PERFORCE allows users to refer to files in one of two ways: using the name of the file in the client workspace, and using the name of the file in the depot. When using the name of the file in the client workspace, the user may give the name in either "local" or "PERFORCE" syntax.
Local syntax is simply the native name on the client host, as would be used by any other commands. This name may be an absolute path or relative to the current directory, although it can only contain relative components at the beginning of the file name (i.e. it doesn't allow sub/dir/./here/foo.c). On NT, either backward or forward slashes may be used.
PERFORCE syntax is a canonical syntax that doesn't vary across operating systems. It begins with two slashes and the client name, followed by the path name of the file relative to the client root directory. The components of the path name are separated by slashes. For example:
//weasel/rcs5.6.1/src/ci.c
If the client "weasel" had a root directory of /usr/local/src, then the above name would refer to weasel's /usr/local/src/rcs5.6.1/src/ci.c. Such a reference is only available while on the client named "weasel". It is not possible refer directly to files on other clients.
When using the name of the file in the depot, PERFORCE syntax is used with the client workspace name replaced by the repository's name, "depot". (That is to say, there is one repository, it's name is "depot", and there can be no client workspace named "depot.") For example:
//depot/main/rcs5.6.1/src/ci.c
The relationship of the name of the file in the client workspace to the name of the file on the depot is determined by the client view, which will be discussed shortly.
Wherever PERFORCE allows the user to refer to files, the user may use wildcards. There are three wildcards: "*", "...", and "%d" (where d is a digit). The "*" wildcard matches anything except slashes. The "..." wildcard matches anything including slashes. The "%d" wildcards are like the "*" wildcards, but can be used for parametric substitution in views (discussed shortly).
PERFORCE's wildcards may be mixed with both local or PERFORCE syntax. For example,
J* Files in the current directory starting with J. */Makefile All Makefiles in current subdirectories. ... All files under the current directory. .../*.c All such files ending in .c. /usr/... All files under /usr. (UNIX) d:\src\... All files under \src\ on drive d: (NT) //weasel/... All files on client weasel. //depot/... All files in the depot.
PERFORCE permits only one "..." in a name; any number of "*"s may be used. The "*" wildcard is special to all UNIX and most other command shells. Normally, the shell will match "*" against the contents of the client directory; to have PERFORCE match the "*" against the contents of the depot, it must be escaped, usually with quotes or a backslash. Most command shells don't interfere with the other two wildcards.
Because of PERFORCE's naming conventions, some characters cannot be used in file names: space, unprintable characters, and the wildcards "*", "...", and "%".
The relationship of the name of a file in the client workspace and the name of the file in the depot is specified with the client view. A view comprises one or more mappings, each of which gives a depot file name on the left and a client file name on the right, both in PERFORCE syntax. The client name in the client file name must match the actual client name. For example:
//depot/rcs.7/src/ci.c //weasel/rcs.7/src/ci.c
These file names may use wildcards, as long as the wildcards are balanced between the left and right hand sides. For example:
//depot/rcs.7/src/* //weasel/rcs.7/src/*
There can be multiple "*"'s: the first "*" on the left corresponds to the first on the right, and so forth. In addition to the "..." and "*" wildcards, the "%d" wildcards may be used. These allow for the name to be rearranged during mapping:
//depot/rcs.7/%2/%1 //weasel/rcs.7/%1/%2
Multiple mappings may be present in a view.
//depot/rcs.7/src/* //weasel/rcs.7/src/* //depot/rcs.7/doc/* //weasel/rcs.7/doc/*
If there is a conflict in the mappings, the later ones take precedence over earlier ones:
//depot/rcs.7/... //weasel/rcs.7/... //depot/rcs.7/doc/* //weasel/rcs.7.doc/*
In this example, everything from the doc subdirectory goes into a special rcs.7.doc directory in the client workspace; otherwise the client workspace and the depot have the same tree strucutre.
If a view is constructed such that a name does not map the same way in both directions, PERFORCE treats the name as if it does not map at all. For example:
//depot/rcs.7/... //weasel/rcs.7/... //depot/nowhere/* //weasel/rcs.7/doc/*
The file //depot/rcs.7/doc/man.ps would map (via the first line) to //weasel/rcs.7/doc/man.ps and then back (via the higher precedence second line) to //depot/nowhere/man.ps. Because the original and final names don't match, PERFORCE would not map this name at all.
Creating or changing a client view does nothing to affect the client workspace until the user requests that the client workspace be synchronised with the depot. At that time, all depot files that can be mapped through the client view are transferred to the client workspace, and any files previously in the client workspace that no longer map are deleted.
Because the client view and the actual client workspace contents are only synchronized on explicit request, referring to a file in the client workspace can lead ambiguously to two different files in the depot: the one that corresponds to what the client workspace currently has, and the one that currently maps through the view. Except for special cases, such as adding an entirely new file and the synchronize operation itself, PERFORCE assumes that a reference to a client file means the file the client workspace has, not the one that may map through the view.
Client files are normally write protected to remind the user that the files should not be modified without PERFORCE's consent. The user informs PERFORCE by stating the action to "open" the file: add, delete, or edit. In addition to turning on write permission for the client file, PERFORCE also records at what revision the file was opened. Any number of client workspaces may have the same file opened, but any given file may be opened only once in each client workspace.
A client file remains opened until it is submitted as the next revision of the corresponding depot file or is explicitly reverted. If it is reverted, PERFORCE replaces the modified version with the revision of the file before the modifications took place.
Before a file can be submitted from the client workspace to the depot, it must be locked. Only one client workspace may lock any given file at a time. PERFORCE allows the lock to be made anytime from when the file is opened until when the file is submitted. By default, if files are not locked at submission time, PERFORCE will automatically attempt to lock them.
In some cases, a user may modify an opened file that doesn't correspond to the head revision in the depot. This can happen if the user opens a non-head revision or if the user opens the head revision but another user submits a new revision first.
In these cases the user is required to merge the head revision before submitting. PERFORCE has a simple file merge tool that steps users through the complications of merging the various revisions of the file.
PERFORCE treats multiple open files submitted at the same time as a single transaction, called a "change". Each change is given a sequential number and has an associated description, provided by the user when the change is created.
After the change is submitted, the new revisions of the files have no special relationship to each other, except that they share a common description and change number. For some reporting commands, the change number can be used as a handle to refer to the collection of file revisions in the change.
A change's number and description can be created at any time. Before the change is submitted, it is said to be pending. A client workspace may have any number of pending changes at a time. At any time opened files may be associated with an pending change or moved from one pending change to another. Once a change is submitted, it becomes a permanent, immutable part of the server metadata.
The change number is assigned when the change is created. While the change is pending, it is possible for other, higher-numbered changes to be submitted first. If that happens, the pending change will be renumbered at submission to ensure that the numbers for submitted changes always increase with time.
If an open file is not associated with any pending change, it is considered to be in the default change. PERFORCE assigns the default change a number and gathers a description at submit time.
The PERFORCE depot contains all versions of all files ever submitted to the server. PERFORCE can label important configurations of those files for later reference. A label is essentially a list of the files that are in the client workspace, along with their revision numbers. A user can subsequently reference a label whenever specifying the revision of a file.
Like a client workspace, a label has its own view and is synchronized explicitly by the user. Unlike a client workspace, when a label is synchronized it is with respect to the current client workspace, not to the depot, and no file transfers take place. A label can be resynchronized with the same or different client workspaces any number of times.
PERFORCE handles variants of source files, where the evolution of a file is not along a single line, with a mechanism called Inter-file branchingTM. Most SCM systems handle variants by having a hierarchical revision number, such as 1.3.2.1.1.2. Inter-file branching allows the revision numbers to remain simple, sequential integers, while a user-selected part of the file's name selects the variant. In this scheme, a branch of a file is made by copying the file to a new file with another name, typically with a different directory component. Each file may then evolve with independent revision numbers.
PERFORCE remembers when a file is branched or updated from another file. Specifically, it remembers which revisions have been integrated from one file into another. It uses this information to determine what revisions have yet to be integrated, so that PERFORCE can orchestrate integrating updates from the original to the branched file.
A branched file is related to the original file by its name, and the user specifies this relationship with a view. A branch view is much like a client view, except that the name on the right side is also a depot file name. For example:
//depot/mainline/rcs/src/... //depot/rcs/r7/src/...
This example says that the files under //depot/rcs/r7/src are to be created and updated from the similarly named files under //depot/mainline/rcs/src. Because the branch view is used to create the branched files, the user must create the branch view first.
Once files are related by a branch view, that view can be used to create and subsequently update the target files in the view. If a source file in a view doesn't have a corresponding target file, the target file will be created; if the target file does exist, it will be merged; if the target file exists but there is no corresponding source file, the target file will be deleted.
Integration happens in the context of a normal change: the PERFORCE integration command opens the target files for the appropriate action, which is not committed until the change is submitted. The PERFORCE integration command uses variants of the normal user actions: instead of "add" it uses "branch"; instead of "edit" it uses "integrate". The distinction is largely for reporting: "branch" indicates that the whole text of the file was copied from another file; "integrate" indicates that the file took on deltas from another file.
If the file is opened for "integrate", the changes from the source file will have to be resolved with the target file. Usually PERFORCE can perform a three-way file merge and let the user edit the result. If either file is binary, however, a three-way merge is not possible and the user must simply choose either to take the source file whole or leave the target file as-is.
The "integrate" action leaves the file read-only, to remind the user that the change should not mix integration with miscellaneous modifications. Keeping integrations "pure" allows PERFORCE to avoid integrating the change back to the source file.
See Chapter 5, "Branching and Integration," for a deeper discussion about branching.
All file-related PERFORCE client commands can limit their actions to the files named on the command line. If no file name is given, the action is unlimited and includes all files in the depot or in the client workspace. The file name can be in any of the three formats: local syntax for the client file, PERFORCE syntax for the client file, or PERFORCE syntax for the depot file.
The commands that permit file names on the command line all allow those file names to include the wildcards "..." and "*". These wildcards are matched against the depot contents to produce the list of affected files.
Normally, the user's command shell will attempt to expand an unquoted "*". If the "*" is to be matched against the local client workspace, that it fine (though obviously only local syntax can be used). If the "*" is to be matched against the depot contents, it usually must be quoted. The "..." wildcard is normally not bothered by most command shells.
Some file-related PERFORCE client commands can also limit their actions to specific file revisions. A revision specification is tacked onto the end of the file name, and is one of seven varieties:
In all cases, if a file doesn't exist at the given revision number it appears as if the file doesn't exist at all. Thus using a label to refer to a file that isn't in the label is indistinguishable from referring to file that doesn't exist at all.
If no revision specification is given, the default is usually #head.
A revision specification can be given without a file name. This limits the command's action to the specified revision of all files in the depot or in the client's workspace. Thus #head refers to the head revision of all files in the depot, and @label refers to the revisions of all files in the named label.
A few PERFORCE client commands can limit their actions to a range of revision numbers, rather than just a single revision. A revision range is two revision specifications, separated by a ",". If only a single revision is given where a revision range is expected, the named revision specifies the end of the range and the beginning is left at 1.
If no revision number or range is given where a revision range is expected, the default is all revisions.
PERFORCE provides optional support for software defect tracking through PERFORCE jobs. A job is a generic term for a defect report, system improvement request, change order, etc, and it describes work that is intended to be performed on the files in the depot. A job consists of a job name, a status, an owner, and a description. The job's name can either be provided by the user or generated by PERFORCE.
A job represents intended work, while a change is work actually done. Jobs are related to changes by fixes. Fixes make up a many-to-many mapping between jobs and changes. For example, a single enhancement (job) may require many changes to bring it about, while a single maintenance change may fix more than one bug (job).
PERFORCE's support for jobs can be used as a simple defect tracking system by itself, but it is mainly intended to mirror essential information from an external defect tracking system. A job stores the information necessary to provide to the user context for changes that are being submitted. However, jobs do not manage all the sundry information normally used by full-scale defect tracking systems, such as customer name, reporting engineer, priority, etc.
PERFORCE tracks the name of each user who accesses the depot. Associated with each user is the time that he last accessed the server, his full name and email address. Defaults are created the first time the user accesses the depot, but users can edit and replace these. Also associated with each user can be the names of files whose changes the user wishes to review. This is discussed in Chapter 6, "Change Review."
PERFORCE includes provisions for automating change review, where users can receive email when files they are interested in undergo changes. Each user can subscribe to a list of files for review, and PERFORCE can generate both a list of unreviewed changes and a list of users subscribed to the files affected by each change. The actual change review automation is carried out by an auxilliary daemon that polls the PERFORCE depot periodically.
Typically, the change review daemon sends email to the subscribed users, including a description of the change made. A similar daemon could be used to upload fix data automatically to an external defect tracking system.
PERFORCE does not record permissions or store access control lists for individual files in the depot, and PERFORCE does not authenticate its clients or users. Instead, PERFORCE restricts access to the depot using a protections table.
By default, there is no protections table and any user whose PERFORCE client program can connect to the PERFORCE server is able to use any PERFORCE command against any files in the depot. Once the protections table is created, only listed users on listed hosts can access specific files in the depot. Each line in the protections table identifies a user, a client host, an access mode, and a depot file path. Users, hosts, and files can all make use of wildcards. The access modes are: list, read, write, review, and superuser access. In this list, each access mode includes all the priviledges of earlier modes.
List access allows the user to view metadata but not the contents of files; without list access, the user cannot even discover if files are present. Read access allows the user to create clients that can download the contents of files. Write access allows users to make changes to files in the depot. Review access is read access, plus the special permission to run the command that the change review daemon uses. Superuser access is write access plus the ability to edit the protections table.
Because access can be granted based on path name, it is possible to make arrangements not possible with normal permissions schemes. For example, it is possible to permit a certain user to add or edit only files named "Makefile" throughout the source tree.
Hosts are identified by their TCP/IP address (dotted quad numeric address-not host name) and can provide for security against unauthorized access. Since PERFORCE's security is based on IP addresses, it is as secure as UNIX ".rhosts" support. User names are not authenticated and so the user names in the protections table merely offer a form of safety, preventing inadvertant access.
The distinction between a host and a PERFORCE client is important: hosts are identified by their TCP/IP address, while the client's name, like the user name, is not authenticated at all. PERFORCE's protections offer security against unauthorized hosts, not against malicious users on authorized hosts.