自动删除Subversion未版本控制的文件


111

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


7
我是SVN用户,一直在将Git与SVN进行比较,以查看最终是否要进行切换。看起来这可能是Git的“ git clean”命令大放异彩的另一个示例。
jpierson


stackoverflow.com/questions/2803823 / ...重复,那里有很多有用的活动。
Heath Raftery

Answers:


26

编辑:

Subversion 1.9.0引入了执行此操作的选项:

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))

看来做得很好。


1
仍适用于Python 2.7.2。沃伦(Warren):您可以提供更多详细信息吗?
Thomas Watnedal 2014年

我认为这只是Python 2.6的问题。在2.7中再次为我工作。
沃伦·P

1
Downvote:波纹管的另一种解决方案svn cleanup --remove-unversioned更好。它适用于Subversion 1.9.0(此版本来自2015年)。它是稳定和标准的。
tres.14159

138

这对我来说很有效:

 svn status | egrep '^\?' | cut -c8- | xargs rm

塞思·里诺Seth Reno)更好:

svn status | grep ^\? | cut -c9- | xargs -d \\n rm -r 

它处理未版本控制的文件夹和文件名中的空格

根据下面的评论,这仅适用于Subversion未知的文件(status =?)。凡是颠覆知道(包括忽略的文件/文件夹)不会被删除。

如果您使用的是Subversion 1.9或更高版本,则可以简单地将svn cleanup命令与--remove-unversioned和--remove-ignored选项一起使用


6
也可以在Windows中的cygwin中使用。
Honza

9
对于带有空格的文件名,您可以考虑将-d选项添加到xargs中,对于任何添加的目录,可以考虑将-r选项添加到rm中:svn status | grep ^ \?| 切-c9- | xargs -d \\ n rm -r
Seth Reno

4
我也有在OS X上运行-d选项的问题,我的选择如下,将换行符转换为null字符,并在xargs上使用-0选项来处理文件名中的空格:svn status | grep ^ \?| 切-c9- | tr'\ n''\ 0'| xargs -0 rm
Brian Webster

3
如果您svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r
不赞成

3
@Pavel看看xargs --no-run-if-empty选项
Ken Ken

71

尽管没有进行自动构建,但我在尝试执行相同操作时浏览了该页面。

经过一番寻找之后,我在TortoiseSVN中发现了“ 扩展上下文菜单 ”。按住Shift键,然后右键单击工作副本。现在,TortoiseSVN菜单下还有其他选项,包括“ 删除未版本化的项目... ”。

尽管可能不适用于该特定问题(例如,在自动构建的范围内),但我认为这可能对其他希望做同样事情的人有所帮助。


大!在XP上,它仅适用于列表视图(资源管理器的右侧),而不适用于树形视图(左侧)。
Christopher Oezbek,2010年

太棒了,仅将其发送到回收站,可以直接删除。正是我所需要的。
迪恩·托马斯

您也可以使用TortoiseSVN的TortoiseProc.exe在命令行上自动执行此操作:有关详细信息,请参见下面的答案。
stevek_mcc


9

如果您使用的是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"

1
这对我有用。似乎使某些未版本控制的文件夹阻塞。
jpierson 2010年

7

我将此添加到我的Windows Powershell配置文件

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

2
@FelipeAlvarez是的。是的,我们愿意。自切成薄片以来,这不是最伟大的事情,但胜过批次。我想说它至少和bash一样有用,也许更多,因为您可以引入.NET程序集。
jpmc26 2014年

它遭受了Microsoft冗长的令人讨厌的趋势的困扰(不仅在命令名称长度方面,而且在没有从互联网上复制大量代码片段的情况下根本无法完成任何事情),但它令人震惊地有用,并且经过深思熟虑。
沃伦·P

1
您可能要添加--no-ignoresvn status,并-RecurseRemove-Item
凯文·史密斯

5

Linux命令行:

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

或者,如果您的某些文件是由root拥有的:

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

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


5

只需在unix-shell上执行以下操作:

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

如果要删除的文件数超过命令行参数的最大数,则此方法不起作用。另请参见基于xargs的答案。
maxschlepzig 2014年

4

您不仅可以导出到新位置并从那里开始构建吗?


1
对于自动化构建,我希望进行干净导出。
g。

1
理想情况下,您可以执行此操作,但是如果您的结帐很大,就会出现问题。这可能是OP要求的原因:缩短构建时间。
jpmc26 2014年

