On Mon, May 21, 2012 at 2:41 PM, Alex Siyanko <asiya...@xdyne.com> wrote: > On 5/21/2012 1:45 PM, Johan Corveleyn wrote: > > On Sat, May 19, 2012 at 5:59 PM, Alex Siyanko <asiya...@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@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: > > 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@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