Automatycznie usuwaj niewersjonowane pliki Subversion


111

Czy ktoś zna sposób na rekurencyjne usuwanie wszystkich plików w kopii roboczej, które nie są objęte kontrolą wersji? (Potrzebuję tego, aby uzyskać bardziej wiarygodne wyniki w mojej automatycznej kompilacji VMware).


7
Jestem użytkownikiem SVN i porównywałem Git z SVN, aby zobaczyć, czy ostatecznie chcę dokonać zmiany. wygląda na to, że może to być kolejny przykład, w którym Git świeci swoim poleceniem „git clean”.
jpierson,

3
Lub hg purge --allw Mercurial.
Brendan Long

Duplikat stackoverflow.com/questions/2803823/… gdzie jest dużo bardziej przydatna aktywność.
Heath Raftery,

Odpowiedzi:


26

Edytować:

Subversion 1.9.0 wprowadził opcję, aby to zrobić:

svn cleanup --remove-unversioned

Wcześniej używam tego skryptu Pythona, aby to zrobić:

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

Wydaje się, że całkiem nieźle wykonuje swoją pracę.


1
Nadal działa dla mnie z Pythonem 2.7.2. Warren P: Czy możesz podać więcej szczegółów?
Thomas Watnedal

Myślę, że to był tylko problem z Pythonem 2.6. U mnie znowu działa w 2.7.
Warren P

1
Głos przeciw: inne rozwiązanie z poniższego svn cleanup --remove-unversionedjest lepsze. I to jest dla Subversion 1.9.0 (ta wersja pochodzi z 2015 roku). Jest stabilny i standardowy.
tres.14159

138

to działa dla mnie w bash:

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

Seth Reno jest lepszy:

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

Obsługuje niewersjonowane foldery i spacje w nazwach plików

Zgodnie z komentarzami poniżej, działa to tylko w przypadku plików, o których subversion nie wie (status =?). Wszystko, Subversion nie wiedzieć (w tym Ignorowani plików / folderów) nie zostaną usunięte.

Jeśli używasz subversion 1.9 lub nowszej, możesz po prostu użyć polecenia svn cleanup z opcjami --remove-unversioned i --remove-ignored


6
Do użytku również w systemie Windows w Cygwin.
Honza

9
Możesz rozważyć dodanie opcji -d do xargs dla nazw plików ze spacjami i opcji -r do rm dla wszystkich dodanych katalogów: status svn | grep ^ \? | cut -c9- | xargs -d \\ n rm -r
Seth Reno

4
Miałem również problemy z opcją -d działającą na OS X, moja alternatywa jest następująca, która tłumaczy podziały wierszy na znaki puste i używa opcji -0 na xargs do obsługi spacji w nazwach plików: svn status | grep ^ \? | cut -c9- | tr '\ n' '\ 0' | xargs -0 rm
Brian Webster

3
Jeśli marszczysz brwi na polecenia, które zależą od dokładnej liczby znaków w danych wyjściowych innego polecenia:svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r
Michael Schlottke-Lakemper

3
@Pavel Spójrz na opcję xargs --no-run-if-empty
Ken

71

Natknąłem się na tę stronę, szukając tego samego, ale nie dla automatycznej kompilacji.

Po dokładniejszym przyjrzeniu się odkryłem „ Rozszerzone menu kontekstowe ” w TortoiseSVN. Przytrzymaj klawisz Shift i kliknij prawym przyciskiem myszy kopię roboczą. Istnieją teraz dodatkowe opcje w menu TortoiseSVN, w tym „ Usuń niewersjonowane elementy… ”.

Chociaż być może nie dotyczy tego konkretnego pytania (tj. W kontekście automatycznej kompilacji), pomyślałem, że może to być pomocne dla innych, którzy chcą zrobić to samo.


Wspaniały! W XP działa tylko w widoku listy (prawa strona eksploratora), a nie w widoku drzewa (lewa strona).
Christopher Oezbek

Fantastycznie, wyślij go tylko do kosza, byłoby miło zrobić proste usunięcie. Dokładnie to, czego potrzebowałem.
Dean Thomas

Możesz również zautomatyzować to w wierszu poleceń za pomocą TortoiseProc.exe TortoiseSVN: szczegóły w mojej odpowiedzi poniżej.
stevek_mcc,


9

Jeśli korzystasz z wiersza poleceń systemu Windows,

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

Poprawiona wersja:

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

Jeśli używasz tego w pliku wsadowym, musisz podwoić %:

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

1
To trochę zadziałało dla mnie. Wydawało się jednak, że dławił się niektórymi niewersjonowanymi folderami.
jpierson

7

Dodałem to do mojego profilu Windows PowerShell

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

