[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: Thu, 24 May 2012 09:52:25 +0200

On Thu, May 24, 2012 at 1:57 AM, Alex Siyanko <asiyanko_at_xdyne.com> wrote:
> On 5/23/2012 5:15 PM, Johan Corveleyn wrote:
>>
>> 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)
>>
>
> Hi Johan,
>
> thank you for taking your time to look at this.
> I hope your opinion will help to draw more attention from the development
> team.
>
> The thing is, that the in-house software, that I've developed on top of SVN
> makes heavy use of this feature.
> svn:externals definitions of described type are generated programmatically
> for checking out compound working copies.
> And so far I don't see any other easy way around this issue, then just
> rolling back all clients back to 1.6.x.

Have you tried if the following works?

-r1 ^/A/tags/1.0/file.txt_at_2 file.txt

So using a peg revision combined with the operational revision. It
that works, maybe it could be a workaround?

-- 
Johan
Received on 2012-05-24 09:53:20 CEST

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