Secara otomatis menghapus file tidak berversi Subversion


111

Adakah yang tahu cara untuk secara rekursif menghapus semua file dalam copy pekerjaan yang tidak di bawah kendali versi? (Saya membutuhkan ini untuk mendapatkan hasil yang lebih andal dalam VMware build otomatis saya.)


7
Saya pengguna SVN dan telah membandingkan Git dengan SVN untuk mengetahui apakah saya akhirnya ingin beralih. sepertinya ini adalah contoh lain di mana Git bersinar dengan perintah "git clean".
jpierson

3
Atau hg purge --alldi Mercurial.
Brendan Long

Duplikat stackoverflow.com/questions/2803823/… di mana terdapat lebih banyak aktivitas berguna.
Heath Raftery

Jawaban:


26

Edit:

Subversion 1.9.0 memperkenalkan opsi untuk melakukan ini:

svn cleanup --remove-unversioned

Sebelum itu, saya menggunakan skrip python ini untuk melakukan itu:

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

Tampaknya melakukan pekerjaan dengan cukup baik.


1
Masih berfungsi untuk saya dengan Python 2.7.2. Warren P: Bisakah Anda memberikan rincian lebih lanjut?
Thomas Watnedal

Saya pikir itu hanya masalah dengan Python 2.6. Bekerja lagi untuk saya di 2.7.
Warren P

1
Tidak suka: Solusi lain dari bawah svn cleanup --remove-unversionedlebih baik. Dan untuk Subversion 1.9.0 (versi ini dari 2015). Ini stabil dan standar.
tres. 14159

138

ini bekerja untuk saya di pesta:

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

Seth Reno lebih baik:

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

Ini menangani folder dan spasi tidak berversi dalam nama file

Sesuai dengan komentar di bawah, ini hanya bekerja pada file yang subversi tidak tahu tentang (status =?). Apa pun yang subversi tidak tahu tentang (termasuk Diabaikan file / folder) tidak akan dihapus.

Jika Anda menggunakan subversi 1.9 atau lebih tinggi, Anda dapat menggunakan perintah pembersihan svn dengan opsi --remove-unversioned dan --remove-ignored


6
Juga dapat digunakan di Windows di cygwin.
Honza

9
Anda dapat mempertimbangkan untuk menambahkan opsi -d ke xargs untuk nama file dengan spasi dan opsi -r ke rm untuk direktori yang ditambahkan: status svn | grep ^ \? | potong -c9- | xargs -d \\ n rm -r
Seth Reno

4
Saya juga mengalami masalah dengan opsi -d yang berjalan di OS X, alternatif saya adalah sebagai berikut, yang menerjemahkan linebreak menjadi karakter null dan menggunakan opsi -0 pada xargs untuk menangani spasi dalam nama file: status svn | grep ^ \? | potong -c9- | tr '\ n' '\ 0' | xargs -0 rm
Brian Webster

3
Jika Anda tidak menyukai perintah yang mengandalkan jumlah karakter yang tepat dalam output dari perintah lain:svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r
Michael Schlottke-Lakemper

3
@Pavel Lihatlah xargs - opsi tidak-lari-jika-kosong
Ken

71

Saya berlari melintasi halaman ini sambil mencari untuk melakukan hal yang sama, meskipun bukan untuk pembuatan otomatis.

Setelah mencari lebih banyak, saya menemukan ' Menu Konteks yang Diperluas ' di TortoiseSVN. Tahan tombol shift dan klik kanan pada copy pekerjaan. Sekarang ada opsi tambahan di bawah menu TortoiseSVN termasuk ' Hapus item tidak berversi ... '.

Meskipun mungkin tidak berlaku untuk pertanyaan khusus ini (yaitu dalam konteks pembuatan otomatis), saya pikir ini mungkin berguna bagi orang lain yang ingin melakukan hal yang sama.


Bagus! Di XP, ini hanya bekerja dalam tampilan daftar (sisi kanan penjelajah) bukan dalam tampilan pohon (sisi kiri).
Christopher Oezbek

Hebat, kirim saja ke recycle bin, alangkah baiknya melakukan hapus langsung. Hanya apa yang saya butuhkan.
Dean Thomas

Anda juga bisa mengotomatiskan ini pada baris perintah dengan TortoiseProc.exe TortoiseSVN: detail dalam jawaban saya di bawah ini.
stevek_mcc


9

Jika Anda menggunakan baris perintah windows,

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

Versi yang ditingkatkan:

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

Jika Anda menggunakan ini dalam file batch, Anda perlu menggandakan %:

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

1
Ini agak berhasil untuk saya. Tampaknya tersedak beberapa folder tidak berversi sekalipun.
jpierson

7

Saya menambahkan ini ke profil windows PowerShell saya

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

