[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: bug report: svn client 1.7.x silently fails to fetch files via svn:externals under certain conditions.

From: Johan Corveleyn <jcorvel_at_gmail.com>
Date: Wed, 23 May 2012 16:15:16 +0200

On Mon, May 21, 2012 at 2:41 PM, Alex Siyanko <asiyanko_at_xdyne.com> wrote:
> 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_at_PEG-REV
>
> If OPERATIVE-REV is older than PEG-REV, the algorithm is as follows:
>
> Locate item in the revision identified by PEG-REV. There can be only one
> such object.
>
> Trace the object's history backwards (through any possible renames) to its
> ancestor in the revision OPERATIVE-REV.
>
> 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.

Sorry for the late response (I got sidetracked by other things). But I
believe you're right. There is definitely something fishy here, or at
least I don't know what the expected behavior should be.

I see that you've filed an issue in the meantime (after confirming
with stsp on irc). Hopefully someone can look into this a bit more in
some not-too-distant future.

For completeness of the archives, this is the issue:

http://subversion.tigris.org/issues/show_bug.cgi?id=4185 (SVN client
silently fails to fetch external file ancestor specified in
svn:externals file definition via operative revision)

-- 
Johan
Received on 2012-05-23 16:16:08 CEST

This is an archived mail posted to the Subversion Users mailing list.