自动删除 Subversion 未版本化的文件

有人知道递归删除不受版本控制的工作副本中的所有文件的方法吗?(我需要在自动构建的 VMware 中获得更可靠的结果。)

60261 次浏览

Can you not just do an export to a new location and build from there?

编辑:

Subversion 1.9.0 introduced an option to do this:

svn cleanup --remove-unversioned

在此之前,我使用这个 python 脚本来完成:

import os
import re


def removeall(path):
if not os.path.isdir(path):
os.remove(path)
return
files=os.listdir(path)
for x in files:
fullpath=os.path.join(path, x)
if os.path.isfile(fullpath):
os.remove(fullpath)
elif os.path.isdir(fullpath):
removeall(fullpath)
os.rmdir(path)


unversionedRex = re.compile('^ ?[\?ID] *[1-9 ]*[a-zA-Z]* +(.*)')
for l in  os.popen('svn status --no-ignore -v').readlines():
match = unversionedRex.match(l)
if match: removeall(match.group(1))

它似乎做得很好。

我对 Thomas Watnedals Python 脚本的 C # 转换:

Console.WriteLine("SVN cleaning directory {0}", directory);


Directory.SetCurrentDirectory(directory);


var psi = new ProcessStartInfo("svn.exe", "status --non-interactive");
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.WorkingDirectory = directory;


using (var process = Process.Start(psi))
{
string line = process.StandardOutput.ReadLine();
while (line != null)
{
if (line.Length > 7)
{
if (line[0] == '?')
{
string relativePath = line.Substring(7);
Console.WriteLine(relativePath);


string path = Path.Combine(directory, relativePath);
if (Directory.Exists(path))
{
Directory.Delete(path, true);
}
else if (File.Exists(path))
{
File.Delete(path);
}
}
}
line = process.StandardOutput.ReadLine();
}
}

I couldn't get any of the above to work without additional dependencies I didn't want to have to add to my automated build system on win32. So I put together the following Ant commands - note these require the Ant-contrib JAR to be installed in (I was using version 1.0b3, the latest, with Ant 1.7.0).

注意,这会在没有警告的情况下删除所有未经版本控制的文件。

  <taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
<taskdef name="for" classname="net.sf.antcontrib.logic.ForTask" />


<macrodef name="svnExecToProperty">
<attribute name="params" />
<attribute name="outputProperty" />
<sequential>
<echo message="Executing Subversion command:" />
<echo message="  svn @{params}" />
<exec executable="cmd.exe" failonerror="true"
outputproperty="@{outputProperty}">
<arg line="/c svn @{params}" />
</exec>
</sequential>
</macrodef>


<!-- Deletes all unversioned files without warning from the
basedir and all subfolders -->
<target name="!deleteAllUnversionedFiles">
<svnExecToProperty params="status &quot;${basedir}&quot;"
outputProperty="status" />
<echo message="Deleting any unversioned files:" />
<for list="${status}" param="p" delimiter="&#x0a;" trim="true">
<sequential>
<if>
<matches pattern="\?\s+.*" string="@{p}" />
<then>
<propertyregex property="f" override="true" input="@{p}"
regexp="\?\s+(.*)" select="\1" />
<delete file="${f}" failonerror="true" />
</then>
</if>
</sequential>
</for>
<echo message="Done." />
</target>

对于不同的文件夹,更改 ${basedir}引用。

虽然不是为了自动构建,但是我在寻找同样的事情的时候浏览了这个页面。

经过一点点寻找,我发现在 TortoiseSVN 的“ 扩展上下文菜单”。按住 shift 键,右键单击工作副本。现在在 TortoiseSVN 菜单下有其他选项,包括“ 删除没有版本的项目..。”。

虽然可能不适用于这个特定的问题(即在自动构建的上下文中) ,但我认为它可能对其他想要做同样事情的人有帮助。

For the people that like to do this with perl instead of python, Unix shell, java, etc. Hereby a small perl script that does the jib as well.

注意: 这还会删除所有未版本控制的目录

#!perl


use strict;


sub main()


{


my @unversioned_list = `svn status`;


foreach my $line (@unversioned_list)


{


chomp($line);


#print "STAT: $line\n";


if ($line =~/^\?\s*(.*)$/)


{


#print "Must remove $1\n";


unlink($1);


rmdir($1);


}


}


}


main();

如果您在 Windows 命令行上,

for /f "tokens=2*" %i in ('svn status ^| find "?"') do del %i

改进版:

for /f "usebackq tokens=2*" %i in (`svn status ^| findstr /r "^\?"`) do svn delete --force "%i %j"

如果在批处理文件中使用这个函数,则需要将 %加倍:

for /f "usebackq tokens=2*" %%i in (`svn status ^| findstr /r "^\?"`) do svn delete --force "%%i %%j"