2
@Papua Ya, kami melakukannya. Ini bukan hal terhebat sejak roti iris, tapi ini mengalahkan tumpukan. Saya akan mengatakan itu setidaknya berguna seperti bash, mungkin sedikit lebih berguna karena Anda dapat menarik rakitan .NET.
jpmc26

Itu menderita kecenderungan keji dari microsoft terhadap verbositas (tidak hanya dalam panjang nama perintah, tetapi secara keseluruhan ketidakmungkinan menyelesaikan sesuatu tanpa menyalin potongan raksasa dari internet), tetapi itu sangat berguna, dan cukup dipikirkan dengan baik.
Warren P

1
Anda mungkin ingin menambah --no-ignoreke svn statusdan -RecursekeRemove-Item
Kevin Smyth

5

Baris perintah Linux:

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

Atau, jika beberapa file Anda dimiliki oleh root:

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

Ini berdasarkan jawaban Ken. (Jawaban Ken melewatkan file yang diabaikan; jawaban saya menghapusnya).


5

Lakukan saja di unix-shell dengan:

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

Ini tidak berfungsi jika jumlah file yang akan dihapus melebihi jumlah maksimal argumen baris perintah. Lihat juga jawaban berbasis xargs.
maxschlepzig

4

Bisakah Anda tidak hanya melakukan ekspor ke lokasi baru dan membangun dari sana?


1
Untuk pembuatan otomatis, saya ingin ekspor bersih.
g.

1
Idealnya, Anda akan melakukan ini, tetapi ini bermasalah jika pembayaran Anda sangat besar. Mungkin itulah alasan OP bertanya: untuk mempersingkat build.
jpmc26

4

Jika Anda memiliki TortoiseSVN di jalur Anda dan Anda berada di direktori yang benar:

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

Opsi dijelaskan dalam bantuan TortoiseSVN untuk /command:cleanup:

Gunakan / noui untuk mencegah dialog hasil bermunculan baik yang memberi tahu tentang pembersihan yang selesai atau menampilkan pesan kesalahan). / noprogressui juga menonaktifkan dialog kemajuan. / nodlg menonaktifkan menampilkan dialog pembersihan di mana pengguna dapat memilih apa yang harus dilakukan dalam pembersihan. Tindakan yang tersedia dapat dispesifikasikan dengan opsi / pembersihan untuk pembersihan status, / kembali, / delunversioned, / delignored, / refreshshell dan / externals.


4

Jika Anda menggunakan tortoise svn, ada perintah tersembunyi untuk melakukan ini. Tahan shift sambil mengklik kanan pada folder untuk meluncurkan menu konteks di windows explorer. Anda akan mendapatkan perintah "Hapus Item Tidak Berversi".

lihat bagian bawah halaman ini untuk detailnya, atau cuplikan layar di bawah ini yang menyoroti fitur tambahan dengan bintang hijau, dan salah satu yang menarik dengan persegi panjang kuning ...

SVN Menu konteks diperpanjang vs menu standar



3

Konversi C # saya dari skrip 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();
    }
}

Saya lebih suka memindahkan file tidak berversi, kalau-kalau Anda membutuhkannya di suatu tempat nanti.
leppie

Pada mesin pengembangan, tentu saja - tetapi dalam build VMware, hal itu tidak masuk akal karena tidak ada yang masuk ke dalamnya dan membuat file.
Stefan Schultze

Terima kasih, saya menggunakan ini sebagai bagian dari skrip MSBuild saya di cruisecontrol untuk membersihkan direktori sumber saya sebelum membangun
gregmac

Dimulai berdasarkan kode Anda dan melangkah lebih jauh: 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

Ini adalah perintah shell unix untuk menghapus semua file yang tidak berada di bawah kendali subversi.

Catatan:

  • yang stdi svn stadalah build-in alias untuk status, yaitu perintah setara dengansvn status
  • --no-ignorejuga menyertakan file non-repositori dalam output status, jika tidak mengabaikan melalui mekanisme seperti .cvsignoredll. - karena tujuannya adalah untuk memiliki titik awal yang bersih untuk build, sakelar ini adalah suatu keharusan
  • yang grepfilter output sehingga hanya file yang tidak diketahui untuk subversi yang tersisa - garis dimulai dengan ?daftar file yang tidak diketahui untuk subversi yang akan diabaikan tanpa --no-ignoreopsi
  • awalan hingga nama file dihapus melalui sed
  • yang xargsperintah diinstruksikan melalui -runtuk tidak mengeksekusi rm, ketika daftar argumen akan kosong
  • yang -d '\n'pilihan memberitahu xargsuntuk menggunakan baris baru sebagai pembatas perintah tersebut juga bekerja untuk nama file dengan spasi
  • rm -r digunakan jika direktori lengkap (yang bukan bagian dari repositori) perlu dihapus

