Can anything be stupider than that a man has the right to kill me because he lives on the other side of a river and his ruler has a quarrel with mine, though I have not quarrelled with him?
-- Blaise Pascal
Introduction
Oh no! Not another perforce post. Spare us. We're not even using perforce anyways. Uhm. Have those guys left? Ok, well then for the rest of us that are left, I'm going to assume that you either use perforce happily at work or you are forced by some guy to use it. If you're the latter, then you might look envily at other modern source control systems that literally run circles around this old beast. I'm not kidding, running circles really means that you in other systems have adopted branching as the most basic operation you do.
Think accurev, git or bitkeeper. They all are based around the fundamental principle of branching is what do you all the time. Whenever you get the latest version, you basically integrate whatever changes happened in some other branch (the main branch?) and pull them down to your own branch (local copy).
But I digress. Back to perforce, who say that they handle branches, even encourage it. They brag that they are good at it as well. It turns out that it's both true and really abysmally false. Yes, branching files in the repository is really fast, it does so keeping excellent track of changes and it's relatively painless. I once sat on a game project where we had one branch for each of the two platforms. The codebase was about 1 million lines of code. I spent about one day a week to pull down changes from one branch to another while we had the whole renderer, network and sound system rewritten. I could never have done that without perforce (ok, it still took a whole day, or sometimes more. It was painful, but well worth the productivity for our team). The point is, integrating changes from one branch to another is really easy and perforce helps you a lot. And it's by far the fastest system out there (have you tried to move directories in subversion? Zzzzz).
Big changes
Unfortunately perforce doesn't work like git or bitkeeper where you are always in your own branch, or at least that is not the default behavior. Most companies have a main line where all their engineers check into, or if there is branching going on, at least more than one person checking into any given branch. This is usually not a problem, apart from when you're in the middle of a big change and want to have some kind of history on your changes since they've grown too big for your comfort.
We've all been there. A small enough change turns out to open this innocent can and the worms come crawling out there like, well, worms. It's ugly, but you don't really think about it but rather put on your trusty headphones, put on some of that angry metal and spend the next hour or so fixing things. Or so you think, because at every turn there is more worms and they are starting to look like they guys from Spore now. So finally you've got too many changes and for whatever reason you can't check it into the mainline without some testing. But you really want to have some history on your changes, desperately need them, because it sucks so hard to have to go back and fix bugs in your code that once worked without no history of your changes!
The solution to all of this is of course to check it in. If you were on git you could just do it, nobody else is using that your personal branch. If you are on perforce, you can longingly glance at your neighbor that has git. Or you could scream a little inside and try to fix your bugs. Stuff like this usually snowballs away from you.
If only you could create a branch on the fly, take your existing changes there and check into that branch. Now that would actually solve all our problems. Can such a wonderful thing be done? It turns out that it's surprisingly easy to do this, but in standard perforce fashion it's not exposed in an easy manner [1]. So someone has to write a script for it. Lucky for you, I've already done that!
In an essence the script looks at the current clientspace, saves all the current work off to the side and then branches all the files to a new location in the repository, then changes the current clientspec to point at that new location and finally restores the changes we had in the old clientspec. In practice you could run this on your clientspec and basically move your work with you.
In action this would be:
p4branch.py quad //depot/experimental1/... p4 submit -d “point checkin, not tested yet”
This would take all my files in my clientspec "quad" and copy them over to the experimental1 branch and then submit them into perforce at the new location, not breaking anybody else. Once I've completed my experiment, I could integrate the files from //depot/experimental1/... to //depot/main/... again.
Prerequisites and limitations
Unfortunately, this script can't be used just as is. It sets some constraints since the programmer was really lazy employed agile practices. First, your perforce repository needs to have separate directories for each branch. This is really good practice anyhow, but I thought that I'd throw it out there. This is an example of a layout:
See how all the sibling directories form different branches? There is one branch, the main branch aptly called main.
Another restriction is that you must have a fairly simple clientspec, in fact it need to be downright simplistic. This comes down to the substitution rules I use (they are dumb, but hey the work for me!) in the script itself. You can only have one line in your view, doing a simple mapping from the depot to your client. A sample client might look like:
Client: QUAD Update: 2008/09/13 00:08:25 Access: 2008/09/13 00:04:43 Owner: Jim_Tilander Host: quad Description: Created by Jim_Tilander. Root: c:\work\perforce Options: noallwrite noclobber nocompress unlocked nomodtime rmdir SubmitOptions: submitunchanged LineEnd: local View: //depot/main/... //QUAD/...
Notice that the last line, the view, only have one directory from the repository and pulling it down without any rewrites to the client root.
In closing
I must say that before you go off and try this script, please be careful! I've of course tried it out here at home and I'm planning on taking the script to work and try it out as well. But these are all controlled environments that I know of. I have no chance to predict all the ways that perforce can be setup and used, so the script might very well not handle e.g. spaces very well and wind up wiping your entire computer!!!
That said, I've tried to save all the files, backup the repository and choose safety over speed. The script could very well just have swapped out things on the fly and not pulled down the repository again, but that would have meant slightly less failsafe so I choose the more safer way.
Finally, if you like this script, as the other scripts, please participate in the development by joining the group and also posting patches, issues etc at the project page.
Resources
- Practical Perforce, a pragmatic take on how to manage and do common operations in perforce the way it was intended. Go with the flow and read it!
- Download the script http://code.google.com/p/p4scripts/source/browse/trunk/src/p4branch.py
- This needs the script p4shelf.
Footnotes
[1] Actually, this is a common complaint about perforce, that there is very little functionality out of the box. Much like Maya, you need to apply heavy customization to the package in order for it to work at your site. Sometimes I do feel that perforce should provide slick tools to do exactly this out of the box and spare me to write the scripts...