<?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>Keyword Substitution</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.advanced.props.special.ignore.html" title="Ignoring Unversioned Items" /> <link rel="next" href="svn.advanced.sparsedirs.html" title="Sparse Directories" /> </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">Keyword Substitution</th> </tr> <tr> <td width="20%" align="left"><a accesskey="p" href="svn.advanced.props.special.ignore.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.sparsedirs.html">Next</a></td> </tr> </table> <hr /> </div> <div class="sect1" title="Keyword Substitution"> <div class="titlepage"> <div> <div> <h2 class="title" style="clear: both"><a id="svn.advanced.props.special.keywords"></a>Keyword Substitution</h2> </div> </div> </div> <p> <a id="idp9859952" class="indexterm"></a>Subversion has the ability to substitute <em class="firstterm">keywords</em>—pieces of useful, dynamic information about a versioned file—into the contents of the file itself. Keywords generally provide information about the last modification made to the file. Because this information changes each time the file changes, and more importantly, just <span class="emphasis"><em>after</em></span> the file changes, it is a hassle for any process except the version control system to keep the data completely up to date. Left to human authors, the information would inevitably grow stale.</p> <p>For example, say you have a document in which you would like to display the last date on which it was modified. You could burden every author of that document to, just before committing their changes, also tweak the part of the document that describes when it was last changed. But sooner or later, someone would forget to do that. Instead, simply ask Subversion to perform keyword substitution on the <code class="literal">LastChangedDate</code> keyword. You control where the keyword is inserted into your document by placing a <em class="firstterm">keyword anchor</em> at the desired location in the file. This anchor is just a string of text formatted as <code class="literal">$</code><em class="replaceable"><code>KeywordName</code></em><code class="literal">$</code>.</p> <p>Adding keyword anchor text alone to your file does nothing special. Subversion will never attempt to perform textual substitutions on your file contents unless explicitly asked to do so. After all, you might be writing a document<sup>[<a id="idp9866800" href="#ftn.idp9866800" class="footnote">26</a>]</sup> about how to use keywords, and you don't want Subversion to substitute your beautiful examples of unsubstituted keyword anchors!</p> <p>To tell Subversion whether to substitute keywords on a particular file, we again turn to the property-related subcommands. The <code class="literal">svn:keywords</code> property, when set on a versioned file, controls which keywords will be substituted on that file. The value is a space-delimited list of keyword names or aliases.</p> <p>For example, say you have a versioned file named <code class="filename">weather.txt</code> that looks like this:</p> <div class="informalexample"> <pre class="programlisting"> Here is the latest report from the front lines. $LastChangedDate$ $Rev$ Cumulus clouds are appearing more frequently as summer approaches. </pre> </div> <p>With no <code class="literal">svn:keywords</code> property set on that file, Subversion will do nothing special. Now, let's enable substitution of the <code class="literal">LastChangedDate</code> keyword.</p> <div class="informalexample"> <pre class="screen"> $ svn propset svn:keywords "Date Author" weather.txt property 'svn:keywords' set on 'weather.txt' $ </pre> </div> <p>Now you have made a local property modification on the <code class="filename">weather.txt</code> file. You will see no changes to the file's contents (unless you made some of your own prior to setting the property). Notice that the file contained a keyword anchor for the <code class="literal">Rev</code> keyword, yet we did not include that keyword in the property value we set. Subversion will happily ignore requests to substitute keywords that are not present in the file and will not substitute keywords that are not present in the <code class="literal">svn:keywords</code> property value.</p> <p>Immediately after you commit this property change, Subversion will update your working file with the new substitute text. Instead of seeing your keyword anchor <code class="literal">$LastChangedDate$</code>, you'll see its substituted result. That result also contains the name of the keyword and continues to be delimited by the dollar sign (<code class="literal">$</code>) characters. And as we predicted, the <code class="literal">Rev</code> keyword was not substituted because we didn't ask for it to be.</p> <p>Note also that we set the <code class="literal">svn:keywords</code> property to <code class="literal">Date Author</code>, yet the keyword anchor used the alias <code class="literal">$LastChangedDate$</code> and still expanded correctly:</p> <div class="informalexample"> <pre class="programlisting"> Here is the latest report from the front lines. $LastChangedDate: 2006-07-22 21:42:37 -0700 (Sat, 22 Jul 2006) $ $Rev$ Cumulus clouds are appearing more frequently as summer approaches. </pre> </div> <p>If someone else now commits a change to <code class="filename">weather.txt</code>, your copy of that file will continue to display the same substituted keyword value as before—until you update your working copy. At that time, the keywords in your <code class="filename">weather.txt</code> file will be resubstituted with information that reflects the most recent known commit to that file.</p> <p>All keywords are case-sensitive where they appear as anchors in files: you must use the correct capitalization for the keyword to be expanded. You should consider the value of the <code class="literal">svn:keywords</code> property to be case-sensitive, too—for the sake of backward compatibility, certain keyword names will be recognized regardless of case, but this behavior is deprecated.</p> <p>Subversion defines the list of keywords available for substitution. That list contains the following keywords, some of which have aliases that you can also use:</p> <div class="variablelist"> <a id="idp9888896" class="indexterm"></a> <a id="idp9890352" class="indexterm"></a> <a id="idp9892256" class="indexterm"></a> <a id="idp9893744" class="indexterm"></a> <a id="idp9895648" class="indexterm"></a> <a id="idp9897520" class="indexterm"></a> <a id="idp9899008" class="indexterm"></a> <a id="idp9900912" class="indexterm"></a> <a id="idp9902400" class="indexterm"></a> <a id="idp9904272" class="indexterm"></a> <a id="idp9905728" class="indexterm"></a> <dl> <dt> <span class="term"> <code class="literal">Date</code> </span> </dt> <dd> <p>This keyword describes the last time the file was known to have been changed in the repository, and is of the form <code class="literal">$Date: 2006-07-22 21:42:37 -0700 (Sat, 22 Jul 2006) $</code>. It may also be specified as <code class="literal">LastChangedDate</code>. Unlike the <code class="literal">Id</code> keyword, which uses UTC, the <code class="literal">Date</code> keyword displays dates using the local time zone.</p> </dd> <dt> <span class="term"> <code class="literal">Revision</code> </span> </dt> <dd> <p>This keyword describes the last known revision in which this file changed in the repository, and looks something like <code class="literal">$Revision: 144 $</code>. It may also be specified as <code class="literal">LastChangedRevision</code> or <code class="literal">Rev</code>.</p> </dd> <dt> <span class="term"> <code class="literal">Author</code> </span> </dt> <dd> <p>This keyword describes the last known user to change this file in the repository, and looks something like <code class="literal">$Author: harry $</code>. It may also be specified as <code class="literal">LastChangedBy</code>.</p> </dd> <dt> <span class="term"> <code class="literal">HeadURL</code> </span> </dt> <dd> <p>This keyword describes the full URL to the latest version of the file in the repository, and looks something like <code class="literal">$HeadURL: http://svn.example.com/repos/trunk/calc.c $</code>. It may be abbreviated as <code class="literal">URL</code>.</p> </dd> <dt> <span class="term"> <code class="literal">Id</code> </span> </dt> <dd> <p>This keyword is a compressed combination of the other keywords. Its substitution looks something like <code class="literal">$Id: calc.c 148 2006-07-28 21:30:43Z sally $</code>, and is interpreted to mean that the file <code class="filename">calc.c</code> was last changed in revision 148 on the evening of July 28, 2006 by the user <code class="literal">sally</code>. The date displayed by this keyword is in UTC, unlike that of the <code class="literal">Date</code> keyword (which uses the local time zone).</p> </dd> <dt> <span class="term"> <code class="literal">Header</code> </span> </dt> <dd> <p>This keyword is similar to the <code class="literal">Id</code> keyword but contains the full URL of the latest revision of the item, identical to <code class="literal">HeadURL</code>. Its substitution looks something like <code class="literal">$Header: http://svn.example.com/repos/trunk/calc.c 148 2006-07-28 21:30:43Z sally $</code>.</p> </dd> </dl> </div> <p>Several of the preceding descriptions use the phrase <span class="quote">“<span class="quote">last known</span>”</span> or similar wording. Keep in mind that keyword expansion is a client-side operation, and your client <span class="quote">“<span class="quote">knows</span>”</span> only about changes that have occurred in the repository when you update your working copy to include those changes. If you never update your working copy, your keywords will never expand to different values even if those versioned files are being changed regularly in the repository.</p> <div class="sidebar" title="Where's $GlobalRev$?"> <div class="titlepage"> <div> <div> <p class="title"> <strong>Where's $GlobalRev$?</strong> </p> </div> </div> </div> <p>New users are often confused by how the <code class="literal">$Rev$</code> keyword works. Since the repository has a single, globally increasing revision number, many people assume that it is this number that is reflected by the <code class="literal">$Rev$</code> keyword's value. But <code class="literal">$Rev$</code> expands to show the last revision in which the file <span class="emphasis"><em>changed</em></span>, not the last revision to which it was updated. Understanding this clears the confusion, but frustration often remains—without the support of a Subversion keyword to do so, how can you automatically get the global revision number into your files?</p> <p>To do this, you need external processing. Subversion ships with a tool called <span class="command"><strong>svnversion</strong></span>, which was designed for just this purpose. It crawls your working copy and generates as output the revision(s) it finds. You can use this program, plus some additional tooling, to embed that revision information into your files. For more information on <span class="command"><strong>svnversion</strong></span>, see <a class="xref" href="svn.ref.svnversion.html" title="svnversion Reference—Subversion Working Copy Version Info">svnversion Reference—Subversion Working Copy Version Info</a>.</p> </div> <p>In addition to previous set of stock keyword definitions and aliases, Subversion 1.8 allows you the freedom to define and use custom keywords. To define a custom keyword, add a token to the value of the <code class="literal">svn:keywords</code> property which is of the form <strong class="userinput"><code><em class="replaceable"><code>MyKeyword</code></em>=<em class="replaceable"><code>FORMAT</code></em></code></strong>, where <em class="replaceable"><code>MyKeyword</code></em> is the keyword name (which you'll use in the keyword anchor) and <em class="replaceable"><code>FORMAT</code></em> is a format string into which information will be substituted when your keyword is expanded inside your file.</p> <p>The format string syntax used for custom keywords supports the following format codes:</p> <div class="variablelist"> <dl> <dt> <span class="term"> <code class="literal">%a</code> </span> </dt> <dd> <p>The author of the revision given by <code class="literal">%r</code>.</p> </dd> <dt> <span class="term"> <code class="literal">%b</code> </span> </dt> <dd> <p>The basename of the URL of the file.</p> </dd> <dt> <span class="term"> <code class="literal">%d</code> </span> </dt> <dd> <p>Short format of the date of the revision given by <code class="literal">%r</code>.</p> </dd> <dt> <span class="term"> <code class="literal">%D</code> </span> </dt> <dd> <p>Long format of the date of the revision given by <code class="literal">%r</code>.</p> </dd> <dt> <span class="term"> <code class="literal">%P</code> </span> </dt> <dd> <p>The file's path, relative to the repository root.</p> </dd> <dt> <span class="term"> <code class="literal">%r</code> </span> </dt> <dd> <p>The last known revision in which this file changed in the repository. (This is the same revision which would be substituted for the <code class="literal">Revision</code> keyword.)</p> </dd> <dt> <span class="term"> <code class="literal">%R</code> </span> </dt> <dd> <p>The URL to the root of the repository.</p> </dd> <dt> <span class="term"> <code class="literal">%u</code> </span> </dt> <dd> <p>The URL of the file.</p> </dd> <dt> <span class="term"> <code class="literal">%_</code> </span> </dt> <dd> <p>A space character. (Keyword definitions cannot contain a literal space character.)</p> </dd> <dt> <span class="term"> <code class="literal">%%</code> </span> </dt> <dd> <p>A literal percent sign ('<code class="literal">%</code>').</p> </dd> <dt> <span class="term"> <code class="literal">%H</code> </span> </dt> <dd> <p>Equivalent to <code class="literal">%P%_%r%_%d%_%a</code>.</p> </dd> <dt> <span class="term"> <code class="literal">%I</code> </span> </dt> <dd> <p>Equivalent to <code class="literal">%b%_%r%_%d%_%a</code>.</p> </dd> </dl> </div> <p>As you can see, many of the individual format codes serve as placeholders for the same information available through the stock keywords. But of course, the custom keyword format allows you to more flexibly string together multiple bits of information. For example, you might wish to have a single keyword in your files which reports the repository relative path of the file and last-changed revision, formatted in a pleasant, human-readable way. To do so, you'd first define your custom keyword:</p> <div class="informalexample"> <pre class="screen"> $ svn pset svn:keywords "PathRev=%P,%_r%r" calc/button.c property 'svn:keywords' set on 'button.c' $ </pre> </div> <p>Next, you'd edit the file's contents to add the keyword anchor for your custom keyword, which in this case is <code class="literal">$PathRev$</code>. After committing these changes, an examination of your file's contents will show that your custom keyword was substituted as you would expect—where previously the file contained <code class="literal">$PathRev$</code>, it now reads <code class="literal">$PathRev: trunk/calc/button.c, r23 $</code>.</p> <div class="note" title="Note" style="margin-left: 0.5in; margin-right: 0.5in;"> <table border="0" summary="Note"> <tr> <td rowspan="2" align="center" valign="top" width="25"> <img alt="[Note]" src="images/note.png" /> </td> <th align="left">Note</th> </tr> <tr> <td align="left" valign="top"> <p>Subversion will automatically truncate any keyword expansions which exceed 255 bytes in length. Also custom keywords defined with names that exceed 255 bytes will be ignored altogether.</p> </td> </tr> </table> </div> <p>You can also instruct Subversion to maintain a fixed length (in terms of the number of bytes consumed) for the substituted keyword. By using a double colon (<code class="literal">::</code>) after the keyword name, followed by a number of space characters, you define that fixed width. When Subversion goes to substitute your keyword for the keyword and its value, it will essentially replace only those space characters, leaving the overall width of the keyword field unchanged. If the substituted value is shorter than the defined field width, there will be extra padding characters (spaces) at the end of the substituted field; if it is too long, it is truncated with a special hash (<code class="literal">#</code>) character just before the final dollar sign terminator.</p> <p>For example, say you have a document in which you have some section of tabular data reflecting the document's Subversion keywords. Using the original Subversion keyword substitution syntax, your file might look something like:</p> <div class="informalexample"> <pre class="programlisting"> $Rev$: Revision of last commit $Author$: Author of last commit $Date$: Date of last commit </pre> </div> <p>Now, that looks nice and tabular at the start of things. But when you then commit that file (with keyword substitution enabled, of course), you see:</p> <div class="informalexample"> <pre class="programlisting"> $Rev: 12 $: Revision of last commit $Author: harry $: Author of last commit $Date: 2006-03-15 02:33:03 -0500 (Wed, 15 Mar 2006) $: Date of last commit </pre> </div> <p>The result is not so beautiful. And you might be tempted to then adjust the file after the substitution so that it again looks tabular. But that holds only as long as the keyword values are the same width. If the last committed revision rolls into a new place value (say, from 99 to 100), or if another person with a longer username commits the file, stuff gets all crooked again. However, if you are using Subversion 1.2 or later, you can use the new fixed-length keyword syntax and define some field widths that seem sane, so your file might look like this:</p> <div class="informalexample"> <pre class="programlisting"> $Rev:: $: Revision of last commit $Author:: $: Author of last commit $Date:: $: Date of last commit </pre> </div> <p>You commit this change to your file. This time, Subversion notices the new fixed-length keyword syntax and maintains the width of the fields as defined by the padding you placed between the double colon and the trailing dollar sign. After substitution, the width of the fields is completely unchanged—the short values for <code class="literal">Rev</code> and <code class="literal">Author</code> are padded with spaces, and the long <code class="literal">Date</code> field is truncated by a hash character:</p> <div class="informalexample"> <pre class="programlisting"> $Rev:: 13 $: Revision of last commit $Author:: harry $: Author of last commit $Date:: 2006-03-15 0#$: Date of last commit </pre> </div> <p>The use of fixed-length keywords is especially handy when performing substitutions into complex file formats that themselves use fixed-length fields for data, or for which the stored size of a given data field is overbearingly difficult to modify from outside the format's native application. Of course, where binary file formats are concerned, you must always take great care that any keyword substitution you introduce—fixed-length or otherwise—does not violate the integrity of that format. While it might sound easy enough, this can be an astonishingly difficult task for most of the popular binary file formats in use today, and <span class="emphasis"><em>not</em></span> something to be undertaken by the faint of heart!</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>Be aware that because the width of a keyword field is measured in bytes, the potential for corruption of multibyte values exists. For example, a username that contains some multibyte UTF-8 characters might suffer truncation in the middle of the string of bytes that make up one of those characters. The result will be a mere truncation when viewed at the byte level, but will likely appear as a string with an incorrect or garbled final character when viewed as UTF-8 text. It is conceivable that certain applications, when asked to load the file, would notice the broken UTF-8 text and deem the entire file corrupt, refusing to operate on the file altogether. So, when limiting keywords to a fixed size, choose a size that allows for this type of byte-wise expansion.</p> </td> </tr> </table> </div> <div class="footnotes"> <br /> <hr width="100" align="left" /> <div class="footnote"> <p><sup>[<a id="ftn.idp9866800" href="#idp9866800" class="para">26</a>] </sup>… or maybe even a section of a book …</p> </div> </div> </div> <div class="navfooter"> <hr /> <table width="100%" summary="Navigation footer"> <tr> <td width="40%" align="left"><a accesskey="p" href="svn.advanced.props.special.ignore.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.sparsedirs.html">Next</a></td> </tr> <tr> <td width="40%" align="left" valign="top">Ignoring Unversioned Items </td> <td width="20%" align="center"> <a accesskey="h" href="index.html">Home</a> </td> <td width="40%" align="right" valign="top"> Sparse Directories</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>