If you are using tortoise svn there is a hidden command to do this. Hold shift whilst right clicking on a folder to launch the context menu in windows explorer. You will get a "Delete Unversioned Items" command.

详细信息请参阅 呼叫的底部,或者下面的屏幕截图,其中用绿色星星突出显示扩展特征,用黄色矩形突出显示感兴趣的特征..。

SVN Extended context menu vs standard menu

If you don't want to write any code, svn2.exe from 你好 does this, also there's 一篇文章 on how it's implemented. Deleted folders and files are put in the recycle bin.

Run "svn2.exe sync [path]".

svn status --no-ignore | awk '/^[I\?]/ {system("echo rm -r " $2)}'

移除回声,如果你确定要这么做的话。

使用 TortoiseSVN: * 右键单击工作拷贝文件夹,同时按住 shift-key * 选择“ delete unversion item”

如何删除工作副本中所有未版本化/忽略的文件/文件夹?

Linux 命令行:

svn status --no-ignore | egrep '^[?I]' | cut -c9- | xargs -d \\n rm -r

Or, if some of your files are owned by root:

svn status --no-ignore | egrep '^[?I]' | cut -c9- | sudo xargs -d \\n rm -r

这是基于 Ken 的回答。(Ken 的回答跳过了被忽略的文件; 我的回答删除了它们)。

我把这个加到了我的 Windows PowerShell 档案里

function svnclean {
svn status | foreach { if($_.StartsWith("?")) { Remove-Item $_.substring(8) -Verbose } }
}

Might as well contribute another option

svn status | awk '{if($2 !~ /(config|\.ini)/ && !system("test -e \"" $2 "\"")) {print $2; system("rm -Rf \"" $2 "\"");}}'

/(config | . ini)/用于我自己的目的。

也许应该在 svn 命令中添加—— no-annon

我在 RH5机器上偶然发现了 svn-clean,它位于/usr/bin/svn-clean

Http://svn.apache.org/repos/asf/subversion/trunk/contrib/client-side/svn-clean

Pure windows cmd/bat solution:

@echo off


svn cleanup .
svn revert -R .
For /f "tokens=1,2" %%A in ('svn status --no-ignore') Do (
If [%%A]==[?] ( Call :UniDelete %%B
) Else If [%%A]==[I] Call :UniDelete %%B
)
svn update .
goto :eof


:UniDelete delete file/dir
if "%1"=="%~nx0" goto :eof
IF EXIST "%1\*" (
RD /S /Q "%1"
) Else (
If EXIST "%1" DEL /S /F /Q "%1"
)
goto :eof

既然大家都这么做了。

svn status | grep ^? | awk '{print $2}' | sed 's/^/.\//g' | xargs rm -R

只要在 unix-shell 上使用:

rm -rf `svn st . | grep "^?" | cut -f2-9 -d' '`

在 PERL 中完成这项工作的简单方法是:

#!/usr/bin/perl
use IO::CaptureOutput 'capture_exec'


my $command = sprintf ("svn status --no-ignore | grep '^?' | sed -n 's/^\?//p'");


my ( $stdout, $stderr, $success, $exit_code ) = capture_exec ( $command );
my @listOfFiles = split ( ' ', $stdout );


foreach my $file ( @listOfFiles )
{ # foreach ()
$command = sprintf ("rm -rf %s", $file);
( $stdout, $stderr, $success, $exit_code ) = capture_exec ( $command );
} # foreach ()

我试过 这个答案Seth Reno 的版本,但是没有用。我在文件名之前有8个字符,而不是在 cut -c9-中使用的9个字符。

So this is my version with sed instead of cut:

svn status | grep ^\? | sed -e 's/\?\s*//g' | xargs -d \\n rm -r

我用了大约3个小时来生成这个,在 Unix 中需要5分钟。 主要问题是: Win 文件夹名称中的空格、不可能编辑% i 以及在 Win cmd 循环中定义变量的问题。

setlocal enabledelayedexpansion


for /f "skip=1 tokens=2* delims==" %%i in ('svn status --no-ignore --xml ^| findstr /r "path"') do (
@set j=%%i
@rd /s /q !j:~0,-1!
)
svn st --no-ignore  | grep '^[?I]' | sed 's/^[?I]  *//' | xargs -r -d '\n' rm -r

这是一个 unixshell 命令,用于删除不受 subversion 控制的所有文件。

Notes:

  • svn st中的 ststatus的内置别名,即该命令等效于 svn status
  • --no-ignore在状态输出中也包含非存储库文件,否则通过像 .cvsignore等机制忽略-因为目标是有一个干净的构建起点,所以这个切换是必须的
  • grep对输出进行过滤,以便只留下不知道 subversion 的文件——从 ?开始的行列出不知道 subversion 的文件,如果没有 --no-ignore选项,这些文件将被忽略
  • the prefix up to the filename is remove via sed
  • 当参数列表为空时,通过 -r指示 xargs命令不执行 rm
  • -d '\n'选项告诉 xargs使用换行符作为分隔符,这样的命令也适用于带空格的文件名
  • 如果需要删除完整的目录(不属于存储库的一部分) ,则使用 rm -r

