Автоматически удалять неверсированные файлы Subversion


111

Кто-нибудь знает способ рекурсивно удалить все файлы в рабочей копии, которые не находятся под контролем версий? (Мне это нужно, чтобы получить более надежные результаты при автоматической сборке VMware.)


7
Я пользователь SVN и сравнивал Git с SVN, чтобы понять, хочу ли я в конечном итоге сделать переход. похоже, это может быть еще один пример, когда Git сияет своей командой "git clean".
jpierson

3
Или hg purge --allв Mercurial.
Брендан Лонг,

Дубликат stackoverflow.com/questions/2803823/…, где гораздо больше полезной деятельности.
Хит Рэфтери

Ответы:


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. Уоррен П .: Не могли бы вы предоставить более подробную информацию?
Thomas Watnedal

Я думаю, это была проблема Python 2.6. У меня снова работает в 2.7.
Warren P

1
Голос против: другое решение ниже svn cleanup --remove-unversionedлучше. И это для Subversion 1.9.0 (эта версия от 2015 года). Он стабилен и стандартен.
tres.14159

138

это работает для меня в bash:

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

У Сета Рино лучше:

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
Сет Рино

4
У меня также были проблемы с опцией -d, работающей в OS X, моя альтернатива следующая, которая переводит разрывы строк в нулевые символы и использует опцию -0 в xargs для обработки пробелов в именах файлов: svn status | grep ^ \? | вырезать -c9- | tr '\ n' '\ 0' | xargs -0 rm
Брайан Вебстер

3
Если вы осуждаете команды, которые полагаются на точное количество символов в выводе другой команды:svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r
Michael Schlottke-Lakemper

3
@Pavel Взгляните на параметр xargs --no-run-if-empty
Кен

71

Я наткнулся на эту страницу, пытаясь сделать то же самое, но не для автоматизированной сборки.

Пройдя еще немного, я обнаружил « Расширенное контекстное меню » в TortoiseSVN. Удерживая нажатой клавишу Shift, щелкните правой кнопкой мыши рабочую копию. В меню TortoiseSVN теперь есть дополнительные параметры, включая « Удалить неверсированные элементы ... ».

Хотя, возможно, это не применимо к этому конкретному вопросу (например, в контексте автоматизированной сборки), я подумал, что это может быть полезно для других, желающих сделать то же самое.


Большой! В XP он работает только в виде списка (правая часть проводника), а не в виде дерева (слева).
Кристофер Озбек,

Великолепно, только отправить в корзину, неплохо было бы сделать прямое удаление. Как раз то, что мне было нужно.
Дин Томас

Вы также можете автоматизировать это в командной строке с 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

7

Я добавил это в свой профиль Windows PowerShell

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

2
@FelipeAlvarez Да. Да. Это не самая лучшая вещь после нарезанного хлеба, но это лучше, чем замес. Я бы сказал, что он по крайней мере так же полезен, как bash, возможно, немного больше, поскольку вы можете использовать сборки .NET.
jpmc26

Он страдает от отвратительной склонности Microsoft к многословию (не только в длине имени команды, но и в общей невозможности сделать что-либо без копирования гигантских фрагментов из Интернета), но он шокирующе полезен и довольно хорошо продуман.
Warren P

1
Вы можете добавить что-то --no-ignoreк svn statusи -RecurseкRemove-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

Это основано на ответе Кена. (Ответ Кена пропускает игнорируемые файлы; мой ответ удаляет их).


5

Просто сделайте это в unix-shell с помощью:

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

Это не работает, если количество удаляемых файлов превышает максимальное количество аргументов командной строки. См. Также ответы на основе xargs.
maxschlepzig

4

А нельзя просто экспортировать в новое место и строить оттуда?


1
Для автоматической сборки мне нужен чистый экспорт.
г.

1
В идеале вы бы сделали это, но это проблематично, если ваша касса очень большая. Вероятно, это причина, по которой ОП попросил: сделать сборку короче.
jpmc26

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

Если вы используете tortoise svn, для этого есть скрытая команда. Удерживая нажатой клавишу Shift, щелкните папку правой кнопкой мыши, чтобы запустить контекстное меню в проводнике Windows. Вы получите команду «Удалить неверсированные элементы».

см. подробности внизу этой страницы или снимок экрана ниже, на котором расширенные функции выделены зелеными звездами, а интересующий - желтым прямоугольником ...

SVN Расширенное контекстное меню против стандартного меню



3

Мое преобразование сценария 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();
    }
}

Я бы предпочел переместить неверсированные файлы на случай, если они вам понадобятся позже.
leppie

Конечно, на машине разработки - но в VMware сборки это не имело бы никакого смысла, потому что никто не входит в систему и не создает файлы.
Стефан Шульце

Спасибо, я использовал это как часть моего сценария MSBuild в cruisecontrol, чтобы очистить исходный
каталог

Начал с вашего кода и пошел дальше: 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 для удаления всех файлов, не находящихся под контролем Subversion.

Ноты:

  • stв svn 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 файлов создаются n /bin/shи n rmпроцессов.
maxschlepzig

Согласовано. Спасибо за информацию о xargs.
Aria


1

Может также предложить другой вариант

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

/(Config|.ini)/ предназначен для моих целей.

И было бы неплохо добавить --no-ignore к команде svn



1

Чистое решение cmd / bat для windows:

@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 действительно сработал.
Christiaan Westerbeek

1

Я пробовал версию Сета Рино из этого ответа, но у меня это не сработало. У меня было 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

Я бы добавил это как комментарий к ответу Томаса Уотнедала , но пока не могу.

Небольшая проблема с ним (которая не повлияет на 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

Если вы не хотите писать какой-либо код, svn2.exe из svn2svn делает это, также есть статья о том, как это реализовано. Удаленные папки и файлы помещаются в корзину.

Запустите «svn2.exe sync [путь]».


0

Для людей, которым нравится делать это с помощью perl вместо python, оболочки Unix, 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();


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.

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 #, приведенный выше, у меня не работал - у меня есть клиент 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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.