2
@FelipeAlvarez Yes. Tak. To nie jest najlepsza rzecz od czasu krojonego chleba, ale przebija partię. Powiedziałbym, że jest co najmniej tak samo przydatny jak bash, prawdopodobnie trochę bardziej, ponieważ można pobierać zestawy .NET.
jpmc26

Cierpi na obrzydliwą tendencję Microsoftu do gadatliwości (nie tylko pod względem długości nazwy polecenia, ale ogólnie niemożności zrobienia czegokolwiek bez kopiowania gigantycznych fragmentów z Internetu), ale jest szokująco przydatna i dość dobrze przemyślana.
Warren P

1
Możesz dodać --no-ignoredo svn statusi -RecursedoRemove-Item
Kevin Smyth

5

Linia poleceń Linuksa:

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

Lub, jeśli właścicielem niektórych plików jest root:

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

To jest oparte na odpowiedzi Kena. (Odpowiedź Kena pomija ignorowane pliki; moja odpowiedź usuwa je).


5

Po prostu zrób to na powłoce unix za pomocą:

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

To nie działa, jeśli liczba plików do usunięcia przekracza maksymalną liczbę argumentów wiersza poleceń. Zobacz także odpowiedzi oparte na xargs.
maxschlepzig

4

Czy nie możesz po prostu wyeksportować do nowej lokalizacji i stamtąd budować?


1
W przypadku kompilacji automatycznej chciałbym mieć czysty eksport.
g.

1
Idealnie byś to zrobił, ale jest to problematyczne, jeśli twoja kasa jest bardzo duża. Jest to prawdopodobnie powód, dla którego PO poprosił: skrócić czas budowy.
jpmc26

4

Jeśli masz TortoiseSVN na swojej ścieżce i jesteś we właściwym katalogu:

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

Opcje są opisane w pomocy TortoiseSVN dla /command:cleanup:

Użyj / noui, aby zapobiec wyświetlaniu okna dialogowego wyników, informującego o zakończeniu czyszczenia lub wyświetlającego komunikat o błędzie). / noprogressui wyłącza również okno dialogowe postępu. / nodlg wyłącza wyświetlanie okna dialogowego czyszczenia, w którym użytkownik może wybrać, co dokładnie powinno zostać zrobione podczas czyszczenia. Dostępne akcje można określić za pomocą opcji / cleanup dla czyszczenia statusu, / revert, / delunversioned, / delignored, / refreshshell i / externals.


4

Jeśli używasz żółwia svn, istnieje ukryte polecenie, aby to zrobić. Przytrzymaj klawisz Shift, klikając prawym przyciskiem myszy folder, aby uruchomić menu kontekstowe w eksploratorze Windows. Otrzymasz polecenie „Usuń elementy bez wersji”.

zobacz szczegóły na dole tej strony lub zrzut ekranu poniżej, który podkreśla rozszerzone funkcje zielonymi gwiazdami, a ten, który Cię interesuje, żółtym prostokątem ...

SVN Rozszerzone menu kontekstowe a standardowe menu



3

Moja konwersja C # skryptu Thomas Watnedals w języku 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();
    }
}

Wolałbym raczej przenieść niewersjonowane pliki, na wypadek gdybyś ich później potrzebował.
leppie

Oczywiście na maszynie deweloperskiej - ale w wersji VMware nie miałoby to żadnego sensu, ponieważ nikt nie logowałby się do niej i nie tworzył plików.
Stefan Schultze

Dzięki, użyłem tego jako części mojego skryptu MSBuild w cruisecontrol, aby wyczyścić katalog źródłowy przed kompilacją
gregmac

Zacząłem na podstawie twojego kodu i poszedłem o wiele dalej: 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

To jest polecenie powłoki unix, które usuwa wszystkie pliki poza kontrolą subversion.

Uwagi:

  • stw svn stto wbudowany alias status, czyli komenda jest równoważnasvn status
  • --no-ignorewłącza również pliki niezwiązane z repozytoriami w wyjściu statusu, w przeciwnym razie ignoruje je za pomocą mechanizmów, takich jak .cvsignoreitp. - ponieważ celem jest uzyskanie czystego punktu startowego dla kompilacji, ten przełącznik jest koniecznością
  • te grepfiltry wyjście takie, że tylko te pliki, nie wiadomo do Subversion pozostało - linie począwszy ?Files list nieznany wywrotową, które byłyby ignorowane bez --no-ignoreopcji
  • prefiks do nazwy pliku jest usuwany za pośrednictwem sed
  • xargskomenda jest instruowany przez -rnie wykonać rm, gdy lista argumentem byłaby pusta
  • -d '\n'opcja nakazuje xargsużywać nowej linii jako separator takie polecenie działa również w nazwach plików ze spacjami
  • rm -r jest używany w przypadku konieczności usunięcia kompletnych katalogów (które nie są częścią repozytorium)

