Any sufficiently advanced technology is indistinguishable from magic.
-- Arthur C. Clarke, (Clarke's third law)
Introduction
How do you use perforce? Some like to stuff as much as possible in the repository, in the hopes that it will be useful to have it all in one place. Others like to keep it minimalistic as to not bog down the server too much. I've already written a little bit about the things that might be good to consider setting up a perforce server (look at the article here), but once it's up and running you might want to have a look at how you are using it.
Perforce is very good at two things, speed and integration. At these two points it's a good competitor with the other solutions out there. Having these two things should be an incentive to start taking advantage of it. The speed and integration comes at some costs though, the speed is severely impacting the way you can work offline and the integration is only as good as you tell perforce that you make changes.
A source control system is only as good as you let it be, if you never tell it what you're doing, it will never pick it up. On the same note, if you are not shaping your workflow around what it can handle, you experience with the system will not be so good. So here are a couple of practical tips that you should consider adopting.
Organizing staged third party libraries
If you are using third party source libraries it's most probable that you might want to do minor changes to them. This can be easy or really painful. The painful way is to simply check the source code in and change it inplace. Yes, it might seem like the right way to go. [Ok, the really painful way is to not check it into perforce at all, and leave it on the side but we're not quite that ehrm, out looking for new ways of pain are we?] The easier way to do this is to have a stage directory where you place the distribution each time a new drop comes out. From there you branch it to the place where you want to use it. At this final place, you can also do changes.
//depot/external/packages/zlib/... # usable copy //depot/external/drop/zlib/... #drop distributions here //depot/internal/mygame/... # uses //depot/external/packages/zlib/include
Now every time you get a new drop you can do this:
- Sync up.
- Delete the local directory of the library without telling perforce
- Unzip the new files
- Run p4offlinesync.py
- Checkin
- Branch the new version into the final location
- Merge any of your old changes
- Checkin
- Bob is your uncle.
This will let you track how the third party library changed between revisions, if they added any files, where they had bug fixes etc. It will also in most cases just resolve your changes automatically, and only ever require integration when your local patches overlap with the thirdparty vendor and then it's a very good idea indeed to look at what didn't merge properly.
Automate tedious tasks
There are a lot of powerful idioms you can use when developing in a team. One of the things that the history lets you do is to easily jump back and forth between versions of the files. Some companies frown upon people who check in and run. This is really just a small annoyance, it might not be considered polite but in the end it's not really a big deal as long as that person is buying into the fact that people can revert his changelist if it turned out that it broke something somehow. Reverting individual changelists is really quite involved in perforce, it feels a little like Maya, they give you the bare bones and then you have to fill in the details yourself. This one thing should perhaps be built in, but then again maybe the secret behind maya's and perforce's success lies within them not putting these features in.
Automating common tasks like reverting a changelist is pretty easy (even easier if you download the excellent script here.). But seriously, some automation should definitely be there, just so that your programmers can get over the mental barrier of doing something conceptually easy, but very involved in details.
Don't use the default integration
The default integration with visual studio frankly blows. It easily blows large medicine balls through a very small garden hose. It's not even perforce's fault as far as I can tell. It's just that the model for the source control plugins in visual studio are all modeled after the workflow in SourceSafe. Now people might argue that SourceSafe is perfectly all right. Yes. It is. As much as CVS is all right. That is, for a very limited project with one programmer or two it might work. But for anything in a professional production environment, please. Since you're reading this I assume that you're already happily in the perforce camp.
But if you don't use the default integration, will that not leave you doing an awful lot of work? Well, there are alternatives that are not quite as retarded as the default plugin. Some of them include:
- NiftyPerforce
- DoItNow
- SimpleMacros (look at EditModifiedDocumentsInPerforce).
Use the file integration
Moving files around in perforce is quite easy. The main thing to overcome is the fact that you want to use it. Don't move files behind perforce's back. To copy a file from one location to another, simply use the "file integration" command. If you want to move it, simply delete the old copy. There is even a menu command in perforce to do this called "rename", but it's really just a shortcut to the integrate/delete two stage operation.
Try to keep the mappings simple
One of the much touted things in perforce is the client mappings and the fact that they can pretty much transform the repository to any crazy setup you might have on the clients. Try to resist the urge to use this feature for anything that's not dead simple. As soon as you have more than a couple of lines in you clientspec things becomes messy. I once worked at a place where they had 40-50 lines of mappings for different libraries and projects. It was incredibly complex and completely unnecessary. Try to keep it simple and in one depot. Multi depot development also is a little bit of a mind warp.
One of the good things about the clientspec is that it lets you specify exclude patterns. So if you want to not sync to source maya files or psd files, you can specify those. Those same clientmappins also applies to files you add, so if you add exclusion filters on common intermediate files (or those pesky .user/.suo/.ncb files) then you will never accidentally add them.
Prepare for branching
Even if you don't branch right now, the day might come when you do want to branch. That day might be put off if the up front work is big. Now, you can kind of prepare for this day by simply moving all your files up one level in the repository tree. Instead of having:
//depot/shared/core.h //depot/projects/tetris/main.cpp
You can instead move this to be
//depot/main/shared/core.h //depot/main/projects/tetris/main.cpp
This way you can have several top level directories, each naming a particular branch. It's an easy way to visualize the branches in the perforce viewer as well. All without making complicated client mappings. Yay.
Ooops, I forgot to branch
Ever found yourself in a situation where you started on a minor change and it all snowballed into a bloody mess, source code all over the place died and you went rampart on the optimize delete-key? At those times you wished that you were already on a branch, but it's kind of a pain to create a new branch and start working on it. Well, it turns out that it really isn't that hard, but it's just a lot of tedious work. It would be great if there was a script to do this, right?
You can actually use p4shelf for this exact scenario. The script allows you to archive your work in the current clientspec and move the work to any other clientspec that has a similar mapping.
In closing
That were some of my tips of making your daily perforce life a little bit easier so that you can concentrate on simply writing code or perhaps world domination through the next addictive game. Do you have any must do tips?
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!