2

Saya tidak bisa mendapatkan semua hal di atas untuk bekerja tanpa ketergantungan tambahan. Saya tidak ingin menambahkan ke sistem build otomatis saya di win32. Jadi saya mengumpulkan perintah Ant berikut - perhatikan ini memerlukan Ant-contrib JAR untuk diinstal (saya menggunakan versi 1.0b3, yang terbaru, dengan Ant 1.7.0).

Perhatikan ini menghapus semua file tidak berversi tanpa peringatan.

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

Untuk folder lain, ubah ${basedir}referensinya.


1
Catatan: hanya menghapus file tidak berversi; tidak menghapus folder kosong tidak berversi.

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

hapus gema jika Anda yakin itu yang ingin Anda lakukan.


1
Ini lebih rendah daripada jawaban berbasis xargs karena untuk n file yang akan dihapus ada n /bin/shdan n rmproses bercabang.
maxschlepzig

Sepakat. Terima kasih atas info xargs.
Aria

2

Karena semua orang melakukannya ...

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

1

Mungkin juga menyumbangkan opsi lain

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

/(Configi>.ini)/ untuk tujuan saya sendiri.

Dan mungkin ide yang bagus untuk menambahkan --no-ignore ke perintah svn



1

Solusi cmd / bat windows murni:

@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

Sebenarnya skrip ini tidak menghapus file saya. Mungkin karena adanya ruang di dalamnya. Jawaban satu baris oleh @SukeshNambiar berhasil.
Christiaan Westerbeek

1

Saya sudah mencoba versi Seth Reno dari jawaban ini tetapi tidak berhasil untuk saya. Saya memiliki 8 karakter sebelum nama file, bukan 9 yang digunakan dalam cut -c9-.

Jadi ini versi saya dengan sedalih - alih cut:

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

1

Jika Anda keren dengan PowerShell:

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

Keluarkan flag -WhatIf untuk membuat perintah benar-benar melakukan penghapusan. Jika tidak, itu hanya akan menampilkan apa yang akan dilakukannya jika dijalankan tanpa -WhatIf.


1

Saya akan menambahkan ini sebagai komentar untuk jawaban Thomas Watnedal , tetapi belum bisa.

Masalah kecil dengannya (yang tidak akan mempengaruhi Windows) adalah ia hanya memeriksa file atau direktori. Untuk sistem mirip Unix di mana tautan simbolik mungkin ada, perlu untuk mengubah baris:

if os.path.isfile(fullpath):

untuk

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

untuk juga menghapus tautan.

Bagi saya, mengubah baris terakhir if match: removeall(match.group(1))menjadi

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

sehingga menampilkan apa yang dihapusnya juga berguna.

Bergantung pada kasus penggunaan, ?[\?ID]bagian dari ekspresi reguler mungkin lebih baik ?[\?I], karena Djuga menghapus file yang dihapus, yang berada di bawah kontrol versi. Saya ingin menggunakan ini untuk membangun di folder yang bersih dan sudah diperiksa, jadi seharusnya tidak ada file dalam Dkeadaan.


1

@zhoufei Saya menguji jawaban Anda dan berikut adalah versi terbarunya:

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"
  • Anda harus menggunakan dua %tanda di depan G dan H.
  • Ganti urutannya: pertama hapus semua file, lalu hapus semua direktori
  • (opsional :) Sebagai ganti %~1dapat digunakan nama direktori apa pun, saya menggunakan ini sebagai fungsi dalam file bat, jadi %~1parameter input pertama

0

Jika Anda tidak ingin menulis kode apa pun, svn2.exe dari svn2svn melakukan ini, juga ada artikel tentang cara penerapannya. Folder dan file yang dihapus dimasukkan ke dalam recycle bin.

Jalankan "svn2.exe sync [path]".


0

Untuk orang-orang yang suka melakukan ini dengan perl, bukan python, Unix shell, java, dll. Dengan ini, skrip perl kecil yang juga melakukan jib.

Catatan: Ini juga menghapus semua direktori tidak berversi

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

Cara bersih untuk melakukan ini di PERL adalah:

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

Saya menggunakan ~ 3 jam untuk menghasilkan ini. Diperlukan waktu 5 menit untuk melakukannya di Unix. Masalah utama adalah: spasi dalam nama untuk folder Win, ketidakmungkinan untuk mengedit %% i dan masalah dengan mendefinisikan vars di loop cmd 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

C # kode snipet di atas tidak bekerja untuk saya - Saya memiliki klien svn tortoise, dan baris diformat sedikit berbeda. Berikut adalah snipet kode yang sama seperti di atas, hanya ditulis ulang untuk berfungsi dan menggunakan 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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.