Eliminar automáticamente los archivos no versionados de Subversion


111

¿Alguien sabe una forma de eliminar de forma recursiva todos los archivos en una copia de trabajo que no están bajo control de versiones? (Necesito esto para obtener resultados más confiables en mi VMware de compilación automática).


7
Soy un usuario de SVN y he estado comparando Git con SVN para ver si quiero eventualmente hacer el cambio. Parece que este puede ser otro ejemplo en el que Git brilla con su comando "git clean".
jpierson

3
O hg purge --allen Mercurial.
Brendan Long

Duplicado de stackoverflow.com/questions/2803823/… donde hay mucha más actividad útil.
Heath Raftery

Respuestas:


26

Editar:

Subversion 1.9.0 introdujo una opción para hacer esto:

svn cleanup --remove-unversioned

Antes de eso, uso este script de Python para hacer eso:

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

Parece hacer el trabajo bastante bien.


1
Todavía me funciona con Python 2.7.2. Warren P: ¿Puede proporcionar más detalles?
Thomas Watnedal

Creo que fue solo un problema con Python 2.6. Funciona de nuevo para mí en 2.7.
Warren P

1
Votar en contra: La otra solución de abajo svn cleanup --remove-unversionedes mejor. Y es para Subversion 1.9.0 (esta versión es de 2015). Es estable y estándar.
tres.14159

138

esto funciona para mí en bash:

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

El de Seth Reno es mejor:

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

Maneja carpetas y espacios no versionados en nombres de archivos.

Según los comentarios a continuación, esto solo funciona en archivos que Subversion no conoce (estado =?). Todo lo que hace la subversión sabe de (incluyendo ficheros ignorados / carpetas) no se eliminarán.

Si está usando subversion 1.9 o superior, simplemente puede usar el comando svn cleanup con las opciones --remove-unversioned y --remove-ignored


6
También se puede utilizar en Windows en cygwin.
Honza

9
Puede considerar agregar la opción -d a xargs para los nombres de archivo con espacios y la opción -r a rm para cualquier directorio agregado: svn status | grep ^ \? | cut -c9- | xargs -d \\ n rm -r
Seth Reno

4
También tuve problemas con la opción -d ejecutándose en OS X, mi alternativa es la siguiente, que traduce los saltos de línea en caracteres nulos y usa la opción -0 en xargs para manejar espacios en nombres de archivo: svn status | grep ^ \? | cut -c9- | tr '\ n' '\ 0' | xargs -0 rm
Brian Webster

3
Si frunce el ceño ante los comandos que dependen del número exacto de caracteres en la salida de otro comando:svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r
Michael Schlottke-Lakemper

3
@Pavel Eche un vistazo a la opción xargs --no-run-if-empty
Ken

71

Me encontré con esta página mientras buscaba hacer lo mismo, aunque no para una compilación automática.

Después de buscar un poco más descubrí el ' Menú contextual extendido ' en TortoiseSVN. Mantenga presionada la tecla Mayús y haga clic con el botón derecho en la copia de trabajo. Ahora hay opciones adicionales en el menú de TortoiseSVN que incluyen ' Eliminar elementos no versionados ... '.

Aunque tal vez no sea aplicable para esta pregunta específica (es decir, dentro del contexto de una compilación automatizada), pensé que podría ser útil para otros que buscan hacer lo mismo.


¡Excelente! En XP, solo funciona en la vista de lista (lado derecho del explorador), no en la vista de árbol (lado izquierdo).
Christopher Oezbek

Fantástico, solo envíelo a la papelera de reciclaje, sería bueno eliminarlo directamente. Justo lo que necesitaba.
Dean Thomas

También puede automatizar esto en la línea de comando con TortoiseProc.exe de TortoiseSVN: detalles en mi respuesta a continuación.
stevek_mcc


9

Si está en la línea de comandos de Windows,

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

Versión mejorada:

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

Si usa esto en un archivo por lotes, necesita duplicar %:

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

1
Esto funcionó un poco para mí. Sin embargo, pareció ahogarse con algunas carpetas sin versión.
jpierson

7

Agregué esto a mi perfil de Windows PowerShell

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