上面的 C # 代码片段对我来说不起作用-我有 tortoise svn 客户端,行的格式稍有不同。下面是与上面相同的代码片段,只是重写为函数并使用正则表达式。

        /// <summary>
/// Cleans up svn folder by removing non committed files and folders.
/// </summary>
void CleanSvnFolder( string folder )
{
Directory.SetCurrentDirectory(folder);


var psi = new ProcessStartInfo("svn.exe", "status --non-interactive");
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.WorkingDirectory = folder;
psi.CreateNoWindow = true;


using (var process = Process.Start(psi))
{
string line = process.StandardOutput.ReadLine();
while (line != null)
{
var m = Regex.Match(line, "\\? +(.*)");


if( m.Groups.Count >= 2 )
{
string relativePath = m.Groups[1].ToString();


string path = Path.Combine(folder, relativePath);
if (Directory.Exists(path))
{
Directory.Delete(path, true);
}
else if (File.Exists(path))
{
File.Delete(path);
}
}
line = process.StandardOutput.ReadLine();
}
}
} //CleanSvnFolder

If you're cool with powershell:

svn status --no-ignore | ?{$_.SubString(0,1).Equals("?")} | foreach { remove-item -Path (join-Path .\ $_.Replace("?","").Trim()) -WhatIf }

删除-WhatIf 标志,使命令实际执行删除操作。否则,如果不使用-WhatIf 运行,它只会输出 所做的事情。

对于那些想要避免使用除了标准 MS-Dos 命令之外的任何工具的 Windows 用户,这里有一个解决方案:

FOR /F "tokens=1* delims= " %G IN ('svn st ^| findstr "^?"') DO rd /s /q "%H"

FOR /F "tokens=1* delims= " %G IN ('svn st ^| findstr "^?"') DO del /s /f /q "%H"

  • Svnst 将显示工作副本中每个文件和文件夹的状态
  • Findstr 将查找以“ ?”开头的每一行,这意味着文件/文件夹没有版本控制
  • FOR 将用作分隔符,并在第一个之后获取标记(第一个是% G,其余的是% H) 这样,我们就可以从 svn st 命令输出中提取文件/文件夹。
  • Rd 会删除文件夹,del 会删除文件。

如果路径上有 TortoiseSVN,并且位于正确的目录中:

TortoiseProc.exe /command:cleanup /path:"%CD%" /delunversioned /delignored /nodlg /noui

The options are described in the TortoiseSVN help for /command:cleanup:

使用/nui 可以防止弹出结果对话框 要么告诉清理正在完成,要么显示错误 message). /noprogressui also disables the progress dialog. /nodlg disables showing the cleanup dialog where the user can choose what 应该在清理过程中完成。可用的操作可以是 在状态清理/清理/恢复选项中指定, /解除版本控制(delunversion)、/忽略、/刷新 shell 和/外部。

我想把这个作为一个评论添加到 Thomas Watnedal's answer ,但还不能。

它的一个小问题(不会影响 Windows)是它只检查文件或目录。对于像 Unix 这样可能存在符号链接的系统,有必要改变行:

if os.path.isfile(fullpath):

if os.path.isfile(fullpath) or os.path.islink(fullpath):

也删除链接。

对于我来说,将最后一行 if match: removeall(match.group(1))改为

    if match:
print "Removing " + match.group(1)
removeall(match.group(1))

所以它显示什么是删除也是有用的。

根据用例的不同,正则表达式的 ?[\?ID]部分作为 ?[\?I]可能会更好,因为 D还会删除已删除的文件,这些文件处于版本控制之下。我想用这个来建立一个干净的,签入文件夹,所以应该没有文件在 D的状态。

我还发现并使用了以下内容: Svn status —— no-annon | awk’/^ ?/{ print $2}’| xargs rm

@ zhoufei 我测试了你的答案,这里是最新版本:

FOR /F "tokens=1* delims= " %%G IN ('svn st %~1 ^| findstr "^?"') DO del /s /f /q "%%H"
FOR /F "tokens=1* delims= " %%G IN ('svn st %~1 ^| findstr "^?"') DO rd /s /q "%%H"
  • You must use two % marks in front of G and H
  • 切换顺序: 首先删除所有文件,然后删除所有目录
  • (可选:)代替 %~1可以使用任何目录名,我在 bat 文件中使用这个函数,所以 %~1是第一个输入参数

Subversion 1.9.0 introduced option to remove unversioned items [1]

svn cleanup --remove-unversioned

[1] https://subversion.apache.org/docs/release-notes/1.9.html#svn-cleanup-options