2

Nie mogłem uruchomić żadnego z powyższych bez dodatkowych zależności, których nie chciałem dodawać do mojego automatycznego systemu kompilacji na win32. Dlatego zestawiłem następujące polecenia Ant - zauważ, że wymagają one zainstalowania pliku JAR Ant-contrib w (używałem wersji 1.0b3, najnowszej, z Ant 1.7.0).

Zauważ, że powoduje to usunięcie wszystkich niewersjonowanych plików bez ostrzeżenia.

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

W przypadku innego folderu zmień ${basedir}odniesienie.


1
Uwaga: usuwa tylko niewersjonowane pliki; nie usuwa pustych niewersjonowanych folderów.

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

usuń echo, jeśli to jest pewne, co chcesz zrobić.


1
Jest to gorsze od odpowiedzi opartych na xargs, ponieważ dla n do usunięcia plików istnieje rozwidlonych n /bin/shi n rmprocesów.
maxschlepzig

Zgoda. Dzięki za informacje o xargs.
Aria,

2

Ponieważ wszyscy to robią ...

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

1

Równie dobrze może przynieść inną opcję

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

Plik /(config|.ini)/ jest przeznaczony do moich własnych celów.

Dobrym pomysłem może być dodanie --no-ignore do polecenia svn



1

Czyste rozwiązanie 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

Właściwie ten skrypt nie usunął moich plików. Może z powodu znajdujących się w nim przestrzeni. Jednowierszowa odpowiedź @SukeshNambiar zadziałała.
Christiaan Westerbeek

1

Wypróbowałem wersję Setha Reno z tej odpowiedzi, ale nie zadziałała. Mam 8 znaków przed nazwą pliku, a nie 9 używanych wcut -c9- .

Więc to jest moja wersja z sedzamiast cut:

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

1

Jeśli nie przeszkadza Ci PowerShell:

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

Usuń flagę -WhatIf, aby polecenie faktycznie wykonało usuwanie. W przeciwnym razie wyświetli tylko to, co by zrobił, gdyby działał bez -WhatIf.


1

Dodałbym to jako komentarz do odpowiedzi Thomasa Watnedala , ale jeszcze nie mogę.

Drobny problem z nim (który nie wpłynie na system Windows) polega na tym, że sprawdza tylko pliki lub katalogi. W przypadku systemów typu Unix, w których mogą występować dowiązania symboliczne, konieczna jest zmiana linii:

if os.path.isfile(fullpath):

do

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

aby również usunąć linki.

Dla mnie zmiana ostatniej linii if match: removeall(match.group(1))na

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

aby wyświetlał to, co usuwa, też był przydatny.

W zależności od przypadku użycia ?[\?ID]część wyrażenia regularnego może być lepsza ?[\?I], ponieważ Dusuwa również usunięte pliki, które były pod kontrolą wersji. Chcę użyć tego do zbudowania w czystym, zaznaczonym folderze, więc nie powinno być żadnych plików w Dstanie.


1

@zhoufei Przetestowałem twoją odpowiedź i tutaj jest zaktualizowana wersja:

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"
  • Musisz użyć dwóch %znaków przed G i H.
  • Zmień kolejność: najpierw usuń wszystkie pliki, a następnie usuń wszystkie katalogi
  • (opcjonalnie :) W miejsce %~1można użyć dowolnej nazwy katalogu, użyłem tego jako funkcji w pliku bat, więc %~1jest to pierwszy parametr wejściowy

0

Jeśli nie chcesz pisać żadnego kodu, robi to svn2.exe z svn2svn , jest też artykuł o tym, jak to jest zaimplementowane. Usunięte foldery i pliki są umieszczane w koszu.

Uruchom polecenie „svn2.exe sync [ścieżka]”.


0

Dla ludzi, którzy lubią to robić za pomocą perla zamiast pythona, powłoki Unix, javy itp. Oto mały skrypt w Perlu, który również wykonuje jib.

Uwaga: spowoduje to również usunięcie wszystkich niewersjonowanych katalogów

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

Czystym sposobem na zrobienie tego w PERL byłoby:

#!/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

Wygenerowałem to przez około 3 godziny. Zrobienie tego w systemie Unix zajęłoby 5 minut. Głównymi problemami były: spacje w nazwach folderów Win, niemożność edycji %% i oraz problem z definiowaniem zmiennych w pętli 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

Fragment kodu C # powyżej nie działał dla mnie - mam klienta svn żółwia, a linie są sformatowane nieco inaczej. Oto ten sam fragment kodu, co powyżej, tylko przepisany do funkcji i przy użyciu wyrażenia regularnego.

        /// <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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.