Uploaded image for project: 'Subversion'
  1. Subversion
  2. SVN-4185

SVN client silently fails to fetch external file ancestor specified in svn:externals file definition via operative revision

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Blocker
    • Resolution: Fixed
    • 1.7.x
    • 1.8.0
    • cmdline client
    • None

    Description

      Consider the following simple scenario, which used to work in svn 1.6.x, but
      doesn't work in 1.7.x:
      
      1) create 'file.txt' and commit it to repository 'A/trunk' directory;
      2) copy entire 'A/trunk' directory to 'A/tags/1.0' using 'svn
      copy URL URL' command;
      3) create 'B/trunk' directory in the repository with one empty 'import'
      subdirectory, which will be used for importing 'A/tags/1.0/file.txt'
      via svn:externals;
      4) get last revision, at which file.txt was modified via 'svn list
      A/tags/1.0/file.txt -v' command (say revision 1);
      5) checkout 'B/trunk' into a working copy and set svn:externals property
      over 'import' subdirectory to: ' -r1 ^/A/tags/1.0/file.txt file.txt';
      6) finally, update 'B' working copy, which should fetch file.txt into
      'import' WC directory;
      
      Step 6 of the above scenario silently fails in 1.7.x, i.e. subversion reports,
      that file.txt has been fetched at revision 1, but 'import' directory in WC
      remains empty.
      
      One may think, that this looks like desired behavior, because
      ^/A/tags/1.0/file.txt does not exist at revision 1 and therefore I should either use
      
      ' -r2 ^/A/tags/1.0/file.txt file.txt'
      
      or 
      
      ' -r1 ^/A/trunk/file.txt file.txt'
      
      to get things done. But this is not the point here.
      
      I believe, that semantics of operative revision must be the same regardless of
      where it is used - either in svn commands or svn:externals definitions.
      
      This semantics is described in the Subversion 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.
      
      ------------------------------------------------------------------------------ 
      
      Getting back to my example. When I 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. 
      
      So, I expect, that svn:externals definition, which uses operative revision,
      should have identical behavior.
      And, in fact, it does in 1.6.x. Also note, that 1.7.x sort of has it.
      During WC update svn 1.7.x client provides the following output:
      
      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 here. But there is no file.txt in WC after update either.
      So this looks like a definite bug to me. 
      
      I've posted this issue to users mailing list:
      http://svn.haxx.se/users/archive-2012-05/0226.shtml
      
      I also had the following chat conversation with @stsp in order to confirm my
      point of view:
      ------------------------------------------------------------------------
      [20:36] <alex_siyanko> hello, I'm looking for a "buddy" to confirm a bug in
      1.7.x svn client. I posted bug report here:
      http://svn.haxx.se/users/archive-2012-05/0226.shtml but I'm not sure that I was
      heard and don't know what to do next.
      [20:45] <@stsp> alex_siyanko, i read that and i'm unsure about how we want
      externals to behave
      [20:45] <@stsp> but i see your point
      [20:45] <@stsp> if you like, you can file an issue that tracks further discussion
      [20:45] <@stsp> note that changing existing behavior might not be possible due
      to backwards compat rules
      [20:48] <alex_siyanko> well, in my last (3rd) email I think I explained it very
      clearly. I believe that when svn:externals rule is used with operative revision
      over a file, it must cross any copy/rename boundaries, as it used to be in 1.6.x
      and is described in the red book.
      [20:50] <alex_siyanko> in any case current behavior is kind of inconsistent -
      subversion neither responds with  'path not found' error nor it fetches the file
      into a WC
      [20:51] <@stsp> i agree and that is not the question
      [20:51] <@stsp> the question is whether changing the existing behavior would
      have any undesired side effects in existing setups
      [20:51] <@stsp> it's just something we need to consider
      [20:53] <@stsp> and yes, if 1.6.x used to do this then it is a regression of course
      [20:53] <@stsp> so please file an issue for this if you can, and quote me as
      your bug buddy
      [20:53] <@stsp> thanks!
      ------------------------------------------------------------------------
      
      
      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
      -----------------------------------------------------------------------------
      
      And here the output from the above script:
      
      -----------------------------------------------------------------------------
      ### 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:
      -----------------------------------------------------------------------------
      
      Sincerely, Alex Siyanko
      

      Original issue reported by alex_siyanko

      Attachments

        Activity

          People

            Unassigned Unassigned
            subversion-importer Subversion Importer
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: