The Changeset at the Pend of the Universe

Reading Jason’s post on lock types got me thinking about the general concept of pending changes. While some users may already be familiar with the concept, not all other version control systems use similar models. For the uninitiated, here’s a bit of background that may clear things up. Thanks to James for his input!

What is a pending change?

A pending change is a statement of intent, to some degree. Users pend changes to let the central repository know about a change they plan to check in at some later time. Until they either check in or undo the change, the server keeps a record of the type of change pended. If multiple users try to pend changes on the same item, all users after the first will see warnings letting them know that there are other people working on the file, too.

This is distinct from operations which immediately perform their entire functionality. For example, the get command immediately retrieves the files requested to the local disk. The command workspaces immediately prints out a list of workspaces. Most commands which change the state of files in the repository, however, require first a command to pend the change and then a command to check the change in.

For example, let's say we just installed Visual Studio Team System. We'll refer to this diagram throughout our examples. At this point, the system has one folder in source control—the root folder '$/'. Then, a user comes along and pends several adds, like "h add a doc /recursive"* which pends an add on the folders 'a' and 'doc' as well as all folders and files under them. These files do not exist in the repository until the user checks in the change. At that point, version control attempts to upload the changes to the server and, if successful (for instance, no conflicts exist), assigns a changeset number.

Where do pending changes go?

When a change is pended, the effect of the operation occurs in the files of the user’s local workspace. If the change is later checked in, the main repository files are updated to reflect the change. Otherwise, if it is undone, the user’s local files are rolled back to the state they were in prior to pending the change. If a user has more than one workspace, only the workspace in which the change was pended will reflect the change.

The status command displays a list of pending changes. Without any other arguments, it only displays changes pending for the current user in the current workspace. (The "current workspace" is determined by the directory you call "h status" from combined with your current workspace mappings. If the folder falls within one of the mappings, the client will default to that workspace. If the current folder is unmapped, you will need to specify the workspace. For more on mappings, see this helpful post.) The /workspace flag can be used to indicate the workspace or "*" for all workspaces. For example, "h status /workspace:AdamSiWS2" or "h status /workspace:*". In addition, the /user flag can be used to specify another user or "*" for all users, as in "h status /workspace:* /user:CORPNET\JSmith" which will show all pending changes for user CORPNET\JSmith. "h status /workspace:* /user:*" will show all pending changes for all users. The status command also accepts a filespec and then only shows pending changes on the indicated files. "h status . /recursive" will show the any pending changes on folders and files located within the current directory tree.

In our diagram, the white boxes actually represent two things. At the blue arrow point in time, they represent the changes that are being pended to the workspace. At the green arrow point in time, the changes are being checked in to become a changeset. They are reflected in the user's local workspace but are not yet available to anyone else. The server knows that these changes are pending, but has no other information about them.

Which commands pend changes?

Changes are pended by the commands add, branch, checkout (also known as "edit"), delete, merge, rename (also known as "move"), and undelete. For branch and merge, the change is actually pended on the target rather than the source of the operation. While locks will also appear in a status query, the lock is actually applied as soon as the lock command is called and is unlocked when the lock-holder checks in.

Back to our example, lets look at the second change. The user may have typed "h branch a b" to pend the branch, "h delete doc\r.txt" for the "h edit doc\s.txt" followed by some text change for the edit, and "h add doc\t.txt" for the add. The user may also have had other pending changes that were not submitted as part of this checkin, such as "h add foo\bar.vb".

Basically, changing files in the repository is a two step process. First, you have to let the server know what you’re planning to do. Then, after making the appropriate changes, you tell the server to update the files. This lets you try out your changes locally before updating the repository. What happens if someone else beats you to the punch? Well, you get a conflict—but that’s a topic for another post.

Note: At some point, the command 'h.exe' will be changing to 'tf.exe' or similar. However, for the December CTP and earlier versions, the version control command line executable is still named 'h.exe'.