December 9, 2009

Shelving: Pretty Darn Useful!

Version Control
Developer Collaboration

As of Release 2009.2 (now in beta), Perforce supports "shelving". That is, you can cache your modified files on the server, without having to check them in as a versioned change. For teams, shelving makes code reviews and code handoffs possible. Individuals can use shelving for multi-tasking, code shunting, incremental snapshots, and safety nets.

Shelved files in Perforce are visible to users who have access to the underlying files, so shelving is a perfect way of exposing the files you are working on to your team. Just use the shelve command to upload your local versions. They'll be assigned a changelist number that can be used to view and diff your shelved files. In fact, reviewers can even unshelve your files into their own workspaces if they want.

In your workspace, the shelved files are left open. A shelved changelist acts as a pending changelist, so you can continue working on the files during and after code review. You can re-shelve files into the same shelved changelist for another review, or you can submit them as a versioned change.

Perforce's shelving implementation is different from other implementations in several ways. For one thing, files remain untouched in your workspace when you shelve them. The shelve command creates a changelist that acts both as a pending change in your workspace, and as a public reference to the shelved versions of your files. For another, you can't submit a shelved changelist. (Not yet, at any rate. There are rumors that we'll be able to do this in the future.) So before you submit your files you have to tell the server to discard the shelved versions. Or, you can move your opened files to a new pending changelist and submit that instead. If you do the latter, your shelved files remain cached on the server until you discard them.

This makes Perforce's shelving suitable for handing off work in progress. After shelving your modified files you can use revert to release the shelved changelist from your workspace. This restores your workspace to its pre-modified condition. If you then assign the shelved changelist to a new owner, that user will now see it in her list of pending changes. She can now unshelve the files into her workspace, keeping them in the same pending changelist. After working on the files she can either reshelve them and hand the changelist back to you, or she can submit the changelist herself.

Shelving is also an easy way to shunt code from one machine to another. For example, you've done some coding on a Windows machine. But does your new code compile on the Mac? To find out, shelve your files while on Windows, then unshelve them while on a Mac. You can shelve and unshelve code this way as needed before submitting a change.

How about shelving work in progress for multi-tasking? Say you're burning out on one coding task and want to take break to work on another. No problem -- just shelve your files. You can leave a note to yourself about what you were doing in the description of the shelved changelist. Now revert your workspace files to restore your workspace to its unmodified condition; your shelved versions remain cached on the server. You can now start working on another coding task, and when you tire of the second task, shelve again to create a second shelved changelist. To go back to the first task, unshelve the first changelist. You can switch between tasks this way as often as you like.

Shelving gives you a way to make incremental snapshots of unsubmitted work in progress. The trick here is to create a new shelved changelist every time you want to save a snapshot of your files. To do that, your files can't be in a shelved changelist, which is where the shelve command leaves them. That means that each time you shelve, you must then move your opened files back to the default changelist. Each invocation of the shelve command copies your files to the server and gives you a new, shelved change number that is a reference to a snapshot you can restore.

This is admittedly a bit more cumbersome than using your editor's autosave. Why not just rely on that? Because for one thing, autosave works only on individual files. Shelving, by contrast, can scoop up all your opened files, creating a snapshot of your entire work in progress. For another, shelving saves all pending check-in data, including new file names, new file types, and resolved or unresolved merges. Your editor's autosave can't do that. Nor can your editor restore to a state that's not in your undo stack. With shelving, you can save any number of important (or seemingly important) states on the server until you discard them explicitly. (Which brings up an important point: If you use shelving to make incremental snapshots, please be considerate and delete shelved changelists once you no longer need them. Your Perforce administrator will thank you for that.)

Even if you don't need incremental snapshots, you'll find that shelving makes a great safety net for resolving merges into files you've already edited. Just run shelve before you run resolve. After resolving, you can compare your workspace files to the shelved versions to make sure none of your own edits were mangled in the merge. If don't like the result of a merge, you can revert the file and unshelve it to get your pre-resolved version back. This also restores the file's pending resolve status, so now you can try resolving it a different way.

To sum up, there remains one question: how did we get by so long without shelving?