Автоматично видаляти неперевершені файли 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. Warren P: Чи можете ви надати більш детальну інформацію?
Томас Ватнедал

Я думаю, що це була просто проблема з Python 2.6. Знову працює для мене в 2.7.
Воррен П

1
Downvote: Інше рішення, наведене нижче, svn cleanup --remove-unversionedє кращим. І це для Subversion 1.9.0 (ця версія з 2015 року). Він стійкий і стандартний.
tres.14159

138

це працює для мене в баші:

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

Сет Рено краще:

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

Він обробляє неперевершені папки та пробіли у іменах

Згідно з коментарями нижче, це працює лише у файлах, про які не знає підривник (статус =?). Все , що підривна дійсно знає про (включаючи ігноровані файли / папки) не будуть видалені.

Якщо ви використовуєте підрив 1.9 або вище, ви можете просто скористатися командою очищення svn з параметрами --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
Ken

71

Я перебігав цю сторінку, шукаючи зробити те ж саме, але не для автоматизованої збірки.

Трохи подивившись, я відкрив ' Розширене контекстне меню ' в TortoiseSVN. Утримуйте клавішу Shift і клацніть правою кнопкою миші робочу копію. Зараз у меню TortoiseSVN є додаткові параметри, зокрема " Видалити неперевершені елементи ... ".

Хоча, можливо, це не стосується конкретного питання (тобто в контексті автоматизованої збірки), я вважав, що це може бути корисним для інших, хто хоче зробити те саме.


Чудово! У XP він працює лише у поданні списку (права частина Explorer), а не у вигляді дерева (зліва).
Крістофер Йозбек

Фантастичний, надішліть його лише до кошика, було б непогано зробити прямое видалення. Тільки те, що мені було потрібно.
Дін Томас

Ви також можете автоматизувати це в командному рядку за допомогою TortoiseProc.exe TortoiseSVN: подробиці моєї відповіді нижче.
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

Я додав це до свого профілю windowshell

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

2
@FelipeAlvarez Так. Так ми робимо. Це не найбільша річ, оскільки нарізаний хліб, але він б'є партією. Я б сказав, що він принаймні настільки ж корисний, як і bash, напевно, трохи більше, тому що ви можете втягувати .NET збірки.
jpmc26

Він страждає від грізної тенденції мікрософт до багатослівності (не тільки в довжині імені команди, але і в цілому неможливості зробити щось без копіювання гігантських фрагментів з Інтернету), але це приголомшливо корисно і досить добре продумано.
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 відключає, показуючи діалогове вікно очищення, де користувач може вибрати, що саме слід робити при очищенні. Доступні дії можна вказати за допомогою параметрів / очищення для очищення стану, / повернення, / делюверсія, / зняття, / оновлення та / зовнішнє середовище.


4

Якщо ви використовуєте svn черепаху, для цього є прихована команда. Утримуйте зсув, натискаючи правою кнопкою миші на папку, щоб запустити контекстне меню в Windows Explorer. Ви отримаєте команду "Видалити неперевершені елементи".

Докладніше див. у нижній частині цієї сторінки , або знімок екрана, під яким висвітлюються розширені функції із зеленими зірками, а також ті, що цікавлять жовтий прямокутник ...

SVN Розширене контекстне меню та стандартне меню



3

Моє перетворення C # сценарію Thomas Watnedals Python:

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 вбудовано це не має сенсу, тому що ніхто не ввійде в неї і створює файли.
Штефан Шульце

Дякую, я використав це як частину мого сценарію MSBuild в круїз-контролі, щоб очистити свій вихідний dir перед складанням
gregmac

Розпочався на основі вашого коду і пішов далі: github.com/tgmayfield/svn-clean-sharp/downloads
Том Мейфілд,

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

Це команда оболонки Unix для видалення всіх файлів, які не перебувають під контролем підривної роботи.

Примітки:

  • stв svn stце вбудований псевдонім для status, тобто команда еквівалентнаsvn status
  • --no-ignoreтакож включає нерепозиторні файли у вихідний стан, інакше ігнорується через такі механізми, як .cvsignoreі т.д.
  • то grepфільтри на виході таким чином, що тільки ті файли , невідомим в підривній залишилося - рядки , що починаються з ?списком файлами невідомої диверсії , які були б проігноровані без --no-ignoreопції
  • префікс до імені файлу видаляється через sed
  • xargsкоманда проінструктований з допомогою -rне виконати rm, коли список аргументів буде порожнім
  • -d '\n'параметр вказує xargsвикористовувати символ нового рядка в якості роздільника , наприклад команда також працює для імен файлів з пробілами
  • rm -r застосовується у випадку, якщо повні каталоги (які не входять до сховища) потрібно видалити

2

Я не міг змусити жодне з перерахованих вище працювати без додаткових залежностей, які мені не хотілося додавати до моєї автоматизованої системи збирання на win32. Тому я зібрав наступні команди Ant - зауважте, що для цього потрібно встановити JAR-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 rmпроцесів.
maxschlepzig

Домовились. Дякуємо за інформацію 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)/ призначений для моїх власних цілей.

І може бути хорошою ідеєю додати до команди svn --no-ignore



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

Я спробував версію Сет-Рено з цієї відповіді, але мені це не вийшло. Перед ім'ям файлу було 8 символів, а не 9, які використовувались у cut -c9-.

Отже, це моя версія sedзамість cut:

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

1

Якщо ви круті з powerhell:

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, який також виконує ривок.

Примітка. Це також видаляє всі неперевершені каталоги

#!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 години для створення цього. Це займе 5 хвилин, щоб зробити це в Unix. Основною проблемою були: пробіли в іменах для папок Win, неможливість редагування %% i та проблема з визначенням vars у циклі 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 # не працював для мене - у мене є клієнт-черепаха 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.