The most annoying thing about Perforce SCM

I’ve been using Perforce on for various things during the last 2 years. The first thing that was really annoying, and now has become so annoying that it is about to cross into being outright hostile about Perforce is…

There is no way to find out what’s going on with the files in your workspace, without a slow roundtrip to the server for every file in the local workspace directory!

Yes, Virginia, you have to iterate through each friggin’ file in the local workspace, and ask the server what it knows about it… multiple times…

Finding the “status” of the local workspace directory is an operation that is so ubiquitous when working with software that it is really beyond my head why Perforce doesn’t even have a single command for it. Here are some cases where this sort of “local tree status” is useful:

  • You have applied a diff (patchfile) on top of a checkout, and you want to see which files were affected, and how they changed.
  • You have deleted directory “mumble”, extracted “mumble-1.2” and renamed it to “mumble” and you want to see what files changed, so you can import the new version of the “mumble” component.
  • A fellow developer wants you to test some local changes he made, so he sends you a couple of files, which you want to diff with your latest checkout of these files.

The best recommendation I’ve found so far is listed in one of the “Technical Notes” of the Perforce documentation, and it goes something like this:

p4 diff -sd ... | p4 -x - delete
find . '!' -type d | p4 -x - add 2>&1 | fgrep -v existing
p4 diff -se ... | p4 -x - edit

That’s crazy. The equivalent command in, say, Subversion is something like:

svn status | more

or even something shorter:

svn stat | more

With Mercurial things are even faster, and quite unsurprisingly similar to what Subversion supports:

hg addremove
hg status | more

That’s it… You can run “hg add” on new files, “hg delete” on files which are gone from the local workspace, and then look at the current status of your local workspace, and it all happens in the short timespan of a second or so: that’s how long it takes to type the two commands and watch Mercurial blaze through the file list.

Knowing that there are systems out there which are fast, free software and more featureful, every time I have to run a script with the Perforce commands needed to tell the repository what it should be smart enough to find on its own, and then wait for half an hour for a Perforce server across half of the world to get in sync with reality, a stream of endless frustrated curses attempts to escape my mouth :-/

The next time someone asks me which SCM system to use, and someone suggests a commercial, slow, feature-restricted SCM system, it will be very hard to convince me that the free software SCM systems we have today don’t fit the bill…

VERY very hard…


6 thoughts on “The most annoying thing about Perforce SCM

  1. keramida Post author

    True, “svn st” works. So does “hg st”, and “bzr st”.

    Almost every single SCM, which respects itself, is smart enough to implement a “status” command and command completion from unique prefix strings :-)

  2. dky

    I am in a similar state. Having to work with P4 that I do not know and do not wish to learn either.
    Have you come across something like git-p4 for mercurial (written either in PERL/PYTHON). I am aware of sscm for which I need Ruby. I am getting into yet another language/scm and not able to zero in on one…
    I really like the simplicity of mercurial but need a working hg-p4 (aka git-p4).

  3. keramida Post author

    I basically wrote my own.

    I like Mercurial far more than Perforce for a few reasons. Accessing a Perforce depot from across the globe was also getting to be an immense pain after a while. So I wrote a few shell scripts which do essentially ‘incremental snapshot imports’ from Perforce.

    The result was not really on par with git-p4, and I’ve been pondering for a while how we could write an extension for Mercurial to do incremental imports. It may still be worth writing something like this.

    The basic setup I finally settled for used two workspaces for each branch I wanted to import from Perforce to Mercurial: (a) a Perforce client view that mapped parts of the depot to a local p4 specific working directory, and (b) a Mercurial workspace where I periodically pushed snapshots.

    There are several assumptions that the scripts relied upon, i.e.:

    (1) Only a single depot path was imported, i.e. //depot/foo/bar/…

    (2) The Mercurial workspace is ‘clean’ from local changes.

    (3) The local Mercurial commits are of the form:

    bring over XXXX from //depot/foo/bar/…

    Original Perforce commit log
    goes here in as many lines as

    What the importer scripts did was essentially the following:

    (1) Find out the last XXXX change number from the commit logs of the Mercurial workspace.

    (2) Find out the latest YYYY change number from the Perforce depot, and the range of changes from XXXX to YYYY.

    (3) For each change in the Perforce workspace view:

    (3.1) Run “p4 sync” to that change.

    (3.2) Use “p4 describe -s” to find out the set of affected files, and build lists of new, deleted and modified files, and the commit log for the change.

    (3.3) Use “cpio -p -dmu” to copy the new and modified files from the Perforce workspace into the Mercurial workspace.

    (3.4) Use “rm” in the Mercurial workspace to delete the files which are gone in Perforce.

    (3.5) Run “hg addremove –similarity 99.0” in the Mercurial workspace in an effort to track renames.

    (3.6) Commit the changes to the Mercurial workspace.

    This is a very “crude” way of importing snapshots, and it probably fails in spectacular ways with Perforce workspaces which mix and match files from various depot paths. It worked “well enough” for my needs at the time, though, so I stopped there.

    The inverse operation, of pulling patches out of Mercurial and committing them to Perforce, was a bit easy too. I just used “hg export” and “hg diff” to create diff-style patches. Then these patches were applied with GNU patch(1) on the Perforce workspace and I used another shell script to run on the patched files the equivalent of:

    find file1 file2 … fileN | p4 -x – add 2>&1 | fgrep -v existing
    p4 diff -se file1 file2 … fileN | p4 -x – open
    p4 diff -sd file1 file2 … fileN | p4 -x – delete

    That was usually enough to build an active “changelist”, and commit the patches to Perforce.

  4. Sam Heller

    I’ve just recently been stuck with perforce, but I’ve found something a little more tenable :
    p4 changelist -o
    will give you something resembling svn stat. Depending on how big your repository is you might get a lot of unecessary info, but a pipe through grep usually takes care of it for me

Comments are closed.