【问题标题】:Automatically remove Subversion unversioned files自动删除 Subversion 无版本文件
【发布时间】:2010-09-19 08:30:42
【问题描述】:

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

【问题讨论】:

  • 我是 SVN 用户,并且一直在将 Git 与 SVN 进行比较,看看我是否最终想要进行切换。看起来这可能是 Git 的“git clean”命令大放异彩的另一个例子。
  • 或 Mercurial 中的 hg purge --all
  • stackoverflow.com/questions/2803823/… 的副本,其中有很多有用的活动。

标签: svn build-automation


【解决方案1】:

编辑:

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

它似乎做得很好。

【讨论】:

  • 仍然适用于 Python 2.7.2。 Warren P:你能提供更多细节吗?
  • 我认为这只是 Python 2.6 的问题。在 2.7 中再次为我工作。
  • 投反对票:来自下面svn cleanup --remove-unversioned 的另一个解决方案更好。它适用于 Subversion 1.9.0(此版本来自 2015 年)。稳定、规范。
【解决方案2】:

Subversion 1.9.0 引入了删除未版本化项目的选项 [1]

svn cleanup --remove-unversioned

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

【讨论】:

    【解决方案3】:

    @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是第一个输入参数

    【讨论】:

      【解决方案4】:

      我还发现并使用了以下内容: svn 状态 --no-ignore| awk '/^?/ {打印 $2}'| xargs rm

      【讨论】:

        【解决方案5】:

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

        请参阅page 的底部了解详细信息,或下面的屏幕截图,其中以绿色星标突出显示扩展功能,并以黄色矩形突出显示感兴趣的功能...

        【讨论】:

          【解决方案6】:

          我会将此作为评论添加到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 状态下应该没有文件。

          【讨论】:

            【解决方案7】:

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

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

            【讨论】:

            • @FelipeAlvarez 是的。是的,我们有。这不是切片面包以来最棒的事情,但它胜过批次。我想说它至少和 bash 一样有用,可能更有用,因为你可以引入 .NET 程序集。
            • 它受到微软令人讨厌的冗长倾向的影响(不仅仅是命令名称的长度,而且如果不从互联网上复制巨大的 sn-ps,总体上不可能完成任何事情),但它非常有用,而且相当深思熟虑。
            • 您可能希望将--no-ignore 添加到svn status-RecurseRemove-Item
            【解决方案8】:

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

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

            /command:cleanup 的 TortoiseSVN 帮助中描述了这些选项:

            使用 /noui 防止弹出结果对话框 告诉清理已完成或显示错误 信息)。 /noprogressui 也禁用进度对话框。 /点头 禁用显示清理对话框,用户可以在其中选择什么 完全应该在清理中完成。可用的操作可以是 使用选项 /cleanup 指定状态清除、/revert、 /delunversioned、/delignored、/refreshshell 和 /externals。

            【讨论】:

              【解决方案9】:

              这在 bash 中对我有用:

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

              Seth Reno 的更好:

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

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

              根据下面的 cmets,这仅适用于 subversion 不知道的文件 (status=?)。 subversion确实知道的任何东西(包括被忽略的文件/文件夹)都不会被删除。

              如果您使用的是 subversion 1.9 或更高版本,您可以简单地使用带有 --remove-unversioned 和 --remove-ignored 选项的 svn cleanup 命令

              【讨论】:

              • 在 cygwin 中也可以在 Windows 中使用。
              • 您可能会考虑将 -d 选项添加到 xargs 用于带有空格的文件名,并将 -r 选项添加到 rm 用于任何添加的目录:svn status | grep ^\? |切-c9- | xargs -d \\n rm -r
              • 我在 OS X 上运行的 -d 选项也有问题,我的替代方案如下,它将换行符转换为空字符并使用 xargs 上的 -0 选项来处理文件名中的空格:svn状态 | grep ^\? |切-c9- | tr '\n' '\0' | xargs -0 rm
              • 如果您不喜欢依赖于另一个命令输出中的确切字符数的命令:svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r
              • @Pavel 看看 xargs --no-run-if-empty 选项
              【解决方案10】:

              对于想要避免使用除标准 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"

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

              【讨论】:

              • 我不相信这完全有效,特别是如果您忽略了文件(如 .obj 文件),您需要更改 'svn st ^| findstr "^?'" 到 'svn st --no-ignore ^| findstr "^[?I]"' 将忽略的文件添加到列表中。
              【解决方案11】:

              如果你对 powershell 很满意:

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

              取出 -WhatIf 标志以使命令实际执行删除。否则它只会输出它在没有 -WhatIf 的情况下运行 做的事情。

              【讨论】:

                【解决方案12】:

                上面的 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
                

                【讨论】:

                  【解决方案13】:
                  svn st --no-ignore  | grep '^[?I]' | sed 's/^[?I]  *//' | xargs -r -d '\n' rm -r
                  

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

                  注意事项:

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

                  【讨论】:

                    【解决方案14】:

                    我用了大约 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!
                    )
                    

                    【讨论】:

                      【解决方案15】:

                      我尝试了this answer 中的Seth Reno's 版本,但它对我不起作用。我在文件名前有 8 个字符,而不是 cut -c9- 中使用的 9 个字符。

                      所以这是我用sed 代替cut 的版本:

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

                      【讨论】:

                        【解决方案16】:

                        纯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 的单行回答确实有效。
                        【解决方案17】:

                        只需在 unix-shell 上使用:

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

                        【讨论】:

                        • 如果要删除的文件数量超过命令行参数的最大数量,这将不起作用。另请参阅基于 xargs 的答案。
                        【解决方案18】:

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

                        【讨论】:

                          【解决方案19】:

                          因为其他人都在这样做......

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

                          【讨论】:

                            【解决方案20】:

                            如果你在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"
                            

                            【讨论】:

                            • 这对我有用。不过,似乎在一些未版本化的文件夹上卡住了。
                            【解决方案21】:

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

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

                            【讨论】:

                              【解决方案22】:

                              不妨提供另一个选择

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

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

                              在 svn 命令中添加 --no-ignore 可能是个好主意

                              【讨论】:

                                【解决方案23】:

                                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 的回答跳过了被忽略的文件;我的回答删除了它们)。

                                【讨论】:

                                  【解决方案24】:

                                  使用 TortoiseSVN:* 右键单击​​工作副本文件夹,同时按住 shift 键 * 选择“删除未受版本控制的项目”

                                  How can I delete all unversioned/ignored files/folders in my working copy?

                                  【讨论】:

                                    【解决方案25】:
                                    svn status --no-ignore | awk '/^[I\?]/ {system("echo rm -r " $2)}'
                                    

                                    如果您确定要这样做,请移除回声。

                                    【讨论】:

                                    • 这不如基于 xargs 的答案,因为对于 n 个要删除的文件,有 n 个 /bin/sh 和 n 个 rm 进程分叉。
                                    • 同意。感谢您提供 xargs 信息。
                                    【解决方案26】:

                                    见:svn-clean

                                    【讨论】:

                                    • 在 cygwin 中的 subversion-tools 包中。
                                    • 在 Ubuntu 中,在同一个包中:subversion-tools
                                    • 这也会删除嵌套的存储库。
                                    【解决方案27】:

                                    对于喜欢使用 perl 而不是 python、Unix shell、java 等的人。特此提供一个小的 perl 脚本,它也可以完成 jib。

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

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

                                    【讨论】:

                                      【解决方案28】:

                                      如果您不想编写任何代码,svn2svn 的 svn2.exe 会执行此操作,还有an article 的实现方式。删除的文件夹和文件会被放入回收站。

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

                                      【讨论】:

                                        【解决方案29】:

                                        我在想做同样的事情时遇到了这个页面,但不是为了自动构建。

                                        经过一番查看后,我在 TortoiseSVN 中发现了“扩展上下文菜单”。按住 shift 键并右键单击工作副本。 TortoiseSVN 菜单下现在有其他选项,包括“删除未受版本控制的项目...”。

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

                                        【讨论】:

                                        • 太棒了!在 XP 上,它仅适用于列表视图(资源管理器的右侧)而不适用于树视图(左侧)。
                                        • 太棒了,只发送到回收站,直接删除就好了。正是我需要的。
                                        • 您也可以使用 TortoiseSVN 的 TortoiseProc.exe 在命令行上自动执行此操作:详细信息请参阅下面的答案。
                                        【解决方案30】:

                                        如果没有额外的依赖项,我无法让上述任何一项工作,我不想将这些依赖项添加到我在 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} 引用。

                                        【讨论】:

                                        • 注意:只删除未版本控制的文件;不会删除空的未版本化文件夹。
                                        猜你喜欢
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2012-03-07
                                        • 2021-09-26
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2018-01-16
                                        相关资源
                                        最近更新 更多