A UI Specification for "Locking" This document describes a user interface of a new locking system for Subversion. It implements the set of features described in the associated functional spec. I. Introduction A. Goals/Audience There are two audiences we need to consider for a locking UI: 1. The enlightened software developer - understands general VC concepts (required for job) - understands concurrency model - has already embraced Subversion (or at least CVS) - ITCH: Some files aren't mergeable, like image files or spreadsheets. Need to force serialized edits on such things, as an occasional exception to concurrency. 2. The reluctant user of version control - bright people, but no time or interest in learning VC concepts - doesn't understand concurrency - doesn't understand "out-of-dateness" or merging procedures - typical examples: - coder who has only used VSS or Clearcase with 100% locking - website developer being forced to use VC - manager being forced to use VC - ITCH: VC system should be effortless, transparent, and idiot proof. VC system should prevent people from wasting editing time, destroying each others changes, all while avoiding concurrency concepts such as "merging" and "out of dateness". B. The "Hijack" Scenario This is specific use-case which is particularly important to making version control usable by the second type of user described above. In this scenario, the user has a tool that circumvents whatever system is in place to enforce serialized editing. In systems like VSS or Clearcase 'copy' views, this usually means an editor that ignores the read-only attribute on a file. When the user goes to commit, they discover that they were supposed to lock the file, and the repository version has changed. What now? The power-svn user would certainly have no problem knowing what to do seeing an error that "the file must be locked to commit", nor would such a user be confused by seeing a subsequent error that the "file is out-of-date". The power user would run 'svn update', resolve conflicts, then lock the file and commit. But the reluctant or ignorant svn user shouldn't (and doesn't need to) be forced to deal with merging and out-of-dateness when working in an "all locking" environment. Here are a few usability case-studies: - Clearcase dynamic views The workspace is always up-to-date, all of the time. And it's impossible to circumvent the read-only bit. So the hijack scenario can't happen at all. - Clearcase copy-based views In the hijack scenario, the user attempts to commit and the client responds by attempting an interactive contextual merge. If not possible, the whole commit fails and a guru is phoned to fix the situation. - Visual Source Safe in the hijack scenario, the user remembers to lock the file long after editing it; VSS asks whether to use the server version or local version of the file. Somebody's edits are lost. It is the recommendation of this document that the command line client produce normal conflicts when 'svn up' is run on a hijacked file; but that for a GUI such as TortoiseSVN, a more friendly (or interactive) procedure is followed -- perhaps one that allows the user to choose between versions of files. II. New Client Behaviors A. Overview This section describes a user interface to accomplish "locking", as described in the functional spec. A new property is used to enforce locking and prevent people from wasting time; lock tokens are objects, stored in the working copy, that represent a lock; and two new subcommands (lock/unlock) are described. B. The "svn:needs-lock" property Create a new "svn:needs-lock" property to indicate that a file should be locked before committing. Just like "svn:executable", the value of the property is irrelevant and the property can be created (or deleted) by any user or administrator. Note that this property doesn't enforce locking. When the Subversion client encounters the "svn:needs-lock" property on a path (on checkout or update), it sets the working-copy path to a read-only state by default. This serves as a reminder to the user that she should lock this path before editing it. When a user locks the path, the Subversion client makes the working-copy path read-write. When the user releases the lock, or if the lock is found to be defunct (see next section), the Subversion client makes the path read-only again. C. Lock manipulation via client 1. Lock Tokens When a user successfully locks a path, the working copy receives a "lock token" from the server. This token is an object that connects your exclusive right to commit to a path with your working copy. You can think of a lock token as a form of authentication for a certain working copy. Why is it important or useful for lock tokens to be attached to only one working copy? [An example: you might lock an unmergeable file using a computer at your office, perhaps as part of a changeset in progress. It should not be possible for a working copy on your home computer to accidentally commit a change to that same file, just because you've authenticated as the user which owns the lock. If you really want to change the file from home, you'd have to "steal" the lock from your other working copy, which is discussed later in this document.] Because locks can be broken or stolen, it is possible for a lock token to become "defunct". A defunct lock cannot be used or released--it is useless and is cleaned up when you next run 'svn update'. 2. New client subcommands Summary: svn lock [--force]: lock (or steal) svn unlock [--force]: release (or break) a. Creating a lock To lock a path, use the 'svn lock' command: $ svn lock foo.c username: harry password: XXXXX [...] 'foo.c' locked by user 'harry'. In order for this command to work, - You *must* provide a username to the server. 'anonymous' locks are not allowed. - The path must not already be locked. - The path must not be out-of-date. The lock command accepts -m or -F to add a lock comment, so others can see why the file was locked. The lock comment is optional. b. Using a lock A lock can be used to make an exclusive commit to a path. Also, if you have a lock, you can opt to "release" (destroy) it when you're done. To make use of a lock, two forms of authentication must be provided to the server: - The authenticated username that owns the lock - A non-defunct lock token If either of these forms of authentication are missing or incorrect, the lock cannot be used. 1. Using a lock to Commit $ svn commit foo.c Upon successful commit, a locked path is released by default. The Subversion client provides an option to retain the lock after commit: $ svn commit foo.c --no-unlock If --no-unlock is not specified, even unmodified files will be considered part of the commit and shown to the user in the list of files to commit. Such files will also be unlocked after the commit. 2. Releasing a lock $ svn unlock foo.c Lock on 'foo.c' has been released. After successful release, the working copy's lock token is gone. c. Breaking a lock "Breaking" a lock is a means of releasing a lock when: - The authenticated username is not the same as the lock owner, or - The working-copy lock representation is unavailable. Use the --force option to the unlock subcommand to break a lock. For example: $ svn unlock foo.c username: sally password: XXXX svn: error: 'foo.c' is locked by user 'harry'. $ svn unlock foo.c --force username: sally password: XXXX Lock on 'foo.c' has been broken. The --force option also accepts a URL, so that the lock can be released without a working copy. d. Stealing a lock "Stealing" a lock is a means of creating a lock when: - The path is locked by you, but you don't have a representation of the lock in your current working copy, or - The path is locked by someone else. In order to steal a lock, a user must be authenticated to the server. Use the --force option to the lock command to steal a lock. For example: $ svn lock foo.c username: sally password: XXXX svn: error: 'foo.c' is locked by user 'harry'. $ svn lock foo.c --force username: sally password: XXXX 'foo.c' locked by user 'sally'. Remember that the 'svn lock' command still requires that the target be up-to-date to succeed. e. Discovering/examining locks 1. seeing lock tokens in a working copy 'svn status' considers a lock token "interesting", and displays it using some new symbol, in a new column: $ svn status M foo.c M K bar.c A baz.c Note that K (locKed) is used instead of the more intuitive L, since L is already in use for another purpose. 2. seeing locks in a repository. 'svn status -u' adds out-of-date information from the server; in a similar manner, this command shows any locks that exist on the server: $ svn status -u M foo.c M K bar.c A * baz.c * file1 O file2 M B file3 M T file42 As with "svn status", the sixth column indicates lock state. The letters have the following meanings: ' ': No lock in either WC or repository. 'K': Locked in the WC and lock token valid in repository. 'O': No lock in WC, lock in repository. (Locked in Other WC.) 'B': Lock in WC, but no lock in repository. (Lock Broken.) 'T': Locked in WC, but locked with another token in repository. (Lock was sTolen.) 3. 'svn info', describes the attributes of a lock-token, if attached to a working object. If invoked on a URL, it displays information about any remote lock attached. $ svn info foo.c Path: foo.c Name: foo.c URL: http://..../ [...] Lock Token: 465610b1-33eb-0310-8a02-cae41507c13a Lock Owner: lundblad Lock Comment: Refactoring. Lock Creation Date: 2004-12-14 14:49:36 +0100 (Tue, 14 Dec 2004) $ svn info http://host/repos/file2 Path: /file2 Name: file2 URL: http://..../ [...] Lock Token: 465610b1-33eb-0310-8a02-cae41507c13b Lock Owner: fitz Lock Comment: Don't touch my file! Lock Creation Date: 2004-12-25 14:49:36 +0100 (Tue, 14 Dec 2004) 4. 'svn update' changes At the start of an update, the client reports any lock-tokens to the server. If a lock token has become "defunct", the client is instructed to destroy the lock token. A new column will be added to the update output to indicate removed lock tokens: svn up U path1 U path2 B path3 C B path4 In the above example, lock tokens for path3 and path4 were removed. Note that 'B' is used even if there is a new lock in the repository. III. New Server Behaviors A. Overview This section describes new server UIs for locking: two new hook scripts, a new 'svnlook' subcommand, and a new 'svnadmin' subcommand. B. Tracking locks The Subversion server holds the master list of all locks for a repository. It responds to client requests to create, release, break and steal locks. C. Enforcement During a commit, the server checks for locks the same way that it checks for out-of-dateness: $ svn commit Sending foo.c Sending bar.c svn: error: 'bar.c' is locked by user 'harry'. D. Configurable Mechanisms 1. New "pre-" hook scripts a. pre-lock Used to authorize lock creation. Invoked whenever a user creates a lock ('svn lock') or steals a lock ('svn lock --force'). If an administrator wants the locking feature completely disabled, just set this hook to always return failure. - input: REPOS, PATH, USER - successful exit means lock is allowed, else deny lock creation. - if path is already locked, hook script can deduce that USER is "stealing" the lock and decide what to do. b. pre-unlock Used to authorize lock releasing. Invoked whenever a user releases a lock ('svn unlock) or breaks a lock ('svn unlock' --force). - input: REPOS, PATH, USER - successful exit means release is allowed, else deny. - if path is already locked, hook script can deduce that USER is "breaking" the lock and decide what to do. 2. New "post-" hook scripts a. post-lock Used to report lock creation. Invoked whenever a user creates a lock ('svn lock') or steals a lock ('svn lock --force'). - input: REPOS, PATH, USER - exit code ignored - can be used to send email, collect statistics, etc. b. post-unlock Used to report lock release. Invoked whenever a user releases a lock ('svn unlock') or breaks a lock ('svn unlock --force'). - input: REPOS, PATH, USER - exit code ignored - can be used to send email, collect statistics, etc. E. Lock manipulation with svnadmin 1. Discovering locks A new 'svnlook listlocks' subcommand shows all current locks in a repository: $ svnlook listlocks /usr/local/svn/repos # harry Aug 16 15:13 /trunk/bar.c # sally Sep 07 09:30 /trunk/doc/foo.doc 2. Unconditional release of locks A new 'svnadmin unlock' subcommand to unconditionally release a lock. Note that this command circumvents hook scripts, much like other svnadmin actions: $ svnadmin unlock /usr/local/svn/repos /trunk/doc/foo.doc Lock on '/trunk/doc/foo.doc' has been released.