Rimuovi automaticamente i file senza versione di Subversion


111

Qualcuno conosce un modo per rimuovere in modo ricorsivo tutti i file in una copia di lavoro che non sono sotto il controllo della versione? (Ne ho bisogno per ottenere risultati più affidabili nella mia build automatica VMware.)


7
Sono un utente SVN e ho confrontato Git con SVN per vedere se voglio eventualmente fare il passaggio. sembra che questo possa essere un altro esempio in cui Git brilla con il suo comando "git clean".
jpierson

3
O hg purge --allin Mercurial.
Brendan Long

Duplicato di stackoverflow.com/questions/2803823/… dove c'è un'attività molto più utile.
Heath Raftery

Risposte:


26

Modificare:

Subversion 1.9.0 ha introdotto un'opzione per farlo:

svn cleanup --remove-unversioned

Prima di ciò, utilizzo questo script Python per farlo:

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

Sembra fare abbastanza bene il lavoro.


1
Funziona ancora per me con Python 2.7.2. Warren P: Puoi fornire maggiori dettagli?
Thomas Watnedal,

Penso che fosse solo un problema con Python 2.6. Funziona di nuovo per me in 2.7.
Warren P

1
Voto negativo: l'altra soluzione dal muggito svn cleanup --remove-unversionedè migliore. Ed è per Subversion 1.9.0 (questa versione è del 2015). È stabile e standard.
tres.14159

138

questo funziona per me in bash:

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

Quello di Seth Reno è migliore:

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

Gestisce cartelle e spazi senza versione nei nomi dei file

Come da commenti di seguito, funziona solo su file di cui subversion non è a conoscenza (status =?). Tutto ciò che la sovversione non conosce (compresi i file / cartelle ignorati) non sarà cancellato.

Se stai usando subversion 1.9 o versioni successive puoi semplicemente usare il comando svn cleanup con le opzioni --remove-unversioned e --remove-ignored


6
Utilizzabile anche in Windows in Cygwin.
Honza

9
Potresti considerare di aggiungere l'opzione -d a xargs per i nomi di file con spazi e l'opzione -r a rm per qualsiasi directory aggiunta: svn status | grep ^ \? | tagliare -c9- | xargs -d \\ n rm -r
Seth Reno

4
Ho anche avuto problemi con l'opzione -d in esecuzione su OS X, la mia alternativa è la seguente, che traduce le interruzioni di riga in caratteri nulli e utilizza l'opzione -0 su xargs per gestire gli spazi nei nomi dei file: svn status | grep ^ \? | tagliare -c9- | tr '\ n' '\ 0' | xargs -0 rm
Brian Webster

3
Se disapprovate i comandi che si basano sul numero esatto di caratteri nell'output di un altro comando:svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r
Michael Schlottke-Lakemper

3
@Pavel Dai un'occhiata all'opzione xargs --no-run-if-empty
Ken

71

Mi sono imbattuto in questa pagina mentre cercavo di fare la stessa cosa, anche se non per una build automatizzata.

Dopo un po 'più di ricerca ho scoperto il " Menu contestuale esteso " in TortoiseSVN. Tieni premuto il tasto Maiusc e fai clic con il pulsante destro del mouse sulla copia di lavoro. Ora ci sono opzioni aggiuntive nel menu TortoiseSVN tra cui " Elimina elementi non modificati ... ".

Sebbene forse non sia applicabile a questa domanda specifica (cioè nel contesto di una build automatizzata), ho pensato che potrebbe essere utile per altri che cercano di fare la stessa cosa.


Grande! Su XP funziona solo nella visualizzazione elenco (lato destro di Explorer) e non nella visualizzazione albero (lato sinistro).
Christopher Oezbek,

Fantastico, mandalo solo nel cestino, sarebbe bello fare una cancellazione diretta. Proprio quello di cui avevo bisogno.
Dean Thomas,

Puoi anche automatizzarlo dalla riga di comando con TortoiseProc.exe di TortoiseSVN: dettagli nella mia risposta di seguito.
stevek_mcc


9

Se sei sulla riga di comando di Windows,

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

Versione migliorata:

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

Se lo usi in un file batch, devi raddoppiare %:

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

1
Questo tipo ha funzionato per me. Sembrava soffocare con alcune cartelle non modificate.
jpierson

7