2
@FelipeAlvarez Sí. Sí. No es lo mejor desde el pan de molde, pero supera al lote. Yo diría que es al menos tan útil como bash, probablemente un poco más, ya que puede incorporar ensamblados .NET.
jpmc26

Sufre de la abominable tendencia de microsoft hacia la verbosidad (no solo en la longitud del nombre del comando, sino en la imposibilidad general de hacer algo sin copiar fragmentos gigantes de Internet), pero es sorprendentemente útil y bastante bien pensado.
Warren P

1
Es posible que desee añadir --no-ignorea svn statusy -RecurseaRemove-Item
Kevin Smyth

5

Línea de comandos de Linux:

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

O, si algunos de sus archivos son propiedad de root:

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

Esto se basa en la respuesta de Ken. (La respuesta de Ken omite los archivos ignorados; mi respuesta los elimina).


5

Simplemente hazlo en unix-shell con:

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

Esto no funciona si el número de archivos que se eliminarán supera el número máximo de argumentos de la línea de comandos. Consulte también las respuestas basadas en xargs.
maxschlepzig

4

¿No puede simplemente exportar a una nueva ubicación y construir desde allí?


1
Para una compilación automatizada, querría una exportación limpia.
g.

1
Idealmente, haría esto, pero esto es problemático si su pago es muy grande. Esa es probablemente la razón por la que el OP pidió: hacer la construcción más corta.
jpmc26

4

Si tiene TortoiseSVN en su ruta y está en el directorio correcto:

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

Las opciones se describen en la ayuda de TortoiseSVN para /command:cleanup:

Use / noui para evitar que aparezca el cuadro de diálogo de resultados, ya sea para informar sobre la finalización de la limpieza o para mostrar un mensaje de error). / noprogressui también deshabilita el diálogo de progreso. / nodlg deshabilita mostrar el diálogo de limpieza donde el usuario puede elegir qué se debe hacer exactamente en la limpieza. Las acciones disponibles se pueden especificar con las opciones / cleanup para limpieza de estado, / revert, / delunversioned, / delignored, / refreshshell y / externals.


4

Si está utilizando tortoise svn, hay un comando oculto para hacer esto. Mantenga presionada la tecla Mayús mientras hace clic con el botón derecho en una carpeta para iniciar el menú contextual en el explorador de Windows. Obtendrá un comando "Eliminar elementos no versionados".

consulte la parte inferior de esta página para obtener más detalles, o la captura de pantalla a continuación que resalta las características extendidas con las estrellas verdes y la de interés con el rectángulo amarillo ...

Menú contextual extendido SVN vs menú estándar



3

Mi conversión en C # de la secuencia de comandos Python de 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();
    }
}

Prefiero mover los archivos sin versión, en caso de que los necesite en algún lugar más adelante.
leppie

En una máquina de desarrollo, por supuesto, pero en la compilación de VMware, eso no tendría ningún sentido porque nadie inicia sesión y crea archivos.
Stefan Schultze

Gracias, utilicé esto como parte de mi script MSBuild en cruisecontrol para limpiar mi directorio fuente antes de las compilaciones
gregmac

Comenzó en función de su código y fue más allá: 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

Este es un comando de shell de Unix para eliminar todos los archivos que no están bajo el control de Subversion.

Notas:

  • el stin svn stes un alias integrado para status, es decir, el comando es equivalente asvn status
  • --no-ignoretambién incluye archivos que no son de repositorio en la salida de estado; de lo contrario, se ignora a través de mecanismos como, .cvsignoreetc., ya que el objetivo es tener un punto de partida limpio para las compilaciones, este cambio es imprescindible
  • los grepfiltros de salida de tal manera que solo quedan archivos desconocidos para la subversión - las líneas que comienzan con la ?lista de archivos desconocidos para la subversión que serían ignorados sin la --no-ignoreopción
  • el prefijo hasta el nombre del archivo se elimina mediante sed
  • el xargscomando recibe instrucciones a través de -rque no se ejecute rm, cuando la lista de argumentos estaría vacía
  • la -d '\n'opción dicexargs que use una nueva línea como delimitador, por lo que el comando también funciona para nombres de archivo con espacios
  • rm -r se utiliza en caso de que sea necesario eliminar directorios completos (que no forman parte del repositorio)

