On 5/21/2012 1:45 PM, Johan Corveleyn wrote:
> On Sat, May 19, 2012 at 5:59 PM, Alex Siyanko<asiyanko_at_xdyne.com> wrote:
>> Hello,
>>
>> I've stumbled upon the following Subversion client 1.7.x bug:
>>
>> Under certain conditions SVN silently fails to fetch external file at
>> specified operative revision from repository into a working copy.
>> Here is the simplest scenario:
>>
>> 1) I create 'file.txt' and commit it to repository 'A/trunk' directory;
>> 2) then I copy entire 'A/trunk' directory to 'A/tags/1.0' using 'svn copy
>> URL URL' command;
>> 3) next I create 'B' directory in the repository with one empty 'import'
>> subdirectory, which I want to use for importing 'A/tags/1.0/file.txt' via
>> svn:externals;
>> 4) to use explicit revision number in svn:externals property I run 'svn
>> list A/tags/1.0/file.txt -v' command, which gives me the last revision, at
>> which file.txt was modified (say, revision 1).
>> 5) now I checkout 'B' into a working copy and set svn:externals property
>> over 'import' subdirectory as follows: ' -r1 ^/A/tags/1.0/file.txt
>> file.txt'
>> 6) finally I update 'B' working copy, which should fetch file.txt into
>> import directory; unfortunately, that doesn't happen - 'import' directory
>> remains empty, though svn reports no errors
>>
>> It is important to note, that this bug is not present in any SVN 1.6.x
>> client. It only manifests itself in SVN 1.7.x (up to its latest version
>> 1.7.5)
>> I tested it on Windows and Linux platforms using both pre-compiled version
>> of svn client, which comes with TortoiseSVN, as well as svn client, compiled
>> and installed from tar.
>> Also I tried to use both svn:// (with svnserve of 1.6.x and 1.7.x versions)
>> and file:// access methods.
>> The result doesn't depend on the access method, neither it depends on the
>> version of the svnserve at the backend (in case of svn:// method ), so it is
>> an svn client 1.7.x issue.
>>
>> Here is the script to reproduce the described bug:
>> ##############################################################################################################
>> #!/bin/sh
>>
>> # You might need to adjust these lines to point to your
>> # compiled-from-source Subversion binaries, if using those:
>> if [ -z "$SVN" ]; then
>> SVN=`which svn`
>> SVNADMIN=`which svnadmin`
>> fi
>>
>> # Use English output.
>> LC_ALL=C; export LC_ALL
>>
>> # Select an access method. If svn://, the svnserve setup is
>> # handled automagically by this script; but if http://, then
>> # you'll have to configure it yourself first.
>> #
>> # URL=http://localhost/SOMETHING/repos
>> # URL=svn://localhost/repos
>> URL=file:///`pwd`/repos
>>
>> ${SVNADMIN} create repos
>>
>> echo "### Making a Greek Tree for import..."
>> mkdir import-me
>> mkdir import-me/A
>> mkdir import-me/A/trunk
>> mkdir import-me/A/tags
>> mkdir import-me/B
>> mkdir import-me/B/trunk
>> mkdir import-me/B/trunk/import
>> echo "This is the file 'file.txt'"> import-me/A/trunk/file.txt
>> echo "### Done."
>> echo ""
>> echo "### Importing it..."
>> (cd import-me; ${SVN} import -q -m "Initial import." ${URL})
>> echo "### Done."
>> echo ""
>>
>> echo "### copy A/trunk to A/tags/1.0 ###"
>> ${SVN} cp ${URL}/A/trunk ${URL}/A/tags/1.0 -m 'make 1.0 release of project
>> A'
>> revision=`${SVN} ls ${URL}/A/tags/1.0/file.txt -v| grep -P -o '^\s+\d+' |
>> grep -P -o '\d+'`
>> echo "### 'A/tags/1.0/file.txt' Last Commit Revision: $revision ###"
>>
>> echo "### checkout B/trunk to wc ###"
>> ${SVN} co ${URL}/B/trunk wc
>> cd wc
>>
>> echo "### set svn:externals property over B/trunk/import to: ' -r$revision
>> ^/A/tags/1.0/file.txt file.txt' ###"
>> ${SVN} propset svn:externals " -r$revision ^/A/tags/1.0/file.txt file.txt"
>> import
>>
>> echo "### update B/trunk working copy ###"
>> ${SVN} update
>>
>> echo "### list updated B/trunk wc contents ###"
>> ls -R
>> ##############################################################################################################
>>
>>
>> The above script renders following output:
>> --------------------------------------------------------------------------------------
>> ### Making a Greek Tree for import...
>> ### Done.
>>
>> ### Importing it...
>> ### Done.
>>
>> ### copy A/trunk to A/tags/1.0 ###
>>
>> Committed revision 2.
>> ### 'A/tags/1.0/file.txt' Last Commit Revision: 1 ###
>> ### checkout B/trunk to wc ###
>> A wc/import
>> Checked out revision 2.
>> ### set svn:externals property over B/trunk/import to: ' -r1
>> ^/A/tags/1.0/file.txt file.txt' ###
>> property 'svn:externals' set on 'import'
>> ### update B/trunk working copy ###
>> Updating '.':
>>
>> Fetching external item into 'import/file.txt':
>> External at revision 1.
>>
>> At revision 2.
>> ### list updated B/trunk wc contents ###
>> .:
>> import
>>
>> ./import:
>> --------------------------------------------------------------------------------------
>>
>> The 'wc/import' directory is empty after update, when svn 1.7.x is used.
>> Again, that doesn't happen with svn 1.6.x.
> Thanks for the very detailed report, with reproduction script.
>
> However, I'm not sure if there is a bug here, and if there is, exactly
> what the bug is ...
>
> The problem is that ^/A/tags/1.0/file.txt does not yet exist in r1. It
> only appears after the copy, in r2. So I think you'd need "-r2
> ^/A/tags/1.0/file.txt file.txt", or using peg revisions would be even
> better: "^/A/tags/1.0/file.txt_at_2 file.txt"
>
> So "externals" isn't really at fault here. Apparently the "Last
> changed revision" of ^/A/tags/1.0/file.txt is r1, the last revision in
> which the file has changed (not the revision of the copy). I.e. "Last
> changed revision" doesn't consider copies. I _think_ that's known and
> desired behavior, which has always been that way. So I'm surprised
> that this did work in 1.6, like you say. Has the behavior of 'svn
> status' changed here?
>
Hi Johan and thank you for prompt reply. Nevertheless I don't agree
with your reasoning.
Let me give my point of view on this.
I believe that svn:externals feature, when used with operative revision
(not peg revision, this is important!)
should work the same way as other svn commands, such as for example
'cat' or 'co'.
In other words, when operative revision is used in svn:externals, it
should cross copy command boundary.
Getting back to my example, here is the question. Why then, if I, for
example, run:
svn cat -r 1 file:///`pwd`/repos/A/tags/1.0/file.txt
or
svn co -r 1 file:///`pwd`/repos/A/tags/1.0 tags-checkout
subversion happily prints file.txt contents or downloads it to a working
copy.
This happens because it is able to cross copy command boundary. BTW,
this works fine both in 1.6.x and 1.7.x.
And this is the behavior, which is described in the Red Book "The Peg
Revision Algorithm" section.
Namely, it says:
----------------------------------------------------------------------------------------------------------------
The Subversion command-line client performs the peg revision algorithm
any time it needs to resolve possible ambiguities in the paths and
revisions provided to it. Here's an example of such an invocation:
$ svn/|command|/ -r/|OPERATIVE-REV|/ item@/|PEG-REV|/
If /|OPERATIVE-REV|/ is older than /|PEG-REV|/, the algorithm is as follows:
1.
Locate /|item|/ in the revision identified by /|PEG-REV|/. There can
be only one such object.
2.
Trace the object's history backwards (through any possible renames)
to its ancestor in the revision /|OPERATIVE-REV|/.
3.
Perform the requested action on that ancestor, wherever it is
located, or whatever its name might be or might have been at that time.
----------------------------------------------------------------------------------------------------------------
Please pay attention to "through any possible renames" phrase in item 2.
So, I expect, that svn: externals rule, which uses operative revision,
should have identical behavior.
And, in fact, it does in 1.6.x. Also note, that 1.7.x "kind of has" it.
If you take a look at the output of the script, you'll see the following
lines:
Fetching external item into 'import/file.txt':
External at revision 1.
Which tells me, that file.txt has been successfully fetched - there are
no error messages.
The thing is that it didn't really happen.
So this looks like a definite bug to me.
I agree, that "file:///`pwd`/repos/A/tags/1.0/file.txt" doesn't exist at
revision 1.
Therefore, if I use the rule with peg revision in place of operative:
^/A/tags/1.0/file.txt_at_1 file.txt
svn responds with 'path not found' message, which, of course, is
expected behavior.
But if I use operative revision, svn must cross copy command boundaries
according to official documentation.
Am I right or not?
Please let me know your opinion.
Regards,
Alex Siyanko
--
Alex Siyanko<br>
as_at_xdyne.com
Received on 2012-05-21 14:42:09 CEST