<?xml version="1.0" encoding="utf-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Working Without a Working Copy</title> <link rel="stylesheet" type="text/css" href="styles.css" /> <meta name="generator" content="DocBook XSL Stylesheets V1.76.1" /> <style type="text/css"> body { background-image: url('images/draft.png'); background-repeat: no-repeat; background-position: top left; /* The following properties make the watermark "fixed" on the page. */ /* I think that's just a bit too distracting for the reader... */ /* background-attachment: fixed; */ /* background-position: center center; */ }</style> <link rel="home" href="index.html" title="Version Control with Subversion [DRAFT]" /> <link rel="up" href="svn.advanced.html" title="Chapter 3. Advanced Topics" /> <link rel="prev" href="svn.serverconfig.netmodel.html" title="Network Model" /> <link rel="next" href="svn.advanced.summary.html" title="Summary" /> </head> <body> <div xmlns="" id="vcws-version-notice"> <p>This text is a work in progress—highly subject to change—and may not accurately describe any released version of the Apache™ Subversion® software. Bookmarking or otherwise referring others to this page is probably not such a smart idea. Please visit <a href="http://www.svnbook.com/">http://www.svnbook.com/</a> for stable versions of this book.</p> </div> <div class="navheader"> <table width="100%" summary="Navigation header"> <tr> <th colspan="3" align="center">Working Without a Working Copy</th> </tr> <tr> <td width="20%" align="left"><a accesskey="p" href="svn.serverconfig.netmodel.html">Prev</a> </td> <th width="60%" align="center">Chapter 3. Advanced Topics</th> <td width="20%" align="right"> <a accesskey="n" href="svn.advanced.summary.html">Next</a></td> </tr> </table> <hr /> </div> <div class="sect1" title="Working Without a Working Copy"> <div class="titlepage"> <div> <div> <h2 class="title" style="clear: both"><a id="svn.advanced.working-without-a-wc"></a>Working Without a Working Copy</h2> </div> </div> </div> <p>As we described in <a class="xref" href="svn.basic.in-action.html#svn.basic.in-action.wc" title="Subversion Working Copies">the section called “Subversion Working Copies”</a>, the Subversion working copy is a sort of staging area where a user can privately make changes to his or her versioned data and then—when those changes are complete and ready for sharing with others—commit them to the repository. It should come as no surprise, then, that most of the interaction you will have with Subversion will be in the form of asking your Subversion client to do <span class="emphasis"><em>something</em></span> to one or more items in a local working copy. Even for those operations which don't manipulate the working copy data itself (such as <span class="command"><strong>svn log</strong></span>), it's often just easier to use a working copy file or directory as a convenient target for that operation.</p> <p>Clearly, the typical approach to making changes to your versioned data is via commits from a Subversion working copy. Fortunately, it's not the only way. Users of Subversion who need to make relatively simple changes to their versioned data can do so without the overhead of checking out a working copy. We'll cover some of those supported operations in this section.</p> <div class="sect2" title="Remote command-line client operations"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="svn.advanced.working-without-a-wc.svn"></a>Remote command-line client operations</h3> </div> </div> </div> <p>The Subversion command-line client supports a number of operations which can be performed directly against repository URLs in order to make simple changes without a working copy. Some of these are described elsewhere in this book, but we provide an exhaustive list of them here for your convenience.</p> <p>Perhaps the most obvious remote commit-like operation is the <span class="command"><strong>svn import</strong></span> command. We describe that command in <a class="xref" href="svn.tour.importing.html#svn.tour.importing.import" title="Importing Files and Directories">the section called “Importing Files and Directories”</a> as part of explaining how you can easily get a whole tree of unversioned information into your Subversion repository so you can start doing version-controlled operations on it.</p> <p>The <span class="command"><strong>svn mkdir</strong></span> and <span class="command"><strong>svn delete</strong></span> commands, when used with URL targets, are also remote commit-type operations. These allow the user to create one or more new versioned directories or remove (recursively) one or more versioned files or directories, respectively, without the use of a working copy. Each time you issue one of these commands, the client communicates with the server in a way that's similar to how it would describe the commit of a directory added or of an item removed from the working copy. If there's no problem or conflict detected with the requested operation, the server commits the additions or removals in a single new revision.</p> <p>You can use <span class="command"><strong>svn copy</strong></span> or <span class="command"><strong>svn move</strong></span> with two URLs—a copy/move source and a destination—to commit a copies and moves of files and directories directly in the repository. These operations tend to be some of the most expensive ones when performed within a working copy, but they complete in constant time when performed remotely using repository URLs. In fact, the <span class="command"><strong>svn copy</strong></span> remote operation is commonly used to create branches in Subversion, as we discuss later in <a class="xref" href="svn.branchmerge.using.html#svn.branchmerge.using.create" title="Creating a Branch">the section called “Creating a Branch”</a>.</p> <p>As with the regular <span class="command"><strong>svn commit</strong></span> command, you can supply a log message with any of these commands we've discussed so far to describe the changes you're making. Use the <code class="option">--file (-F)</code> or <code class="option">--message (-m)</code> option, or otherwise allow the client to prompt you for the log message.</p> <p>Finally, there are a number of operations related to unversioned revision properties which can be performed directly against the repository. In fact, revision properties are somewhat unique in this context, as they aren't stored in the working copy and therefore <span class="emphasis"><em>must</em></span> be modified without working copy interaction. See <a class="xref" href="svn.advanced.props.html" title="Properties">the section called “Properties”</a> for a more detailed description of how to manage properties in Subversion.</p> </div> <div class="sect2" title="Using svnmucc"> <div class="titlepage"> <div> <div> <h3 class="title"><a id="svn.advanced.working-without-a-wc.svnmucc"></a>Using svnmucc</h3> </div> </div> </div> <p>One shortcoming of the remote commit operation support offered in the command-line client is that you are essentially limited to one operation—or, really, one type of operation—per commit. For example, it's perfectly natural and supported to, say, use <span class="command"><strong>svn delete</strong></span> followed by <span class="command"><strong>svn mkdir</strong></span> within a working copy to replace an existing versioned directory with a brand new one. When you commit the results of those operations, a single new revision is created in the repository, and that revision carries the full replacement of your directory. You can't really do the same thing as remote operations using the command-line client while still preserving the it-happened-in-a-single-revision-ness of the change—<span class="command"><strong>svn delete <em class="replaceable"><code>URL</code></em></strong></span> would create a new revision that removed the directory; <span class="command"><strong>svn mkdir <em class="replaceable"><code>URL</code></em></strong></span> would generate a second revision for the directory's re-creation.</p> <p>Fortunately, Subversion provides a separate tool which exists solely to allow users to string together a set of remote operations and commit them as one atomic change. That tool is the <span class="command"><strong>svnmucc</strong></span> tool—the Subversion Multiple URL Command Client:</p> <div class="informalexample"> <pre class="screen"> $ svnmucc --help Subversion multiple URL command client usage: svnmucc ACTION... Perform one or more Subversion repository URL-based ACTIONs, committing the result as a (single) new revision. Actions: cp REV URL1 URL2 : copy URL1@REV to URL2 mkdir URL : create new directory URL mv URL1 URL2 : move URL1 to URL2 rm URL : delete URL put SRC-FILE URL : add or modify file URL with contents copied from SRC-FILE (use "-" to read from standard input) propset NAME VAL URL : set property NAME on URL to value VAL propsetf NAME VAL URL : set property NAME on URL to value from file VAL propdel NAME URL : delete property NAME from URL … </pre> </div> <p><span class="command"><strong>svnmucc</strong></span> has been a part of the Subversion project's source code tree for many years (as <span class="command"><strong>mucc</strong></span> for most of that time), but it was only in Subversion 1.8 that it become a fully supported member of the Subversion command-line tool suite.</p> <p>The <span class="command"><strong>svnmucc</strong></span> tool can perform any transformation on your versioned data that <span class="command"><strong>svn</strong></span> itself can. But unlike <span class="command"><strong>svn</strong></span>, the functionality that <span class="command"><strong>svnmucc</strong></span> offers isn't broken up into subcommands. Rather, you provide a list of actions and operands in a single command line (or from a file stream, via the <code class="option">--extra-args (-X)</code> option). Some of the actions supported by <span class="command"><strong>svnmucc</strong></span> mimic those of the command-line client. You'll notice in the previous command output actions such as <code class="literal">cp</code>, <code class="literal">mkdir</code>, <code class="literal">mv</code>, and <code class="literal">rm</code>, all of which are very similar to the commands we mentioned in <a class="xref" href="svn.advanced.working-without-a-wc.html#svn.advanced.working-without-a-wc.svn" title="Remote command-line client operations">the section called “Remote command-line client operations”</a>. But remember, the key difference here is that you can use any number of these actions together in a single command invocation, resulting in a single committed revision in the repository.</p> <p>Let's take our previous example of trying to simply replace a remote directory. Using <span class="command"><strong>svnmucc</strong></span>, you would accomplish this as follows:</p> <div class="informalexample"> <pre class="screen"> $ svnmucc rm http://svn.example.com/projects/sandbox \ mkdir http://svn.example.com/projects/sandbox \ -m "Replace my old sandbox with a fresh new one." r22 committed by harry at 2013-01-15T21:45:26.442865Z $ </pre> </div> <p>As you can see, <span class="command"><strong>svnmucc</strong></span> accomplished in a single revision what <span class="command"><strong>svn</strong></span>—without the benefit of a working copy—required two revisions to complete.</p> <div class="warning" title="Warning" style="margin-left: 0.5in; margin-right: 0.5in;"> <table border="0" summary="Warning"> <tr> <td rowspan="2" align="center" valign="top" width="25"> <img alt="[Warning]" src="images/warning.png" /> </td> <th align="left">Warning</th> </tr> <tr> <td align="left" valign="top"> <p>Another difference between <span class="command"><strong>svnmucc</strong></span> and <span class="command"><strong>svn</strong></span> is that the former currently will not prompt you for a commit log message if you fail to supply one via the command line. Rather, it will use a stock (that is, relatively valueless) log message.</p> </td> </tr> </table> </div> <p>The <span class="command"><strong>svnmucc</strong></span> tool is not limited to merely remixing actions that <span class="command"><strong>svn</strong></span> itself can perform. It introduces some additional functionality not found in the command-line client. For example, you can use the <span class="command"><strong>put</strong></span> action to add or modify a file in the repository, copying the file's intended new contents from either a file on your local machine or from data piped in via standard input. The tool also offers <span class="command"><strong>propset</strong></span>, <span class="command"><strong>propsetf</strong></span>, and <span class="command"><strong>propdel</strong></span> actions, useful for setting properties on versioned files and directories (explicitly, or by copying the property's value from a local file) and for deleting properties on the same. Those actions are unsupported in the command-line client at this time.</p> <p>At this point, though, it seems prudent to discuss the difference between what <span class="emphasis"><em>can</em></span> be done with <span class="command"><strong>svnmucc</strong></span> and what <span class="emphasis"><em>should</em></span> be done. A pair of notable quotes comes to mind:</p> <div class="blockquote"> <table border="0" width="100%" cellspacing="0" cellpadding="0" class="blockquote" summary="Block quote"> <tr> <td width="10%" valign="top"> </td> <td width="80%" valign="top"> <p> <span class="quote">“<span class="quote">To whom much has been given, much will be expected.</span>”</span> </p> </td> <td width="10%" valign="top"> </td> </tr> <tr> <td width="10%" valign="top"> </td> <td colspan="2" align="right" valign="top">--<span class="attribution">Jesus</span></td> </tr> </table> </div> <div class="blockquote"> <table border="0" width="100%" cellspacing="0" cellpadding="0" class="blockquote" summary="Block quote"> <tr> <td width="10%" valign="top"> </td> <td width="80%" valign="top"> <p> <span class="quote">“<span class="quote">With great power comes great responsibility.</span>”</span> </p> </td> <td width="10%" valign="top"> </td> </tr> <tr> <td width="10%" valign="top"> </td> <td colspan="2" align="right" valign="top">--<span class="attribution">"Spiderman" Peter Parker's Uncle Ben</span></td> </tr> </table> </div> <p>Inherent in working-copy-less modifications is the loss of the very conflict detection safeguards which make the use of a working copy so valuable. When using <span class="command"><strong>svn</strong></span> in the typical way, changes are committed to the server against a specific base version of a file or directory so that you don't inadvertently overwrite contemporary changes made to the same item by another team member. The server knows what version of the file you had before you changed it, and it knows if other folks have changed that same file since that revision was created. That's all the information the server needs to deny your commit when it would clobber someone else's change, forcing you to integrate their change into your working copy and reconsider your own change. Because there is no working copy in the mix here, <span class="command"><strong>svnmucc</strong></span> really gives you the power to bypass those safeguards and to act as if the current state of the repository is precisely the base state against which you are working. But hopefully it is obvious to you that this is not a power you should cavalierly wield.</p> <p>Fortunately, <span class="command"><strong>svnmucc</strong></span> allows you to be more conservative in the way you use the tool. In order to provide a safety mechanism similar to what is offered by the use of a working copy, <span class="command"><strong>svnmucc</strong></span> offers a <code class="option">--revision (-r)</code> option. With this option, you can manually specify a base revision for the changes you are attempting to commit. The base revision you choose is ideally the most recent revision in your repository of which you can reasonably claim knowledge.</p> <div class="warning" title="Warning" style="margin-left: 0.5in; margin-right: 0.5in;"> <table border="0" summary="Warning"> <tr> <td rowspan="2" align="center" valign="top" width="25"> <img alt="[Warning]" src="images/warning.png" /> </td> <th align="left">Warning</th> </tr> <tr> <td align="left" valign="top"> <p>Users are strongly encouraged to use, and to use correctly, the <code class="option">--revision (-r)</code> option to <span class="command"><strong>svnmucc</strong></span>.</p> </td> </tr> </table> </div> <p>Proper use of the <span class="command"><strong>svnmucc put</strong></span> action best demonstrates how this <code class="option">--revision (-r)</code> option should be used. Say Harry wishes to change the contents of a versioned <code class="filename">README</code> file without bothering with a full checkout of a working copy. (We'll assume that there is no other value in using a working copy for this operation, such as the presence of scripts Harry should run in advance of his commit to verify that it's a reasonable one.) The first decision he has to make is which revision of the file he wants to work with. Typically, users wish to modify the most recent version of a file. So Harry queries the revision in which the file was last modified, and then uses that revision to fetch the contents of the file into a temporary local file:</p> <div class="informalexample"> <pre class="screen"> $ svn info http://svn.example.com/projects/sandbox/README Path: README URL: http://svn.example.com/projects/sandbox/README Relative URL: ^/sandbox/README Repository Root: http://svn.example.com/projects Repository UUID: 13f79535-47bb-0310-9956-ffa450edef68 Revision: 22 Node Kind: file Last Changed Author: sally Last Changed Rev: 14 Last Changed Date: 2012-09-02 10:34:09 -0400 (Sun, 02 Sep 2012) $ svn cat -r 14 http://svn.example.com/projects/sandbox/README \ > README.tmpfile $ </pre> </div> <p>Harry now has a copy of the <code class="filename">README</code> file as it looked when it it was last modified. He makes the edits he wishes to make to this copy of the file. Naturally, when he's finished, he wishes to then commit those changes to the repository.</p> <p>Now, if Harry naively uses <strong class="userinput"><code>svnmucc put …</code></strong> at this point to replace the contents of <code class="filename">README</code> in the repository with his locally modified contents, he has just abused the power that <span class="command"><strong>svnmucc</strong></span> affords. What if, just microseconds prior to his commit, Sally had also modified the <code class="filename">README</code> file? As with the <span class="command"><strong>svn</strong></span> program, <span class="command"><strong>svnmucc</strong></span> won't attempt some sort of server-side content merge in order to preserve both users' changes. Rather, <span class="command"><strong>svnmucc</strong></span> will happily replace the current latest version of the file with the contents specified. Harry will be oblivious. Sally will be livid.</p> <div class="informalexample"> <pre class="screen"> $ svnmucc put README.tmpfile \ http://svn.example.com/projects/sandbox/README \ -m "Tweak the README file." r24 committed by harry at 2013-01-21T16:21:23.100133Z $ Message from sally@shell.example.com on pts/2 at 16:26 ... We need to talk. Now. EOF </pre> </div> <p>Harry should instead recall the revision he originally used as the revision on which to base his changes, supplying that revision to <span class="command"><strong>svnmucc</strong></span> via the <code class="option">--revision (-r)</code> option, and thus giving the server the opportunity to bounce his commit if, by his own (perhaps ignorant) admission, he's attempting to modify an out-of-date item:</p> <div class="informalexample"> <pre class="screen"> $ svnmucc -r 14 put README.tmpfile \ http://svn.example.com/projects/sandbox/README \ -m "Tweak the README file." svnmucc: E170004: Item '/sandbox/README' is out of date $ </pre> </div> <p>Like other <span class="command"><strong>svnmucc</strong></span> options, the <code class="option">--revision (-r)</code> option operates at a scope global to the whole command—every action specified in that command. This enables you to have the same sort of safeguards you would have if you had checked out a working copy of your entire repository (and thus had a working copy entirely at a single uniform revision), made changes to that working copy, and then committed all those changes at once.</p> <p>As you can see, <span class="command"><strong>svnmucc</strong></span> is a handy addition to the Subversion user's tool chest. For a complete reference of this tool's offerings, see <a class="xref" href="svn.ref.svnmucc.html" title="svnmucc Reference—Subversion Multiple URL Command Client">svnmucc Reference—Subversion Multiple URL Command Client</a>.</p> </div> </div> <div class="navfooter"> <hr /> <table width="100%" summary="Navigation footer"> <tr> <td width="40%" align="left"><a accesskey="p" href="svn.serverconfig.netmodel.html">Prev</a> </td> <td width="20%" align="center"> <a accesskey="u" href="svn.advanced.html">Up</a> </td> <td width="40%" align="right"> <a accesskey="n" href="svn.advanced.summary.html">Next</a></td> </tr> <tr> <td width="40%" align="left" valign="top">Network Model </td> <td width="20%" align="center"> <a accesskey="h" href="index.html">Home</a> </td> <td width="40%" align="right" valign="top"> Summary</td> </tr> </table> </div> <div xmlns="" id="vcws-footer"> <hr /> <img src="images/cc-by.png" style="float: right;" /> <p>You are reading <em>Version Control with Subversion</em> (for Subversion 1.8), by Ben Collins-Sussman, Brian W. Fitzpatrick, and C. Michael Pilato.</p> <p>This work is licensed under the <a href="http://creativecommons.org/licenses/by/2.0/">Creative Commons Attribution License v2.0</a>.</p> <p>To submit comments, corrections, or other contributions to the text, please visit <a href="http://www.svnbook.com/">http://www.svnbook.com/</a>.</p> </div> </body> </html>