| 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. | |