问题
When does keyword substitution occur? How to set
I set svn:keywords
property
I put these lines in 1.txt and committed it.
$Revision$
$Author$
回答1:
Keywords are expanded on checkout/update/switch/export/cat of a file if and only if the appropriate svn:keywords
values are set. When committing a file containing a keyword the client reduces the keyword down to be an empty copy of the keyword string and sends that to the server. The reason Subversion does not enable keywords unless the svn:keywords
property is set is Subversion will never change your file content unless you tell us to do so, which the property does.
Consider the INSTALL document for Subversion. It has the svn:keywords
property set to LastChangedDate
. If you retrieve the file with HTTP (and not a Subversion client) from this URL:
https://svn.apache.org/repos/asf/subversion/trunk/INSTALL
You will note that the file only has $LastChangedDate$
and is not expanded. This is the representation of the file as stored in the server. Since 1.8.0 we have an addition option for the server that allows HTTP clients to request the keywords be expanded. So if you visited the following URL you will see the keyword is expanded:
https://svn.apache.org/repos/asf/subversion/trunk/INSTALL?kw=1
You can also use the Subversion client's cat
command to retrieve files and do the keyword substitution for you (e.g.
svn cat https://svn.apache.org/repos/asf/subversion/trunk/INSTALL
).
The values that keywords are expanded to when they are expanded are based on the revision properties for the revision the file was last changed in. Revision properties are generally set at commit time (though the revision properties may be changed at a later date). So what the values you get in the output depend upon the values at the time the expansion is done. The HeadURL
property is of course also a property of how the repository is accessed. Revision
may never change.
I would recommend reading the section about keyword substitution in the SVN Book if you're going to use them.
回答2:
Subversion sets the keywords during commit. Try an svn update
and see if that takes care of it.
Subversion keyword substitution is a server feature. There's documentation on how it works in the Subversion online manual. Make sure svn:keywords
has the keywords you need, properly capitalized, whitespace separated, and without the dollar signs. For example
$ svn propset svn:keywords "Revision Author" myfile.txt
and not
$ svn propset svn:keywords "revision author" myfile.txt # Wrong capitalization
$ svn propset svn:keywords "$Revision$ $Author$" myfile.txt # $ should not be included
$ svn propset svn:keywords "Revision Author" myfile.txt # No commas
And, now onto my rant...
RCS Keywords are Dangerous
Okay, they won't poke your eye out. But, they just are not all that useful and cause all sorts of issues in development.
RCS created the current crop of keywords that you see. RCS didn't really have a concept of a complete repository and there was no easy way to see information like the name of the author or RCS revision number of a particular file. The keywords would support that.
Subversion doesn't need keywords because Subversion has the concept of a compete repository. If you're editing a file and want to know who the author was, or what revision it is, you simply do svn info
on that file.
However, old habits die hard, and Subversion will give you the ability to support some of the less terrible RCS keywords (it will not support $Log$
which can become a recursive nightmare if someone put word $Log$
in the commit comments.) because some managers (aka clueless wonders) insist that keywords are important, and if a version control system doesn't support them, it's no good.
So, what harm is it in using keywords?
Imagine you make a branch:
$ svn cp trunk/proj ../branches/2.3/proj
Now, later on, you want to see the changes you've made on that branch and how it differs from the trunk:
$ svn diff $REPO/trunk/proj $REPO/branches/2.3/proj
Hmm... It looks like every single file on that branch has been changed. Maybe I should do a diff...
$ svn diff $REPO/trunk/proj/foo.txt $REPO/branches/2.3/proj/foo.txt
+ /trunk/proj/foo.txt
- /trunk/branches/2.3/proj/foo.txt
+ /* $Revision: 23293$ */
- /* $Revision: 25329$ */
Oh... The entire diff is just that RCS keyword that I had embedded in my program. Now, there is absolutely no way for me to know what files were actually changed and what weren't changed except for that RCS keyword.
By the way, doing an svn merge
, each of those keyword changes will show up as a conflict. You will spend 20 minutes handling this conflict which ends up being absolute nonsense because when you do a commit, the keywords will change yet again.
So, there's little gain in using RCS Keywords when you use Subversion, and a lot of pain if you do use them.
But, what if I am outside of Subversion?
Yes, RCS keywords were used to figure out what version of a file if you were on a client's system. In fact, there's a particular $Id$ string that the RCS ident
command can search for. In fact, there's even a special command called ident
that allows you to quickly see the RCS ID. For example, I want to know the revision used in my /bin/ksh
:
$ ident /bin/ksh
/bin/ksh
$Id: enum (AT&T Research) 2008-01-08 $
$Id: type (AT&T Labs Research) 2008-01-08 $
$Id: type (AT&T Labs Research) 2008-07-01 $
$Id: test (AT&T Research) 2003-03-18 $
$Id: break (AT&T Research) 1999-04-07 $
$Id: continue (AT&T Research) 1999-04-07 $
$Id: alias (AT&T Research) 1999-07-07 $
$Id: builtin (AT&T Research) 2010-08-04 $
$Id: cd (AT&T Research) 1999-06-05 $
$Id: command (AT&T Research) 2003-08-01 $
$Id: (AT&T Research) 2000-04-02 $
$Id: eval (AT&T Research) 1999-07-07 $
$Id: exec (AT&T Research) 1999-07-10 $
$Id: exit (AT&T Research) 1999-07-07 $
$Id: export (AT&T Research) 1999-07-07 $
$Id: getopts (AT&T Research) 2005-01-01 $
$Id: bg (AT&T Research) 2000-04-02 $
$Id: fg (AT&T Research) 2000-04-02 $
$Id: disown (AT&T Research) 2000-04-02 $
$Id: jobs (AT&T Research) 2000-04-02 $
$Id: hist (AT&T Research) 2000-04-02 $
$Id: kill (AT&T Research) 1999-06-17 $
$Id: let (AT&T Research) 2000-04-02 $
$Id: print (AT&T Research) 2008-11-26 $
$Id: printf (AT&T Research) 2009-02-02 $
$Id: pwd (AT&T Research) 1999-06-07 $
$Id: read (AT&T Research) 2006-12-19 $
$Id: readonly (AT&T Research) 2008-06-16 $
$Id: return (AT&T Research) 1999-07-07 $
$Id: sh (AT&T Research) 93u 2011-02-08 $
$Id: set (AT&T Research) 1999-09-28 $
$Id: shift (AT&T Research) 1999-07-07 $
$Id: sleep (AT&T Research) 2009-03-12 $
$Id: trap (AT&T Research) 1999-07-17 $
$Id: typeset (AT&T Research) 2010-12-08 $
$Id: ulimit (AT&T Research) 2003-06-21 $
$Id: umask (AT&T Research) 1999-04-07 $
$Id: unset (AT&T Research) 1999-07-07 $
$Id: unalias (AT&T Research) 1999-07-07 $
$Id: wait (AT&T Research) 1999-06-17 $
$Id: whence (AT&T Research) 2007-04-24 $
$Id: regex (AT&T Research) 2010-09-22 $
$Id: basename (AT&T Research) 2010-05-06 $
$Id: cat (AT&T Research) 2010-04-11 $
$Id: chmod (AT&T Research) 2010-07-28 $
$Id: cmp (AT&T Research) 2010-04-11 $
$Id: cut (AT&T Research) 2010-08-11 $
$Id: dirname (AT&T Research) 2009-01-31 $
$Id: getconf (AT&T Research) 2008-04-24 $
$Id: head (AT&T Research) 2006-09-27 $
$Id: logname (AT&T Research) 1999-04-30 $
$Id: mkdir (AT&T Research) 2010-04-08 $
$Id: sync (AT&T Research) 2006-10-04 $
$Id: uname (AT&T Research) 2007-04-19 $
$Id: wc (AT&T Research) 2009-11-28 $
$Id: Version JM 93u 2011-02-08 $
$Id: libcoshell (AT&T Research) 2010-05-19 $
Yeah, that was helpful...
There are multiple issues:
- A compiled program could be composed of dozens, if not hundreds of individual files. Using the RS keyword in these is not all that helpful as you can see from the above.
- Compiled code my optimize out the ID string.
- Developers have to remember to include it.
- Even if everything works out perfectly, it doesn't tell you the most useful information: What RELEASE am I looking at. A release may be composed of multiple file, programs, configuration files, etc. They interact with each other. Knowing a few RCS keywords doesn't give you much help. You want the official revision number of the entire release and not for individual files.
What you need is a way of generating this official release when you do your compilation or packaging for an official release. In our company, we use Jenkins as our Continuous Integration engine. No release goes out to a customer unless it was built by Jenkins. This includes JavaScript and Perl projects that don't compile.
We create a build file of some sort that is always packaged in our builds. A fairly simple one may look like this:
Jenkins Project: %JOB_NAME%
Jenkins Build: %BUILD_NUMBER%
When Jenkins does a build, it sets the environment variables JOB_NAME
and BUILD_NUMBER
. When I do a build on Jenkins, I have Jenkins copy and filter this file replacing the %...%
place holders with the actual Jenkins job and build: After my Jenkins build, the file will look something like this:
Jenkins Project: foo-3.4
Jenkins Build: 233
This could be a file on my system somewhere, or I could embed it, so it will show up when the user looks at the about box. This traces my package back to an official release. From that official release, I can generate the release notes and see what was changed. I can use tags to go back and fetch the entire project and all of the various files for testing to see what could be causing a bug. That's way more useful than a random Subversion revision number. And, I don't have the disadvantages that RCS Keywords cause in Subversion.
来源:https://stackoverflow.com/questions/19891671/when-does-tortoisesvn-keyword-substitution-occur