2

No pude hacer que nada de lo anterior funcione sin dependencias adicionales que no quería tener que agregar a mi sistema de compilación automatizado en win32. Así que reuní los siguientes comandos Ant; tenga en cuenta que estos requieren que se instale Ant-contrib JAR (estaba usando la versión 1.0b3, la última, con Ant 1.7.0).

Tenga en cuenta que esto elimina todos los archivos sin versión sin previo aviso.

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

Para una carpeta diferente, cambie la ${basedir}referencia.


1
Nota: solo borra archivos sin versionar; no elimina carpetas vacías sin versionar.

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

elimine el eco si está seguro de lo que quiere hacer.


1
Esto es inferior a las respuestas basadas en xargs porque para que n sean archivos eliminados, hay n /bin/shy n rmprocesos bifurcados.
maxschlepzig

Convenido. Gracias por la información de xargs.
Aria

2

Como todos los demás lo están haciendo ...

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

1

También podría aportar otra opción

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

El /(config|.ini)/ es para mis propios fines.

Y podría ser una buena idea agregar --no-ignore al comando svn



1

Solución pura de 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

En realidad, este script no borró mis archivos. Quizás debido a los espacios en él. La respuesta de una línea de @SukeshNambiar funcionó.
Christiaan Westerbeek

1

He tratado de Seth Reno versión de esta respuesta pero no funcionó para mí. He tenido 8 caracteres antes del nombre de archivo, no 9 usados ​​encut -c9- .

Entonces esta es mi versión con en sedlugar de cut:

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

1

Si estás de acuerdo con powershell:

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

Saque el indicador -WhatIf para que el comando realmente realice las eliminaciones. De lo contrario, solo mostrará lo que haría si se ejecuta sin el -WhatIf.


1

Agregaría esto como un comentario a la respuesta de Thomas Watnedal. , pero aún no puedo.

Un problema menor con él (que no afectará a Windows) es que solo busca archivos o directorios. Para sistemas similares a Unix donde pueden estar presentes enlaces simbólicos, es necesario cambiar la línea:

if os.path.isfile(fullpath):

a

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

para eliminar también los enlaces.

Para mí, cambiar la última línea if match: removeall(match.group(1))por

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

para que muestre lo que está eliminando también fue útil.

Dependiendo del caso de uso, la ?[\?ID]parte de la expresión regular puede ser mejor ?[\?I], ya que Dtambién elimina los archivos eliminados, que estaban bajo control de versiones. Quiero usar esto para compilar en una carpeta limpia y registrada, por lo que no debería haber archivos en un Destado.


1

@zhoufei Probé tu respuesta y aquí está la versión actualizada:

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"
  • Debes usar dos %marcas delante de G y H
  • Cambie el orden: primero elimine todos los archivos, luego elimine todos los directorios
  • (opcional :) En lugar de %~1se puede usar cualquier nombre de directorio, lo usé como una función en un archivo bat, por lo que %~1es el primer parámetro de entrada

0

Si no desea escribir ningún código, svn2.exe de svn2svn hace esto, también hay un artículo sobre cómo se implementa. Las carpetas y archivos eliminados se colocan en la papelera de reciclaje.

Ejecute "svn2.exe sync [ruta]".


0

Para las personas a las que les gusta hacer esto con perl en lugar de python, shell de Unix, java, etc. A continuación, un pequeño script en perl que también hace el jib.

Nota: Esto también elimina todos los directorios no versionados.

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

Una forma limpia de hacer esto en PERL sería:

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

Usé ~ 3 horas para generar esto. Tardaría 5 minutos en hacerlo en Unix. El problema principal era: espacios en los nombres de las carpetas de Win, imposibilidad de editar %% iy problema con la definición de vars en el bucle cmd de 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

El fragmento de código C # anterior no funcionó para mí: tengo un cliente svn de tortuga y las líneas tienen un formato ligeramente diferente. Aquí está el mismo fragmento de código que el anterior, solo reescrito para funcionar y usar expresiones regulares.

        /// <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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.