L'ho aggiunto al mio profilo Windows PowerShell

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

2
@FelipeAlvarez Sì. Sì, lo facciamo. Non è la cosa migliore dopo il pane a fette, ma batte il batch. Direi che è utile almeno quanto bash, probabilmente un po 'di più dato che puoi inserire assembly .NET.
jpmc26

Soffre dell'abominevole tendenza di Microsoft verso la verbosità (non solo nella lunghezza del nome del comando, ma nell'impossibilità complessiva di fare qualsiasi cosa senza copiare frammenti giganti da Internet), ma è incredibilmente utile e piuttosto ben ponderato.
Warren P

1
Puoi aggiungere --no-ignorea svn statuse -RecurseaRemove-Item
Kevin Smyth

5

Riga di comando Linux:

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

Oppure, se alcuni dei tuoi file sono di proprietà di root:

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

Questo si basa sulla risposta di Ken. (La risposta di Ken salta i file ignorati; la mia risposta li elimina).


5

Fallo su unix-shell con:

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

Ciò non funziona se il numero di file da eliminare supera il numero massimo di argomenti della riga di comando. Vedi anche le risposte basate su xargs.
maxschlepzig

4

Non puoi semplicemente esportare in una nuova posizione e costruire da lì?


1
Per una build automatizzata vorrei un'esportazione pulita.
g.

1
Idealmente, dovresti farlo, ma questo è problematico se il tuo checkout è molto grande. Questo è probabilmente il motivo per cui l'OP ha chiesto: abbreviare la build.
jpmc26

4

Se hai TortoiseSVN sul tuo percorso e sei nella directory giusta:

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

Le opzioni sono descritte nella guida di TortoiseSVN per /command:cleanup:

Usa / noui per evitare che la finestra di dialogo dei risultati venga visualizzata indicando che la pulizia è terminata o mostrando un messaggio di errore). / noprogressui disabilita anche la finestra di dialogo di avanzamento. / nodlg disabilita la visualizzazione della finestra di dialogo di pulizia in cui l'utente può scegliere cosa esattamente dovrebbe essere fatto nella pulizia. Le azioni disponibili possono essere specificate con le opzioni / cleanup per la pulizia dello stato, / revert, / delunversioned, / delignored, / refreshshell e / externals.


4

Se stai usando tortoise svn, c'è un comando nascosto per farlo. Tieni premuto MAIUSC mentre fai clic con il pulsante destro del mouse su una cartella per avviare il menu contestuale in Windows Explorer. Otterrai un comando "Elimina elementi non aggiornati".

vedere la parte inferiore di questa pagina per i dettagli, o la schermata qui sotto che evidenzia le caratteristiche estese con le stelle verdi e quella di interesse con il rettangolo giallo ...

SVN Menu contestuale esteso vs menu standard



3

La mia conversione in C # dello script Python di Thomas Watnedals:

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

Preferirei spostare i file senza versione, nel caso in cui ne avessi bisogno da qualche parte in seguito.
leppie

Su una macchina di sviluppo, ovviamente, ma nella build VMware, ciò non avrebbe alcun senso perché nessuno vi accede e crea file.
Stefan Schultze

Grazie, l'ho usato come parte del mio script MSBuild in cruisecontrol per ripulire la mia directory sorgente prima delle build
gregmac

Iniziato in base al tuo codice e andato oltre: 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

Questo è un comando della shell unix per eliminare tutti i file non sotto il controllo di subversion.

Appunti:

  • l' stin svn stè un accumulo di alias per status, cioè il comando è equivalentesvn status
  • --no-ignoreinclude anche file non di repository nell'output di stato, altrimenti ignora tramite meccanismi come .cvsignoreecc. - poiché l'obiettivo è di avere un punto di partenza pulito per le build questa opzione è un must
  • i grepfiltri l'uscita in modo tale che i file unica incognita a Subversion sono lasciati - le linee che iniziano con ?file di elenco sconosciuta alla sovversione che sarebbe ignorato senza l' --no-ignoreopzione
  • il prefisso fino al nome del file viene rimosso tramite sed
  • il xargscomando viene istruito tramite -rdi non eseguire rm, quando la lista degli argomenti sarebbe vuota
  • l' -d '\n'opzione dice xargsdi usare una nuova riga come delimitatore in modo che il comando funzioni anche per i nomi di file con spazi
  • rm -r viene utilizzato nel caso in cui sia necessario rimuovere directory complete (che non fanno parte del repository)

