Add Scott Long's "Perforce in FreeBSD Development" article (aka "p4
primer").
This commit is contained in:
parent
5b46b122fe
commit
a259cd8b30
Notes:
svn2git
2020-12-08 03:00:23 +00:00
svn path=/head/; revision=26410
2 changed files with 831 additions and 0 deletions
en_US.ISO8859-1/articles/p4-primer
19
en_US.ISO8859-1/articles/p4-primer/Makefile
Normal file
19
en_US.ISO8859-1/articles/p4-primer/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
# Perforce in FreeBSD Development article.
|
||||
|
||||
DOC?= article
|
||||
|
||||
FORMATS?= html
|
||||
WITH_ARTICLE_TOC?= YES
|
||||
|
||||
INSTALL_COMPRESSED?= gz
|
||||
INSTALL_ONLY_COMPRESSED?=
|
||||
|
||||
SRCS= article.sgml
|
||||
|
||||
URL_RELPREFIX?= ../../../..
|
||||
DOC_PREFIX?= ${.CURDIR}/../../..
|
||||
|
||||
.include "${DOC_PREFIX}/share/mk/doc.project.mk"
|
812
en_US.ISO8859-1/articles/p4-primer/article.sgml
Normal file
812
en_US.ISO8859-1/articles/p4-primer/article.sgml
Normal file
|
@ -0,0 +1,812 @@
|
|||
<!--
|
||||
The FreeBSD Documentation Project
|
||||
-->
|
||||
|
||||
<!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
|
||||
<!ENTITY % articles.ent PUBLIC "-//FreeBSD//ENTITIES DocBook FreeBSD Articles Entity Set//EN">
|
||||
%articles.ent;
|
||||
]>
|
||||
|
||||
<article>
|
||||
<title>Perforce in &os; Development</title>
|
||||
|
||||
<articleinfo>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<firstname>Scott</firstname>
|
||||
<surname>Long</surname>
|
||||
<affiliation>
|
||||
<address><email>scottl@FreeBSD.org</email>
|
||||
</address>
|
||||
</affiliation>
|
||||
</author>
|
||||
</authorgroup>
|
||||
|
||||
<pubdate>$FreeBSD$</pubdate>
|
||||
|
||||
<legalnotice id="trademarks" role="trademarks">
|
||||
&tm-attrib.freebsd;
|
||||
&tm-attrib.cvsup;
|
||||
&tm-attrib.general;
|
||||
</legalnotice>
|
||||
</articleinfo>
|
||||
|
||||
<sect1 id="intro">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>The &os; project uses the <application>Perforce</application>
|
||||
version control system to manage experimental projects that are
|
||||
not ready for the main CVS repository.</para>
|
||||
|
||||
<sect2 id="resources">
|
||||
<title>Availability, Documentation, and Resources</title>
|
||||
|
||||
<para>While <application>Perforce</application> is a commercial
|
||||
product, the client software for interacting with the server is
|
||||
freely available from Perforce. Binary versions of the software
|
||||
for most OS's, including &os;, are available for downloading
|
||||
from the <application>Perforce</application> web site at <ulink
|
||||
url="http://www.perforce.com/perforce/loadprog.html"></ulink>.</para>
|
||||
|
||||
<para>While there is a GUI client available, most people use the
|
||||
command line application called <command>p4</command>. This
|
||||
document is written from the point of view of using this
|
||||
command.</para>
|
||||
|
||||
<para>Detailed documentation is available online at <ulink
|
||||
url="http://www.perforce.com/perforce/technical.html"></ulink>.</para>
|
||||
|
||||
<para>Reading the <quote>Perforce User's Guide</quote> and
|
||||
<quote>Perforce Command Reference</quote> is highly recommended.
|
||||
The <application>p4</application> application also contains an
|
||||
extensive amount of online help accessible via the <command>p4
|
||||
help</command> command.</para>
|
||||
|
||||
<para>The &os; <application>Perforce</application> server is
|
||||
hosted on <hostid role="fqdn">perforce.freebsd.org</hostid>,
|
||||
port <literal>1666</literal>. The repository is browsable
|
||||
online at <ulink url="http://perforce.freebsd.org"></ulink>.
|
||||
Some portions of the repository are also automatically exported
|
||||
to a number of <application>CVSup</application> servers.</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="start">
|
||||
<title>Getting Started</title>
|
||||
|
||||
<para>The first step to using <application>Perforce</application> is
|
||||
to obtain an account on the server. If you already have a <hostid
|
||||
role="domainname">FreeBSD.org</hostid> account, log into <hostid
|
||||
role="hostname">freefall</hostid>, run the following command, and
|
||||
enter a password that is not the same as your &os; login or any
|
||||
other SSH passphrase:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>/usr/local/bin/p4newuser</userinput></screen>
|
||||
|
||||
<para>Of course if you do not have a <hostid
|
||||
role="domainname">FreeBSD.org</hostid> account, you will need to
|
||||
coordinate with your sponsor.</para>
|
||||
|
||||
<para>The next step is to set the environment variables that
|
||||
<command>p4</command> needs, and verify that it can connect to the
|
||||
server. The <envar>P4PORT</envar> variable is required to be set
|
||||
for all operations, and specifies the appropriate
|
||||
<application>Perforce</application> server to talk to. For the
|
||||
&os; project, set it like so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>export P4PORT=perforce.freebsd.org:1666</userinput></screen>
|
||||
|
||||
<note>
|
||||
<para>Users with shell access on the <hostid
|
||||
role="domainname">FreeBSD.org</hostid> cluster may wish to tunnel
|
||||
the <application>Perforce</application> client-server protocol via
|
||||
an SSH tunnel, in which case the above string should be set to
|
||||
<literal>localhost</literal>.</para>
|
||||
</note>
|
||||
|
||||
<para>The &os; server also requires that the <envar>P4USER</envar>
|
||||
and <envar>P4PASSWD</envar> variables be set. Use the username
|
||||
and password from above, like so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>export P4USER=<replaceable>username</replaceable></userinput>
|
||||
&prompt.user; <userinput>export P4PASSWD=<replaceable>password</replaceable></userinput></screen>
|
||||
|
||||
<para>Test that this works by running the following command:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 info</userinput></screen>
|
||||
|
||||
<para>This should return a list of information about the server. If
|
||||
it does not, check that you have the <envar>P4PORT</envar>
|
||||
variable set correctly.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="clients">
|
||||
<title>Clients</title>
|
||||
|
||||
<para><application>Perforce</application> provides access to the
|
||||
repository and tracks state on a per-client basis. In
|
||||
<application>Perforce</application> terms, a client is a
|
||||
specification that maps files and directories from the repository
|
||||
to the local machine. Each user can have multiple clients, and
|
||||
each client can access different or overlapping parts of the
|
||||
repository. The client also specifies the root directory of the
|
||||
file tree that it maps, and it specifies the machine that the tree
|
||||
lives on. Thus, working on multiple machines requires that
|
||||
multiple clients be used.</para>
|
||||
|
||||
<para>Clients may be accessed via the <command>p4 client</command>
|
||||
command. Running this command with no arguments will bring up a
|
||||
client template in an editor, allowing you to create a new client
|
||||
for your work. The important fields in this template are
|
||||
explained below:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>Client:</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This is the name of the client spec. It can be anything
|
||||
you want, but it must be unique within the
|
||||
<application>Perforce</application> server. A naming
|
||||
convention that is commonly used is
|
||||
<literal><replaceable>username</replaceable>_<replaceable>machinename</replaceable></literal>,
|
||||
which makes it easy to identify clients when browsing them.
|
||||
A default name will be filled in that is just the machine
|
||||
name.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>Description:</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This can contain a simple text description to help
|
||||
identify the client.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>Root:</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This is the local directory that will serve as the root
|
||||
directory of all the files in the client mapping. This should
|
||||
be a unique location in your filesystem that does not overlap
|
||||
with other files or <application>Perforce</application>
|
||||
clients.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>Options:</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>Most of the default options are fine, though it is
|
||||
usually a good idea to make sure that the
|
||||
<option>compress</option> and <option>rmdir</option> options
|
||||
are present and do not have a <literal>no</literal> prefix on
|
||||
them. Details about each option are in the
|
||||
<application>Perforce</application> docs.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>LineEnd:</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This handles CR-LF conversions and should be left to the
|
||||
default unless you have special needs for it.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>View:</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This is where the server-to-local file mappings go. The
|
||||
default is</para>
|
||||
|
||||
<programlisting>//depot/... //<replaceable>client</replaceable>/...</programlisting>
|
||||
|
||||
<para>This will map the entire
|
||||
<application>Perforce</application> repository to the
|
||||
<filename role="directory">Root</filename> directory of your
|
||||
client. <emphasis>DO NOT USE THIS DEFAULT!</emphasis> The
|
||||
&os; repo is huge, and trying to map and sync it all will
|
||||
take an enormous amount of resources. Instead, only map the
|
||||
section of the repo that you intend to work on. For
|
||||
example, there is the smpng project tree at <filename
|
||||
role="directory">//depot/projects/smpng</filename>. A
|
||||
mapping for this might look like:</para>
|
||||
|
||||
<programlisting>//depot/projects/smpng/... //<replaceable>client</replaceable>/...</programlisting>
|
||||
|
||||
<para>The <literal>...</literal> should taken literally. It
|
||||
is a <application>Perforce</application> idiom for saying
|
||||
<quote>this directory and all files and directories below
|
||||
it.</quote></para>
|
||||
|
||||
<para>A View can contain multiple mappings. Let's say you
|
||||
want to map in both the SMPng tree and the NFS tree. Your
|
||||
View might look like:</para>
|
||||
|
||||
<programlisting>//depot/projects/smpng/... //<replaceable>client</replaceable>/smpng/...
|
||||
//depot/projects/nfs/... //<replaceable>client</replaceable>/nfs/...</programlisting>
|
||||
|
||||
<para>Remember that the <replaceable>client</replaceable> is
|
||||
the name of the client that was specified in the
|
||||
<literal>Client</literal> section, but in the
|
||||
<literal>View</literal> it also resolves to the directory
|
||||
that was specified in the <literal>Root</literal>
|
||||
section.</para>
|
||||
|
||||
<para>Also note that the same file or directory cannot be
|
||||
mapped multiple times in a single view. The following is
|
||||
illegal and will produce undefined results:</para>
|
||||
|
||||
<programlisting>//depot/projects/smpng/... //<replaceable>client</replaceable>/smpng-foo/...
|
||||
//depot/projects/smpng/... //<replaceable>client</replaceable>/smpng-bar/...</programlisting>
|
||||
|
||||
<para>Views are a tricky part of the learning experience with
|
||||
<application>Perforce</application>, so do not be afraid to
|
||||
ask questions.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>Existing clients can be listed via the <command>p4
|
||||
clients</command> command. They can be viewed without being
|
||||
modified via the <command>p4 client -o
|
||||
<replaceable>clientname</replaceable></command> command.
|
||||
|
||||
<para>Whenever you are interacting with files in
|
||||
<application>Perforce</application>, the <envar>P4CLIENT</envar>
|
||||
environment variable must be set to the name of the client that
|
||||
you are using, like so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>export P4CLIENT=<replaceable>myclientname</replaceable></userinput></screen>
|
||||
|
||||
<para>Note that client mappings in the repository are not exclusive;
|
||||
multiple clients can map in the same part of the repository. This
|
||||
allows multiple people to access and modify the same parts of the
|
||||
repository, allowing a team of people to work together on the same
|
||||
code.</para>
|
||||
|
||||
<sect1 id="syncing">
|
||||
<title>Syncing</title>
|
||||
|
||||
<para>Once you have a client specification defined and the
|
||||
<envar>P4CLIENT</envar> variable set, the next step is to pull the
|
||||
files for that client down to your local machine. This is done
|
||||
with the <command>p4 sync</command> command, which instructs
|
||||
<application>Perforce</application> to synchronize the local files
|
||||
in your client with the repository. The first time it runs, it
|
||||
will download all of the files. Subsequent runs will only
|
||||
download files that have changed since the previous run. This
|
||||
allows you to stay in sync with others whom you might be working
|
||||
with.</para>
|
||||
|
||||
<para>Sync operations only work on files that the
|
||||
<application>Perforce</application> server knows has changed. If
|
||||
you change or delete a file locally without informing the server,
|
||||
doing a sync will not bring it back. However, doing a <command>p4
|
||||
sync -f</command> will unconditionally sync all files, regardless
|
||||
of their state. This is useful for resolving problems where you
|
||||
think that your tree might be corrupt.</para>
|
||||
|
||||
<para>You can sync a subset of your tree or client by specifying a
|
||||
relative path to the sync command. For example, to only sync the
|
||||
<filename role="directory">ufs</filename> directory of the
|
||||
<literal>smpng</literal> project, you might do the
|
||||
following:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>cd <replaceable>projectroot</replaceable>/smpng</userinput>
|
||||
&prompt.user; <userinput>p4 sync src/sys/ufs/...</userinput></screen>
|
||||
|
||||
<para>Specifying a local relative path works for many other
|
||||
<command>p4</command> commands.</para>
|
||||
|
||||
<sect1 id="branches">
|
||||
<title>Branches</title>
|
||||
|
||||
<para>One of the strongest features of
|
||||
<application>Perforce</application> is branching. Branches are
|
||||
very cheap to create, and moving changes between related branches
|
||||
is very easy (as will be explained later). Branches also allow
|
||||
you to do very experimental work in a sandbox-like environment,
|
||||
without having to worry about colliding with others or
|
||||
destabilizing the main tree. They also provide insulation against
|
||||
mistakes while learning the <application>Perforce</application>
|
||||
system. With all of these benefits, it makes sense for each
|
||||
project to have its own branch, and we strongly encourage that
|
||||
with &os;. Frequent submits of changes to the server are also
|
||||
encouraged.</para>
|
||||
|
||||
<para>The <application>Perforce</application> repository (the
|
||||
<quote>depot</quote>) is a single flat tree. Every file, whether
|
||||
a unique creation or a derivative from a branch, is accessible via
|
||||
a simple path under the server <filename
|
||||
role="directory">//depot</filename> directory. When you create a
|
||||
branch, all you are doing is creating a new path under the
|
||||
<filename role="directory">//depot</filename>. This is in sharp
|
||||
contrast to systems like CVS, where each branch lives in the same
|
||||
path as its parent. With <application>Perforce</application>, the
|
||||
server tracks the relationship between the files in the parent and
|
||||
child, but the files themselves live under their own paths.</para>
|
||||
|
||||
<para>The first step to creating a branch is to create a branch
|
||||
specification. This is similar to a client specification, but is
|
||||
created via the command <command>p4 branch
|
||||
<replaceable>branchname</replaceable></command>.</para>
|
||||
|
||||
<para>The following important fields are explained:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>Branch</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>The name of the branch. It can be any name, but must be
|
||||
unique within the repository. The common convention in &os;
|
||||
is to use
|
||||
<replaceable>username</replaceable>_<replaceable>projectname</replaceable>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>Description</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This can hold a simple text description to describe the
|
||||
branch.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>View</literal></term>
|
||||
|
||||
<listitem>
|
||||
<para>This is the branch mapping. Instead of mapping from the
|
||||
depot to the local machine like a client map, it maps between
|
||||
the branch parent and branch child in the depot. For example,
|
||||
you might want to create a branch of the smpng project. The
|
||||
mapping might look like:</para>
|
||||
|
||||
<programlisting>//depot/projects/smpng/... //depot/projects/my-super-smpng/...</programlisting>
|
||||
|
||||
<para>Or, you might want to create a brand new branch off of
|
||||
the stock &os; sources:</para>
|
||||
|
||||
<programlisting>//depot/vendor/freebsd/... //depot/projects/my-new-project/...</programlisting>
|
||||
|
||||
<para>This will map the &os; HEAD tree to your new
|
||||
branch.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>Creating the branch spec only saves the spec itself in the
|
||||
server, it does not modify the depot or change any files. The
|
||||
directory that you specified in the branch is empty on the server
|
||||
until you populate it.</para>
|
||||
|
||||
<para>To populate your branch, first edit your client with the
|
||||
<command>p4 client</command> command and make sure that the branch
|
||||
directory is mapped in your client. You might need to add a
|
||||
<literal>View</literal> line like:</para>
|
||||
|
||||
<programlisting>//depot/projects/my-new-project/... //<replaceable>myclient</replaceable>/my-new-project/...</programlisting>
|
||||
|
||||
<para>The next step is to run the <command>p4 integrate</command>
|
||||
command, as described in the next section.</para>
|
||||
|
||||
<sect1 id="Integrations">
|
||||
<title>Integrations</title>
|
||||
|
||||
<para><quote>Integration</quote> is the term used by
|
||||
<application>Perforce</application> to describe the action of
|
||||
moving changes from one part of the depot to another. It is most
|
||||
commonly done in conjunction with creating and maintaining
|
||||
branches. An integration is done when you want to initially
|
||||
populate a branch, and it's done when you want to move subsequent
|
||||
changes in the branch from the parent to the child, or from the
|
||||
child to the parent. A common example of this is periodically
|
||||
integrating changes from the vendor &os; tree to your child branch
|
||||
tree, allowing you to keep up to date with changes in the &os;
|
||||
tree. The <application>Perforce</application> server tracks the
|
||||
changes in each tree and knows when there are changes that can be
|
||||
integrated from one tree to another.</para>
|
||||
|
||||
<para>The common way to do an integration is with the following
|
||||
command:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 integrate -b <replaceable>branchname</replaceable></userinput></screen>
|
||||
|
||||
<para><replaceable>branchname</replaceable> is the name given to a
|
||||
branch spec, as discussed in the previous section. This command
|
||||
will instruct <application>Perforce</application> to look for
|
||||
changes in the branch parent that are not yet in the child. From
|
||||
those changes it will prepare a list of diffs to move. If the
|
||||
integration is being done for the first time on a branch (i.e.
|
||||
doing an initial population operation), then the parent files will
|
||||
simply be copied to the child location on the local
|
||||
machine.</para>
|
||||
|
||||
<para>Once the integration operation is done, you must run
|
||||
<command>p4 resolve</command> to accept the changes and resolve
|
||||
possible conflicts. Conflicts can arise from overlapping changes
|
||||
that happened in both the parent and child copy of a file.
|
||||
Usually, however, there are no conflicts, and
|
||||
<application>Perforce</application> can quickly figure out how to
|
||||
merge the changes together. Use the following commands to do a
|
||||
resolve operation:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 resolve -as</userinput>
|
||||
&prompt.user; <userinput>p4 resolve</userinput></screen>
|
||||
|
||||
<para>The first invocation will instruct
|
||||
<application>Perforce</application> to automatically merge the
|
||||
changes together and accept files that have no conflicts. The
|
||||
second invocation will allow you to inspect each file that has a
|
||||
possible conflict and resolve it by hand if needed.</para>
|
||||
|
||||
<para>Once all of the integrated files have been resolved, they need
|
||||
to be committed back to the repository. This is done via the
|
||||
<command>p4 submit</command> command, explained in the next
|
||||
section.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="submit">
|
||||
<title>Submit</title>
|
||||
|
||||
<para>Changes that are made locally should be committed back to the
|
||||
<application>Perforce</application> server for safe keeping and so
|
||||
that others can access them. This is done via the <command>p4
|
||||
submit</command> command. When you run this command, it will open
|
||||
up a submit template in an editor. &os; has a custom template,
|
||||
and the important fields are described below:</para>
|
||||
|
||||
<programlisting>Description:
|
||||
<enter description here>
|
||||
PR:
|
||||
Submitted by:
|
||||
Reviewed by:
|
||||
Approved by:
|
||||
Obtained from:
|
||||
MFP4 after:</programlisting>
|
||||
|
||||
<para>It is good practice to provide at least 2-3 sentences that
|
||||
describe what the changes are that you are submitting. You say
|
||||
should what the change does, why it was done that way or what
|
||||
problem is solves, and what APIs it might change or other side
|
||||
effects it might have. This text should replace the
|
||||
<literal><enter description here></literal> line in the template.
|
||||
You should wrap your lines and start each line with a TAB. The
|
||||
tags below it are &os;-specific and can be removed if not
|
||||
needed.</para>
|
||||
|
||||
<programlisting>Files:</programlisting>
|
||||
|
||||
<para>This is automatically populated with all of the files in your
|
||||
client that were marked in the add, delete, integrate, or edit
|
||||
states on the server. It is always a very good idea to review
|
||||
this list and remove files that might not be ready yet.</para>
|
||||
|
||||
<para>Once you save the editor session, the submit will happen to
|
||||
the server. This also means that the local copies of the
|
||||
submitted files will be copied back to the server. If anything
|
||||
goes wrong during this process, the submit will be aborted, and
|
||||
you will be notified that the submit has been turned into a
|
||||
changelist that must be corrected and re-submitted. Submits are
|
||||
atomic, so if one file fails, the entire submit is aborted.</para>
|
||||
|
||||
<para>Submits cannot be reverted, but they can be aborted while in
|
||||
the editor by exiting the editor without changing the
|
||||
<literal>Description</literal> text.
|
||||
<application>Perforce</application> will complain about this the
|
||||
first time you do it and will put you back in the editor. Exiting
|
||||
the editor the second time will abort the operation. Reverting a
|
||||
submitted change is very difficult and is best handled on a
|
||||
case-by-case basis.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="editing">
|
||||
<title>Editing</title>
|
||||
|
||||
<para>The state of each file in the client is tracked and saved on
|
||||
the server. In order to avoid collisions from multiple people
|
||||
working on the same file at once,
|
||||
<application>Perforce</application> tracks which files are opened
|
||||
for edit, and uses this to help with submit, sync, and integration
|
||||
operations later on.</para>
|
||||
|
||||
<para>To open a file for editing, use the <command>p4 edit</command>
|
||||
command like so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 edit <replaceable>filename</replaceable></userinput></screen>
|
||||
|
||||
<para>This marks the file on the server as being in the edit state,
|
||||
which then allows it to be submitted after changes are made, or
|
||||
marks it for special handling when doing an integration or sync
|
||||
operation. Note that editing is not exclusive in
|
||||
<application>Perforce</application>. Multiple people can have the
|
||||
same file in the edit state (you will be informed of others when
|
||||
you run the <command>edit</command> command), and you can submit
|
||||
your changes even when others are still editing the file.</para>
|
||||
|
||||
<para>When someone else submits a change to a file that you are
|
||||
editing, you will need to resolve his changes with yours before
|
||||
your submit will succeed. The easiest way to do this is to either
|
||||
run a <command>p4 sync</command> or <command>p4 submit</command>
|
||||
and let it fail with the conflict, then run <command>p4
|
||||
resolve</command> to manually resolve and accept his changes into
|
||||
your copy, then run <command>p4 submit</command> to commit your
|
||||
changes to the repository.</para>
|
||||
|
||||
<para>If you have a file open for edit and you want to throw away
|
||||
your changes and revert it to its original state, run the
|
||||
<command>p4 revert</command> command like so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 revert <replaceable>filename</replaceable></userinput></screen>
|
||||
|
||||
<para>This resyncs the file to the contents of the server, and
|
||||
removes the edit attribute from the server. Any local changes
|
||||
that you had will be lost. This is quite useful when you have a
|
||||
made changes to a file but later decide that you do not want to
|
||||
keep them.</para>
|
||||
|
||||
<para>When a file is synced, it is marked read-only in the
|
||||
filesystem. When you tell the server to open it for editing, it
|
||||
is changed to read-write on the filesystem. While these
|
||||
permissions can easily be overridden by hand, they are meant to
|
||||
gently remind you that you should being using the <command>p4
|
||||
edit</command> command. Files that have local changes but are not
|
||||
in the edit state may get overwritten when doing a <command>p4
|
||||
sync</command>.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="changes">
|
||||
<title>Changes, Descriptions, and History</title>
|
||||
|
||||
<para>Changes to the <application>Perforce</application> depot can
|
||||
be listed via the <command>p4 changes</command> command. This
|
||||
will provide a brief description of each change, who made the
|
||||
change, and what its change number was. A change can be examined
|
||||
in detail via the <command>p4 describe
|
||||
<replaceable>changenumber</replaceable></command> command. This
|
||||
will provide the submit log and the diffs of the actual change.
|
||||
It is common to use the <option>-du</option> or
|
||||
<option>-dc</option> flags to produce unified or context diffs
|
||||
instead of the native diff format.</para>
|
||||
|
||||
<para>The <command>p4 filelog
|
||||
<replaceable>filename</replaceable></command> command will show
|
||||
the history of a file, including all submits, integrations, and
|
||||
branches of it.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="diffs">
|
||||
<title>Diffs</title>
|
||||
|
||||
<para>There are two methods of producing file diffs in
|
||||
<application>Perforce</application>, either against local changes
|
||||
that have not been submitted yet, or between two trees (or within
|
||||
a branch) in the depot. These are done with different commands,
|
||||
<option>diff</option> and <option>diff2</option>:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><command>p4 diff</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>This generates a diff of the local changes to files in
|
||||
the edit state. The <option>-du</option> and
|
||||
<option>-dc</option> flags can be used to create unified or
|
||||
context diffs, respectively, or the <envar>P4DIFF</envar>
|
||||
environment variable can be set to a local diff command to be
|
||||
used instead. It is a very good idea to use this command to
|
||||
review your changes before submitting them.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>p4 diff2</command></term>
|
||||
|
||||
<listitem>
|
||||
<para>This creates a diff between arbitrary files in the
|
||||
depot, or between files specified in a branch spec. The diff
|
||||
operation takes place on the server, so <envar>P4DIFF</envar>
|
||||
variable has no effect, though the <option>-du</option> and
|
||||
<option>-dc</option> flags do work. The two forms of this
|
||||
command are:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 diff2 -b <replaceable>branchname</replaceable></userinput></screen>
|
||||
|
||||
<para>and</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 diff2 //depot/<replaceable>path1</replaceable> //depot/<replaceable>path2</replaceable></userinput></screen>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>In all cases the diff will be written to the standard output.
|
||||
Unfortunately, <application>Perforce</application> produces a diff
|
||||
format that is slightly incompatible with the traditional Unix
|
||||
diff and patch tools. Using the <envar>P4DIFF</envar> variable to
|
||||
point to the real &man.diff.1; tool can help this, but only for
|
||||
the <command>p4 diff</command> command. The output of
|
||||
<option>diff2</option> command must be post-processed to be useful
|
||||
(the <option>-u</option> flag of <option>diff2</option> will
|
||||
produce unified diffs that are somewhat compatible, but it does
|
||||
not include files that have been added or deleted). There is a
|
||||
post-processing script at: <ulink
|
||||
url="http://people.freebsd.org/~scottl/awkdiff"></ulink>.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="add-rm-files">
|
||||
<title>Adding and Removing Files</title>
|
||||
|
||||
<para>Integrating a branch will bring existing files into your tree,
|
||||
but you may still want to add new files or remove existing ones.
|
||||
Adding files is easily done be creating the file and then running
|
||||
the <command>p4 add</command> command like so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 add <replaceable>filename</replaceable></userinput></screen>
|
||||
|
||||
<para>If you want to add a whole tree of files, run a command
|
||||
like:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>find . -type f |xargs p4 add</userinput></screen>
|
||||
|
||||
<para>Doing a <command>p4 submit</command> will then copy the file
|
||||
to the Depot on the server. It is very important to only add
|
||||
files, not directories. Explicitly adding a directory will cause
|
||||
<application>Perforce</application> to treat it like a file, which
|
||||
is not what you want.</para>
|
||||
|
||||
<para>Removing a file is just as easy with the <command>p4</command>
|
||||
delete command like so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 delete <replaceable>filename</replaceable></userinput></screen>
|
||||
|
||||
<para>This will mark the file for deletion from the Depot the next
|
||||
time that a submit is run. It will also remove the local copy of
|
||||
the file, so beware.</para>
|
||||
|
||||
<para>Of course, deleting a file does not actually remove it from
|
||||
the repository.</para>
|
||||
|
||||
<para>Deleted files can be resurrected by syncing them to a prior
|
||||
version. The only way to permanently remove a file is to use the
|
||||
<command>p4 obliterat</command>e command. This command is
|
||||
irreversible and expensive, so it is only available to those with
|
||||
admin access.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="working-with-diffs">
|
||||
<title>Working with diffs</title>
|
||||
|
||||
<para>Sometimes you might need to apply a diff from another source
|
||||
to a tree under <application>Perforce</application> control. If
|
||||
it is a large diff that affects lots of files, it might be
|
||||
inconvenient to manually run <command>p4 edit</command> on each
|
||||
file. There is a trick for making this easier. First, make sure
|
||||
that no files are open on your client and that your tree is synced
|
||||
and up to date. Then apply the diff using the normal tools, and
|
||||
coerce the permissions on the files if needed. Then run the
|
||||
following commands:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 diff -se ... |xargs p4 edit</userinput>
|
||||
&prompt.user; <userinput>p4 diff -sd ... |xargs p4 delete</userinput>
|
||||
&prompt.user; <userinput>find . -type f |xargs p4 add</userinput></screen>
|
||||
|
||||
<para>The first command tells <application>Perforce</application> to
|
||||
look for files that have changed, even if they are not open. The
|
||||
second command tells <application>Perforce</application> to look
|
||||
for files that no longer exist on the local machine but do exist
|
||||
on the server. The third command then attempts to add all of the
|
||||
files that it can find locally. This is a very brute-force
|
||||
method, but it works because <application>Perforce</application>
|
||||
will only add the files that it does not already know about. The
|
||||
result of running these commands will be a set of files that are
|
||||
opened for edit, removal, or add, as appropriate. Just do a
|
||||
<command>p4 submit</command> after that.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="renaming-files">
|
||||
<title>Renaming files</title>
|
||||
|
||||
<para><application>Perforce</application> does not have a built-in
|
||||
way of renaming files or moving them to a different part of the
|
||||
tree. Simply copying a file to the new location, doing a
|
||||
<command>p4 add</command> on it, and a <command>p4
|
||||
delete</command> on the old copy, works, but does not preserve
|
||||
change history of the file. This can make future integrations
|
||||
with parents and children very bumpy, in fact. A better method of
|
||||
dealing with this is to do a one-time, in-tree integration, like
|
||||
so:</para>
|
||||
|
||||
<screen>&prompt.user; <userinput>p4 integrate -i <replaceable>oldfile</replaceable> <replaceable>newfile</replaceable></userinput>
|
||||
&prompt.user; <userinput>p4 resolve</userinput>
|
||||
&prompt.user; <userinput>p4 delete <replaceable>oldfile</replaceable></userinput>
|
||||
&prompt.user; <userinput>p4 submit</userinput></screen>
|
||||
|
||||
<para>The integration will force <application>Perforce</application>
|
||||
to keep a record of the relationship between the old and new
|
||||
names, which will assist it in future integrations. The
|
||||
<option>-i</option> flag tells it that it is a
|
||||
<quote>baseless</quote> integration, meaning that there is no
|
||||
branch history available for it to use in the integration. That
|
||||
is perfect for an integration like this, but should not be used
|
||||
for normal branch-based integrations.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="freebsd-cvs-and-p4">
|
||||
<title>Interactions between &os; CVS and Perforce</title>
|
||||
|
||||
<para>The &os; <application>Perforce</application> and CVS
|
||||
repositories are completely separate. However, changes to CVS are
|
||||
tracked at near-real-time in <application>Perforce</application>.
|
||||
Every 2 minutes, the CVS server is polled for updates in the HEAD
|
||||
branch, and those updates are committed to
|
||||
<application>Perforce</application> in the <filename
|
||||
role="directory">//depot/vendor/freebsd/...</filename> tree. This
|
||||
tree is then available for branching and integrating to derivative
|
||||
projects. Any project that directly modifies that &os; source
|
||||
code should have this tree as its branch parent (or grandparent,
|
||||
depending on the needs), and periodic integrations and syncs
|
||||
should be done so that your tree stays up to date and avoids
|
||||
conflicts with mainline development.</para>
|
||||
|
||||
<para>The bridge between CVS and <application>Perforce</application>
|
||||
is one-way; changes to CVS will be reflected in
|
||||
<application>Perforce</application>, but changes in Perforce will
|
||||
not be reflected in CVS. On request, some parts of the
|
||||
<application>Perforce</application> repo can be exported to
|
||||
<application>CVSup</application> and made available for
|
||||
distribution that way. Contact the &os;
|
||||
<application>Perforce</application> administrators if this is
|
||||
something that you are interested in.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="offline-ops">
|
||||
<title>Offline Operation</title>
|
||||
|
||||
<para>One weakness of <application>Perforce</application> is that it
|
||||
assumes that network access to the server is always available.
|
||||
Most state, history, and metadata is saved on the server, and
|
||||
there is no provision for replicating the server like there is
|
||||
with CVS/<application>CVSup</application>. It is possible to run
|
||||
a proxy server, but it only provides very limited utility for
|
||||
offline operation.</para>
|
||||
|
||||
<para>The best way to work offline is to make sure that your client
|
||||
has no open files and is fully synced before going offline. Then
|
||||
when editing a file, manually change the permissions to
|
||||
read-write. When you get back online, run the commands listed in
|
||||
the <xref linkend="working-with-diffs"> to automatically identify
|
||||
files that have been edited, added, and removed. It is quite
|
||||
common to be surprised by <application>Perforce</application>
|
||||
overwriting a locally changed file that was not opened for edit,
|
||||
so be extra vigilant with this.</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="soc">
|
||||
<title>Notes for Google Summer of Code</title>
|
||||
|
||||
<para>Most &os; projects under the Google Summer of Code program
|
||||
will be based in <filename
|
||||
role="directory">//depot/projects/soc2005/<replaceable>project-name</replaceable>/...</filename>
|
||||
on the &os; <application>Perforce</application> server.</para>
|
||||
|
||||
<para>The project mentor is responsible for choosing a suitable
|
||||
project name and getting the student going with
|
||||
<application>Perforce</application>.</para>
|
||||
|
||||
<para>Access to the &os; <application>Perforce</application> server
|
||||
does not imply membership in the &os; CVS committer community,
|
||||
though we happily encourage all students to consider joining the
|
||||
project when the time is appropriate.</para>
|
||||
</sect1>
|
||||
</article>
|
Loading…
Reference in a new issue