4

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

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

TortoiseSVN帮助中描述了以下选项/command:cleanup

使用/ noui阻止弹出结果对话框,告知您清理已完成或显示错误消息。/ noprogressui也禁用进度对话框。/ nodlg禁用显示清理对话框,用户可以在其中选择在清理中应该执行的操作。可以使用选项/ cleanup来指定可用的操作,以进行状态清除,/ revert,/ delunversioned,/ delignored,/ refreshshell和/ externals。


4

如果您使用的是svn乌龟,则有一个隐藏的命令可以执行此操作。按住shift键的同时右键单击文件夹以在Windows资源管理器中启动上下文菜单。您将获得“删除未版本化的项目”命令。

有关详细信息,请参见此页面底部;下面的屏幕截图以绿色的星星突出显示了扩展功能,而黄色的矩形突出显示了您感兴趣的功能...

SVN扩展上下文菜单与标准菜单



3

我对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();
    }
}

我宁愿移动未版本控制的文件,以防万一以后需要它们。
嬉皮

当然,在开发机器上-但是在构建VMware中,这没有任何意义,因为没有人登录到该机器并创建文件。
Stefan Schultze,

谢谢,我将此作为我的
CruiseBuild

根据您的代码开始,并且走得更远:github.com/tgmayfield/svn-clean-sharp/downloads
Tom Mayfield

3
svn st --no-ignore  | grep '^[?I]' | sed 's/^[?I]  *//' | xargs -r -d '\n' rm -r

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

笔记:

  • stsvn st是一个内置的别名status,即命令等同于svn status
  • --no-ignore在状态输出中还包括非存储库文件,否则通过诸如此类的机制忽略。- .cvsignore因为目标是要有一个干净的构建起点,所以此开关是必须的
  • grep输出,使得文件只未知过滤器,以颠覆留-行开头的?列表文件未知的颠覆,将不被忽略--no-ignore选项
  • 文件名之前的前缀通过删除 sed
  • 当参数列表为空时,xargs通过指示该命令-r不执行rm
  • -d '\n'选项告诉xargs使用换行符作为分隔符,因此该命令也适用于带空格的文件名
  • rm -r 用于需要删除完整目录(不属于存储库的部分)的情况

2

没有附加的依赖关系,我无法满足上述要求,我不想在Win32上的自动构建系统中添加这些依赖关系。因此,我整理了以下Ant命令-请注意,这些命令需要安装Ant-contrib JAR(我使用的是最新的1.0b3版本以及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}参考。


1
注意:仅删除未版本控制的文件;不会删除空的未版本控制的文件夹。

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

如果确定您要执行的操作,请删除回显。


1
这不如基于xargs的答案,因为要删除的n /bin/sh个文件有n个和n个rm进程被分叉。
maxschlepzig 2014年

同意 感谢您提供的xargs信息。
咏叹调

2

既然其他人都在做...

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

1

可能还提供其他选择

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

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

将--no-ignore添加到svn命令可能是一个好主意



1

纯Windows cmd / bat解决方案:

@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

实际上,此脚本并未删除我的文件。可能是由于其中的空格。@SukeshNambiar的单行答案确实有效。
克里斯蒂安·韦斯特贝克

1

我已经从此答案中尝试了Seth Reno的版本,但对我没有用。我在文件名前输入了8个字符,在中没有使用9个字符。cut -c9-

所以这是我的版本sed,而不是cut

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

1

如果您对Powershell很满意:

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

取出-WhatIf标志以使该命令实际执行删除操作。否则,它只是输出它如果没有-WhatIf运行做。


1

我将其添加为Thomas Watnedal的答案的评论,但还不能。

它的一个小问题(不会影响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状态下应该没有文件。


1

@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"
  • 您必须%在G和H前面使用两个标记
  • 切换顺序:首先删除所有文件,然后删除所有目录
  • (可选:)代替%~1任何目录名都可以使用,我在bat文件中将其用作函数,因此%~1首先输入参数

0

如果您不想编写任何代码,那么svn2svn的svn2.exe会执行此操作,此外还有一篇有关其实现方式的文章。删除的文件夹和文件放入回收站。

运行“ svn2.exe sync [路径]”。


0

对于喜欢使用perl而不是python,Unix shell,java等的人。特此使用一个小型的perl脚本来完成臂架。

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

#!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();


0

在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 ()

0

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

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!
)

0

上面的C#代码段对我不起作用-我有乌龟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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.