Version Control Systems are tools that every programmer should use. Among them, Git is probably the most popular one. Some companies use Perforce instead. Whether it is better or worse is hard to tell, but it has its advantages that make it indispensable in some types of projects, like game development. Perforce handles large binary files very well. Even if the files have tens or a hundred of gigabytes, it still works fine. I talk about the size of one local copy here, not the entire repository on the server.
From user’s perspective, Perforce differs greatly from Git or SVN. Not only commands are named differently (e.g. there is “Submit” instead of “Commit”), but the whole concept of “changelists” is something that needs to be well understood to be used efficiently. While working with Perforce for many years in different companies and projects, I learned some good practices that I would like to share here. Writing them down was difficult as they seem obvious to me, but hopefully some of them are not obvious to you so you will learn something new.
1. Paste paths to address bar
Let’s start with a simple one. Perforce window has a text box on the top that resembles address bar in web browsers. It shows the path of the currently selected file or directory in Depot or Workspace tab. It can also accept input.
When you work on some file in another tool and you want to jump quickly to it in Perforce, e.g. to check it out, just copy the full path of the file to system clipboard and paste it in this “address bar”. Selection in Workspace tab will switch to it immediately.
2. Remember which submitted change do you base on
Shelved changelists and submitted changelists have very little in common except their name. They are very different concepts. Each file in your workspace is a copy of the file from the repository in some specific version (e.g. #29), most probably retrieved when updating entire workspace at once using a command like Get Revision or Get Latest Revision. On top of that, a file can be checked out to have some local changes, which then you save to a shelved changelist.
My advice is not to use Get Latest Revision ever, but always know which exact submitted changelist is your workspace at, and so which submitted changelist is the base of your local changes you have in your files currently checked out, or files on your shelved changelists. Trust me - this will save you and your colleagues a lot of hassle when same files are changed locally and remotely and some conflicts arise.
For example, if you can launch a build on a build server to test automatically your shelved changes, you could have a possibility to specify base submitted CL number next to your shelved CL number. Then, even if the same files changed in their latest submitted version, the build server will pick the right code to apply your shelve and test. If it is based on the latest submitted code, there would be conflicts and the build would fail. Of course, after the automated build and tests passed, you still need to manually unshelve, update to the latest base, and resolve conflicts. Only then you can submit.
To use this method, every time I want to update my workspace, I first go to Submitted tab, clear all the filters, and save the number of the latest changelist I can see there on top of the list. The number can be saved wherever you want - in the description of your shelved changelist or some personal notes in a text file or in Google Docs. Next, I right-click on the directory enclosing entire workspace and select Get Revision. Instead of “Get latest revision”, I explicitly specify changelist number to get all files from. Then I scrupulously keep track of which submitted CL number are my local changes in some shelved CL based on.
3. Track the history of your complex changes… in some way
One of the biggest disadvantages of Perforce is that it doesn’t remember the history of your local changes. Using Git, you are encouraged to commit small steps of your development and experimentations, create branches and merges. All this can be done locally, as every developer has a local version of the entire repository and its full history. In Perforce, this is not the case. A natural way to work on some code changes here is to just have some files checked out or shelved in your CL on top of the version of the files from the central repository.
This is not a problem when you make a small, point change to the code, but if you work on a bigger piece of code, some new feature or a vast refactoring, you may want to keep different versions of your local changes. Perforce won’t help you with that naturally, so if you may not submit your small steps to the central repository, you are left with some custom solutions, like:
4. Check out before or Reconcile after you modified files
One of the distinctive features of Perforce is that it sets Read-only attribute to all the files in the workspace. Normally, this attribute prevents the files from modifications, but modern text editors often show a warning and allow the user to overwrite the file, anyway. The idea behind this write protection is that you are supposed to know which files you want to modify, use Check Out command to add them to your local changelist and remove Read-only attribute, and modify the file after that.
This is easy when you know exactly which few files you are going to modify. If the code change you need to make is broader and can span across many files and directories, you can approach it in two ways:
5. Use P4Merge even with other version control systems
A diff tool inseparably accompanies every version control system. It is needed to compare changes in two versions of a file or provide a “three-way merge”. The best tool I know is Beyond Compare, but it is not free. Another good and free one is WinMerge. Perforce comes with its own comparison tool called P4Merge. Unlike these two mentioned earlier, it cannot compare entire directories, only single files, but otherwise I like it a lot.
I like it so much that I use it as the diff tool even with Git and other version control systems. On a machine where you don’t need Perforce you can download and launch the installer of P4V / Helix Visual Client (so many names for the Perforce client!), but select only P4Merge from the components to install. You can then set it as the diff tool to use in your Git or other VCS client, like I do in Git Extensions - my favorite visual Git client.
6. Configure mapping to exclude big files you don’t need
Mapping is a powerful feature of Perforce. It allows you to define a set of rules that map paths in remote repository to directories in your local workspace. Recommended mapping is surely defined for the repository in your company. Sometimes it is so simple as:
Where the part before space is a remote path and the part after space is a path within your local workspace. Sometimes it is more complicated, with separate directories for external libraries and tools, binary assets, source code, etc.
There is also a feature to exclude certain files or directories. If you observe that some of them occupy a large space on your disk or take long time to download every time you update your code and you are certain you don’t need them for the tasks you do in this project, you can update your workspace mapping to exclude them by using minus sign.
7. Use Time-lapse View before blaming someone for a bug
If you want to see who modified particular file recently, the first thing we usually do is right-clicking and selecting File History. It works, but more details can be obtained if you learn to interpret information in Time-lapse View instead. A window that appears after clicking this command shows the history of each line of the file, somewhat like “Blame” command in Git. If you select a line, you can see in the bottom panel the details of specific submitted changelist that added or modified that line - changelist number, date, author, description etc.
If you want to find out who was the real author of some piece of code, it is important to take a deeper look at this information. It may turn out that the changelist you are looking at was just something like “Fixed formatting”. You should then grab the purple knob on the timeline on top and drag it left to the revision number before the yellow bar. A version of the entire file then shows up as it was before that change. You can then observe that same place in the code and see how it looked like before, as well as select the line of your interest again and hopefully see the real author, not the one who only fixed formatting.
8. Use multiple workspaces
In a big company, it is normal that things go slowly. E-mails to read, meetings to attend, forms to fill in… To be efficient, you need to do multiple tasks at once and pipeline them. You can often start a new task while the previous one is still awaiting code review or QA validation. How to handle all this in your Perforce workspace?
One way is to keep your code for different tasks shelved on different changelists, but this is not always handy. For example, if each of the tasks has to be done based on a different submitted CL, switching back and forth between them may require updating lots of files and take long time. A solution to this is to have multiple workspaces on your PC, each with a separate copy of the entire project. You can switch between workspaces in Perforce client easily using combo-box on top of Depot and Workspace tab. Of course, this is possible only if a single copy of the project is relatively small and doesn’t fill in your entire hard drive.
9. Double-check local changes before shelving or submitting
No matter if you are going to shelve your changes to save it for later and switch to some other task, to share your code with a colleague who will unshelve it on his machine, or you finished your work and want to Submit, you need to make sure the code you send to the server is exactly what you have on your machine. If you just fixed one line in one file, it comes without effort, but if that was a work you were doing for the entire last week, before shelving or submitting you should make sure that:
10. Use SimplySaveAs tool to download historical version of a file
If you look at History of some file and select some old version of it, you can right-click and do many things - Get This Revision, Diff Against…, Open With… One thing that is missing is a possibility to save this version of the file to your disk. This is contrary to other VCS clients like Git Extensions, which lets you Save As a historical version of a file.
But there is a solution. You probably know that to “Open With”, the file must be saved somewhere on disk, most likely in some temporary directory, and the selected program will be launched with a path to it as a command line parameter. Knowing this, I developed a tiny program called SimplySaveAs that you can use to “Open With” in Perforce and then save the file in a directory of your choice. I will write more about this tool in the future in a separate article.