2

Non riuscivo a far funzionare nessuno dei precedenti senza dipendenze aggiuntive che non volevo aggiungere al mio sistema di compilazione automatizzato su win32. Quindi ho messo insieme i seguenti comandi Ant: nota che richiedono l'installazione del JAR Ant-contrib (stavo usando la versione 1.0b3, l'ultima, con Ant 1.7.0).

Nota che questo elimina tutti i file senza versione senza preavviso.

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

Per una cartella diversa, modificare il ${basedir}riferimento.


1
Nota: elimina solo i file senza versione; non rimuove le cartelle vuote senza versione.

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

rimuovi l'eco se è sicuro di quello che vuoi fare.


1
Questo è inferiore alle risposte basate su xargs perché per n file da eliminare ci sono n /bin/she n rmprocessi biforcati.
maxschlepzig

Concordato. Grazie per le informazioni su xargs.
Aria

2

Dato che lo fanno tutti gli altri ...

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

1

Tanto vale contribuire con un'altra opzione

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

/(Config|.ini)/ è per i miei scopi.

E potrebbe essere una buona idea aggiungere --no-ignore al comando svn



1

Soluzione cmd / bat per finestre pure:

@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

In realtà questo script non ha cancellato i miei file. Forse a causa degli spazi al suo interno. La risposta in una riga di @SukeshNambiar ha funzionato.
Christiaan Westerbeek

1

Ho provato la versione di Seth Reno da questa risposta ma non ha funzionato per me. Ho avuto 8 caratteri prima del nome del file, non 9 usati in cut -c9-.

Quindi questa è la mia versione con sedinvece di cut:

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

1

Se ti piace PowerShell:

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

Elimina il flag -WhatIf per fare in modo che il comando esegua effettivamente le eliminazioni. Altrimenti mostrerà semplicemente cosa farebbe se fosse eseguito senza -WhatIf.


1

Vorrei aggiungere questo come commento alla risposta di Thomas Watnedal , ma non posso ancora.

Un problema minore con esso (che non influirà su Windows) è che controlla solo file o directory. Per sistemi tipo Unix in cui possono essere presenti collegamenti simbolici, è necessario modificare la riga:

if os.path.isfile(fullpath):

per

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

per rimuovere anche i collegamenti.

Per me, cambiare l'ultima riga if match: removeall(match.group(1))in

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

in modo che mostri ciò che sta rimuovendo è stato utile anche.

A seconda del caso d'uso, la ?[\?ID]parte dell'espressione regolare potrebbe essere migliore poiché ?[\?I], poiché Drimuove anche i file eliminati, che erano sotto il controllo della versione. Voglio usarlo per creare una cartella pulita e archiviata, quindi non dovrebbero esserci file in uno Dstato.


1

@zhoufei ho testato la tua risposta ed ecco la versione aggiornata:

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"
  • È necessario utilizzare due %segni davanti a G e H.
  • Cambia l'ordine: prima rimuovi tutti i file, quindi rimuovi tutte le directory
  • (opzionale :) Al posto di %~1può essere utilizzato qualsiasi nome di directory, l'ho usato come funzione in un file bat, quindi %~1è il primo parametro di input

0

Se non vuoi scrivere alcun codice, svn2.exe da svn2svn lo fa, c'è anche un articolo su come è implementato. Le cartelle e i file eliminati vengono inseriti nel cestino.

Esegui "svn2.exe sync [path]".


0

Per le persone a cui piace farlo con perl invece di python, shell Unix, java, ecc. Di seguito un piccolo script perl che fa anche il jib.

Nota: questo rimuove anche tutte le directory senza versione

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

Un modo pulito per farlo in PERL sarebbe:

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

Ho impiegato circa 3 ore per generarlo. Ci vorrebbero 5 minuti per farlo in Unix. Il problema principale era: spazi nei nomi per le cartelle Win, impossibilità di modificare %% ie problema con la definizione di variabili nel ciclo cmd di Win.

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

Lo snipet di codice C # sopra non ha funzionato per me: ho un client svn tortoise e le linee sono formattate in modo leggermente diverso. Ecco lo stesso codice snipet come sopra, solo riscritto per funzionare e usando regex.

        /// <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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.