This chapter describes the tasks required to maintain groups of files in your depot. The following specific issues are addressed:
- Depot directory structure and how to best organize your repository
- Moving files and file changes among stream and project directories
- Identifying specific sets of files using either labels or changelists
This chapter focuses on maintaining a software codebase, but many of the tasks are relevant to managing other groups of files, such as a web site. For advice about best practices, see the white papers on the Perforce web site.
Organizing the depot
You can think of a depot as a top-level directory. Consider the following factors as you decide how to organize your depot:
- Type of content: create depots or mainline streams according to the nature of your projects and their relationships (for example, applications with multiple components developed on separate schedules).
- Release requirements: within a project, create streams for each release and merge changes between branches to control the introduction of features and bug fixes.
- Build management: use labels and changelists to control the file revisions that are built; use client specifications and views to ensure clean build areas.
A basic and logical way to organize the depot is to create one subdirectory (stream) for each project. For example, if your company is working on Jam, you might devote one stream to the release presently in development, another to already-released software, and perhaps one to your corporate web site. Your developers can modify their workspace views to map the files in their project, excluding other projects that are not of interest. For example, if Earl maintains the web site, his workspace view might look like this:
//JamCode/www/dev/... //earl-web-catalpa/www/development/... //JamCode/www/review/... //earl-web-catalpa/www/review/... //JamCode/www/live/... //earl-web-catalpa/www/live/...
And Gale, who’s working on Jam, sets up her workspace view as:
You can organize according to projects or according to the purpose of a stream. For example, to organize the depot according to projects, you can use a structure like the following:
//Acme/project1/main/ //Acme/project1/release 1.0/ //Acme/project1/release 1.1/
Or, to organize the depot according to the purpose of each stream, you can use a structure like the following:
//Acme/main/project1/ //Acme/main/project2/ //Acme/release1.0/project1/ //Acme/release1.0/project2/ //Acme/release2.0/project1/ //Acme/release2.0/project2/
Another approach is to create one depot for each project. Choose a structure that makes branching and merging as simple as possible, so that the history of your activities makes sense to you.
If you are branching from a stream that has no history, use the
p4 add command
to add files to it, then use
p4 copy to create the branched streams. For example, to
create the mainline structure shown in the previous section, perform the
Create a local folder your workspace for the mainline files; for example:
$ mkdir c:\p4clients\myworkspace\depot\main\
- Copy the files for Project1 and Project2 to the newly created folder.
Add the files to the depot:
$ p4 add //Acme/main/project1/... $ p4 add //Acme/main/project2/... $ p4 submit
Create release streams:
$ p4 copy //Acme/main/project1/... //Acme/release1.0/project1/... $ p4 copy //Acme/main/project2/... //Acme/release1.0/project2/... $ p4 submit
Now you can use the
p4 copy and
p4 merge commands to propagate changes
between main and release streams. (You can also seed a stream from another
stream using the
p4 integrate command, if there is a historical relationship
between the source and target that you need to preserve.)
A shortcut: p4 populate
If a target stream is completely empty (no files present, not even deleted files), Helix offers a command that automates the process of copying the files from an existing source stream submitting the associated changelist.
For example, instead of populating a
release1.0 branch with the following two
$ p4 copy //Acme/main/project1/... //Acme/release1.0/project1/... $ p4 submit
you can use the
p4 populate command to populate the stream:
$ p4 populate //Acme/main/project1/... //Acme/release1.0/project1/...
Branching is a method of maintaining the relationship between sets of related files. Branches can evolve separately from their ancestors and descendants, and you can propagate (merge) changes from one branch to another as desired.
To create a stream, use the
p4 merge command. The
command is also used to propagate changes between existing sets of files. For
details about merging changes, refer to Merge changes.
When to branch
Create a branch when two sets of files have different submission policies or need to evolve separately. For example:
Problem : the development group wants to submit code to the depot whenever their code changes, regardless of whether it compiles, but the release engineers don’t want code to be submitted until it’s been debugged, verified, and approved.
Solution: create a release branch by branching the development codeline. When the development codeline is ready, it is merged into the release codeline. Patches and bug fixes are made in the release code and merged back into the development code.
Problem: a company is writing a driver for a new multi-platform printer. The UNIX device driver is done and they are beginning work on an OS X driver, using the UNIX code as their starting point.
Solution: create an OS X branch from the existing UNIX code. These two codelines can evolve separately. If bugs are found in one codeline, fixes can be merged to the other.
One basic strategy is to develop code in a mainline stream and create streams for releases. Make release-specific bug fixes in the release streams and, if required, merge them back into the mainline stream.
To branch a stream, use the
p4 branch command. When you branch a stream,
Helix records the relationships between the branched files and their ancestors.
You can create branches using file specifications or branch specifications. For simple branches, use file specifications. For branches that are based on complex sets of files or to ensure that you have a record of the way you defined the branch, use branch specifications. Branch specifications can also be used in subsequent integrations. Branch specifications also can serve as a record of codeline policy.
Using branch specifications
To map a set of files from source to target, you can create a branch mapping
and use it as an argument when you issue the
p4 integrate command. To create
a branch mapping, issue the
p4 branch branchname command and specify the
desired mapping in the
View: field, with source files on the left and target
files on the right. Make sure that the target files and directories are in your
client view. Creating or altering a branch mapping has no effect on any files in
the depot or client workspace. The branch mapping merely maps source files to
To use the branch mapping to create a branch, issue the
p4 integrate -b
branchname command; then use
p4 submit to submit the target files to the
Branch specifications can contain multiple mappings and exclusionary mappings,
just as client views can. For example, the following branch mapping branches the
Jam 1.0 source code, excluding test scripts, from the main codeline:
Branch: jamgraph-1.0-dev2release View: //depot/dev/main/jamgraph/... //depot/release/jamgraph/1.0/... -//depot/dev/main/jamgraph/test/... //depot/release/jamgraph/1.0/test/... //depot/dev/main/bin/glut32.dll //depot/release/jamgraph/1.0/bin/glut32.dll
To create a branch using the preceding branch mapping, issue the following command:
$ p4 integrate -b jamgraph-1.0-dev2release
p4 submit to submit the changes.
To delete a branch mapping, issue the
p4 branch -d branchname command.
Deleting a branch mapping has no effect on existing files or branches.
As with workspace views, if a filename or path in a branch view contains spaces, make sure to quote the path:
//depot/dev/main/jamgraph/... "//depot/release/Jamgraph 1.0/..."
After you create branches, you might need to propagate changes between them. For
example, if you fix a bug in a release branch, you probably want to incorporate
the fix back into your main codeline. To propagate selected changes between
branched files, you use the
p4 merge and
p4 resolve commands, as follows:
- Issue the
p4 mergecommand to schedule the files for resolve.
p4 resolvecommand to propagate changes from the source files to the target files.
To propagate individual changes, edit the merge file or use a merge program. The changes are made to the target files in the client workspace.
- Submit the changelist containing the resolved files.
Example 28. Propagating changes between branched files
Bruno has fixed a bug in the release 2.2 branch of the Jam project and needs to integrate it back to the main codeline. From his home directory, Bruno types the following:
$ p4 merge //JamCode/release/jam/2.2/src/Jambase //JamCode/dev/jam/Jambase
He sees the following message:
//JamCode/dev/jam/Jambase#134 - merge from ////JamCode/release/jam/2.2/src/Jambase#9
The file has been scheduled for resolve. He types
p4 resolve, and the
standard merge dialog appears on his screen.
//JamCode/dev/jam/Jambase - merging depot/release/jam/2.2/src/Jambase#9 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. When he’s done, the result file overwrites the file in his workspace. The changelist containing the file must be submitted to the depot.
To run the
p4 merge or
p4 copy commands, you must have Helix
permission on the target files, and
read access on the source files. (See the
Helix Versioning Engine Administrator Guide: Fundamentals for information on Helix permissions.)
By default, a file that has been newly created in a client workspace by
p4 merge cannot be edited before being submitted. To edit a newly merged
file before submission, resolve it, then issue the
p4 edit command.
If the range of revisions being merged includes deleted revisions (for
example, a file was deleted from the depot, then re-added), you can specify how
deleted revisions are merged using the
-Di option. For details, refer to
the P4 Command Reference.
Merging specific file revisions
By default, the
p4 merge command merges all the revisions following the
last-merged source revision into the target. To avoid having to manually
delete unwanted revisions from the merge file while editing, you can specify a
range of revisions to be merged. The base file is the revision with the most
edits in common.
Example 29. Merging specific file revisions
Bruno has made two bug fixes to
//JamCode/dev/jam/scan.c in the development
stream, and Earl wants to merge the change into the release 1.0 branch.
scan.c has gone through several revisions since the fixes were
submitted, Earl knows that the bug fixes he wants were made to the 30th revision
scan.c. He types:
$ p4 integrate -b jamgraph-1.0-dev2release depot/release/jam/1.0/scan.c#30,30
The target file (
//depot/release/jam/1.0/scan.c) is given as an argument,
but the file revisions are applied to the source. When Earl runs
only the 30th revision of Bruno’s file is scheduled for resolve. That is, Earl
sees only the changes that Bruno made to
scan.c at revision 30.
Re-merging and re-resolving files
After a revision of a source file has been merged into a target, that
revision is skipped in subsequent merges to the same target. To force the
merging of already-merged files, specify the
-f option when you issue
p4 merge command.
A target that has been resolved but not submitted can be resolved again by
-f option to
p4 resolve. When you re-resolve a file,
yours is the new client file, the result of the original resolve.
Reporting branches and merges
The reporting commands below provide useful information about the status of
files being branched and merged. Note the use of the preview option (
for reporting purposes.
|To display this information||Use this command|
Preview of the results of an integration
Files that are scheduled for resolve
Files that have been resolved but not yet submitted.
List of branch specifications
The integration history of the specified files.
The revision histories of the specified files, including the integration histories of files from which the specified files were branched.