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

RE: Re: question relating SVN file/directory merges and tree conflicts

From: Thomas S. Trias <tomtrias_at_artizan.com>
Date: Wed, 22 Jul 2009 10:36:47 -0700 (PDT)

FYI, I had to quote this by hand, since the web interface doesn't like the message as a text attachment.

On Wed, Jul 22, 2009 at 7:57:04 AM -0700, Stefan Sperling wrote:
> On Wed, Jul 22, 2009 at 10:28:04AM -0400, Bob Archer wrote:
> > Although figuring out how to populate this info
> > during the upgrade is problematic. Perhaps some type of --record-only
> > feature like you have for merge data so that I can specify the
> > move/rename ancestry of various objects manually.
>
> You can easily reconstruct move information today.
> It's just computationally expensive to get at it, because
> Subversion only provides copy information in one direction.
> This also hurts applications such as revision graphing.
>
> You can reconstruct move information by following all copyfrom paths
> in the repository backwards to their origin, and then inverting that
> relation. This is how e.g. trumerge tracks renames
> (http://trumerge.open.collab.net).

This is actually the approach I took in the merge script I wrote in PowerShell; I could probably optimize it now, since it looks like 1.6 will take hints from the mergeinfo on how to apply changes - once you've done the hand merge from old location to new location once, I think 1.6 will use that to guide future merges.

Given the merge source and a target that was copied from the source, one can get a list of copies descending by revision, filter it by relevance, and replace portions of the URL's to get back to the original target; I would then run the results through a one-liner that would apply the merge(s) (which I may turn into a function some day :-). Also, I noticed that the --stop-on-copy isn't ideal if one has had to resurrect a branch, so I leave it as an exercise to the reader to pass in the merge source and / or a base revision and filter the copies appropriately.

--- Legal Stuff ---
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
--- End Legal Stuff ---

function Get-SVNBranchCopy ([switch] $InputObject = $false, $io = $null) {
  begin {
    if ($io -ne $null) {
      Write-Output $io | &($MyInvocation.InvocationName)
      break
    }
  }

  process {
    function MakeEntry ([string] $source, [string] $dest, [int] $rev) {
      $e = New-Object Object
      $e | Add-Member NoteProperty 'Source' $source
      $e | Add-Member NoteProperty 'Dest' $dest
      $e | Add-Member NoteProperty 'Rev' $rev
      $e
    }

    $path = Resolve-Path $_ 2> $null
    if ($path -eq $null -or $path.provider.name -ne "FileSystem") {
      return $null
    }
    $path = $path.Path

    # svn info is a cheap operation on a WC - it uses the local filesystem
    # svn list and svn log go back to the repository

    $root = ([xml] (svn info --xml $path)).info.entry.repository.root
    $results = @()

    ([xml] (svn log -r 1:HEAD --xml --stop-on-copy -q -v $path)).log.logentry |
      % { $rev = [int] $_.revision; $_.paths.path } |
      ? { $_.'copyfrom-path' -ne $null } |
      % {
          $e = MakeEntry ($_.'copyfrom-path') ($_.'#text') $rev
          $i = $results.length

# Write-Host '----- before -----'
# Write-Host ('[' + $e.Source + "]`n[" + $e.Dest + ']')

          if ($i -gt 0) {
            # Destination has to be in the destination path we care about - moving something outside the branch is just like deleting it
            if (-not (($e.Dest -ceq $results[0].Dest) -or $e.Dest.StartsWith($results[0].Dest + '/', $false, $null))) {
              return
            }

            $destpath = $path + $e.Dest.Substring($results[0].Dest.length).Replace('/', '\')

            # Apply substitutions
            do {
              $s = $results[$i--]
              if ($e.Source -ceq $s.Dest) {
                $e.Source = $s.Source
              } elseif ($e.Source.StartsWith($s.Dest + '/', $false, $null)) {
                $e.Source = $s.Source + $e.Source.Substring($s.Dest.length)
              }
            } until ($i -lt 0)
          } else {
            $destpath = $path
          }

          # Include Destination turned back into a path
          $e | Add-Member NoteProperty 'DestPath' $destpath

# Write-Host '----- after -----'
# Write-Host ('[' + $e.Source + "]`n[" + $e.Dest + "]`n[" + $e.DestPath + ']')

          $results += $e
      }

    $results
  }
}

$repo = 'svn://SVNSERVER/Repo'
$source = '/trunk'
Get-SVNBranchCopy branch_wc | ? {
  ($_.Source -ceq $source) -or
  $_.Source.StartsWith($source + '/', $false, $null)
} | % {
  Write-Host ("$([System.DateTime]::Now.ToString())`t[" + $_.Source + '] -> [' + $_.DestPath + ']');
  Write-Output ("`n[" + $_.Source + '] -> [' + $_.DestPath + ']');
  svn merge --non-interactive ($repo + $_.Source) ($_.DestPath) 2>&1
} > ..\merge_out.txt 2>&1

Hope someone finds this useful,

-- 
Thomas S. Trias
Senior Developer
Artizan Internet Services
http://www.artizan.com/
------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=1065&dsMessageId=2374512
To unsubscribe from this discussion, e-mail: [users-unsubscribe_at_subversion.tigris.org].
Received on 2009-07-22 19:37:54 CEST

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

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.