如何在svn中找到文件的所有副本?

时间:2016-09-12 07:14:20

标签: svn

是否有一种简单的方法可以在存在特定文件的svn存储库中找到所有路径(标签和分支)?

我知道在trunk上检查文件的版本以及删除时的文件,所以我需要在这两个版本之间找到文件上方的所有分支,标签和可能的其他路径副本。

1 个答案:

答案 0 :(得分:2)

我最终在powershell中处理整个日志:

$repository = 'http://REPOSITORY/url'
$badPaths = @( '/paths/to/first/commit/of/files/to/track' )
function Delete-Nodes
{
    param([xml]$xml, [string]$xpath)
    $nodes = $xml.SelectNodes($xpath);

    for ($i = $nodes.Count -1; $i -ge 0; $i--)
    {
        $nodes[$i].ParentNode.RemoveChild($nodes[$i]) *>$null
    }
}

[Console]::OutputEncoding = New-Object -typename System.Text.UTF8Encoding
Measure-Command { [xml]$all_revs = svn log $repository -r1:HEAD -v --xml }

$all_revs.SelectNodes('//logentry').Count
$badPathXpath=[string]::Join(' or ', ($badPaths | % { "text()='$_'" }))

Delete-Nodes -xml $all_revs -xpath "//path[@action='M']"
Delete-Nodes -xml $all_revs -xpath "//path[@action='A' and not($badPathXpath) and not(@copyfrom-path)]" # For additions we only care about our bad paths or any copies (from those)
Delete-Nodes -xml $all_revs -xpath "/log/logentry/paths[not(descendant::path)]"
Delete-Nodes -xml $all_revs -xpath "/log/logentry[not(descendant::paths)]"

$monitoredPaths = @{}

foreach ($logentry in $all_revs.log.logentry)
{
    foreach ($path in $logentry.paths.path)
    {
        $used = $true
        $action = $path.action
        $from_path = $path.Attributes['copyfrom-path'].Value
        $from_rev = $path.Attributes['copyfrom-rev'].Value
        $revision = $logentry.revision
        $value = $path.InnerText

        if ($action -eq 'A' -and -not $from_path)
        {            
            if (($badPaths | % { $value.StartsWith($_) } | Where { $_ } ).Count -gt 0)
            {
                $monitoredPaths[$value] = New-Object PSObject -Property (@{ 'Added' = $revision; 'Deleted' = $null })
            }
            else
            {
                $used = $false
            }
        }
        elseif ($monitoredPaths.Count -gt 0 -and $from_path -and -not $monitoredPaths.ContainsKey($value))
        {
            $paths = $monitoredPaths.Keys | Where-Object { $val = $monitoredPaths[$_]; ($from_path -eq $_ -or $_.StartsWith("$from_path/") -or $from_path.StartsWith("$_/")) -and ($from_rev -ge $val.Added -and (-not $val.Deleted -or $val.Deleted -gt $from_rev) ) }
            if ($paths.Count -gt 0)
            {
                foreach ($copied_path in $paths)
                {
                    if ($copied_path.StartsWith("$from_path/"))
                    {
                        $sub_directory = $copied_path.SubString($from_path.Length)
                        $newPath = "$value$sub_directory"
                    }
                    else
                    {
                        $newPath = "$value"
                    }

                    if (($monitoredPaths.Keys | Where-Object { $newPath.StartsWith("$_/") -and -not $monitoredPaths[$_].Deleted }).Count -eq 0)
                    {
                        $monitoredPaths[$newPath] = New-Object PSObject -Property (@{ 'Added' = $revision; 'Deleted' = $null })
                    }
                    else
                    {
                        $used = $false
                    }
                }
            }
            else
            {
                $used = $false  
            }
        }
        elseif ($action -eq 'D' -and $monitoredPaths.ContainsKey($value))
        {
            $monitoredPaths[$value].Deleted = $revision
        }
        elseif ($action -eq 'D')
        {
            $used = $false
            foreach ($path in ($monitoredPaths.Keys | Where-Object { $_.StartsWith("$value/") -and -not $monitoredPaths[$_].Deleted }))
            {
                $monitoredPaths[$path].Deleted = $revision
                $used = $true
            }
        }
        else
        {
            $used = $false
        }

        if (-not $used)
        {
            $logentry.paths.RemoveChild($path) *>$null
        }
    }
}