Does anybody know a way to recursively remove all files in a working copy that are not under version control? (I need this to get more reliable results in my automatic build VMware.)
-
7I'm an SVN user and have been comparing Git to SVN to see if I want to eventually want to make the switch. it looks like this may be another example where Git shines with its "git clean" command. – jpierson Sep 21 '10 at 14:11
-
3Or [`hg purge --all`](http://mercurial.selenic.com/wiki/PurgeExtension) in Mercurial. – Brendan Long Mar 06 '12 at 17:58
-
Duplicate of https://stackoverflow.com/questions/2803823/how-can-i-delete-all-unversioned-ignored-files-folders-in-my-working-copy where there's a lot more useful activity. – Heath Raftery Sep 15 '18 at 00:55
32 Answers
this works for me in bash:
svn status | egrep '^\?' | cut -c8- | xargs rm
Seth Reno's is better:
svn status | grep ^\? | cut -c9- | xargs -d \\n rm -r
It handles unversioned folders and spaces in filenames
As per comments below, this only works on files that subversion doesn't know about (status=?). Anything that subversion does know about (including Ignored files/folders) will not be deleted.
If you are using subversion 1.9 or greater you can simply use the svn cleanup command with --remove-unversioned and --remove-ignored options
-
6
-
Is it safe to "share" and manipulate a SVN working copy between the Windows and CygWin builds of svn? – Craig McQueen Jun 30 '09 at 01:39
-
Actually I guess this example is not manipulating the working copy. Just doing status. – Craig McQueen Jun 30 '09 at 01:40
-
@Craig - all this is doing is finding all the files in the working copy that haven't been added (by checking for a ? status) and deleting them. Exactly the same as doing a status and then manually deleting the files. – Ken Jun 30 '09 at 09:30
-
1The **svn status** command should probably use the **--no-ignore** option. Then the **egrep** command should also check for **"I"** status character. – Craig McQueen Aug 04 '09 at 07:35
-
the rm -i option did not work for me in bash on Mac OS X. I use it with the rm -fr option. Great little snippet. – Jakob Stoeck Jan 22 '11 at 18:06
-
9You might consider adding the -d option to xargs for file names with spaces and the -r option to rm for any added directories: svn status | grep ^\? | cut -c9- | xargs -d \\n rm -r – Seth Reno Jan 26 '11 at 19:34
-
-
1It looks like the -d switch is a GNU addition to xargs; the first command works in FreeBSD. – BCran Feb 22 '11 at 17:34
-
4I also had problems with the -d option running on OS X, my alternative is as follows, which translates the linebreaks into null chars and uses the -0 option on xargs to handle spaces in filenames: svn status | grep ^\? | cut -c9- | tr '\n' '\0' | xargs -0 rm – Brian Webster Apr 15 '11 at 22:19
-
3If you frown upon commands that rely on the exact number of characters in the output of another command: `svn status | grep "^?" | awk '{print $2}' | xargs -d \\n rm -r` – Michael Schlottke-Lakemper Apr 25 '13 at 07:18
-
Can anybody update command that doesn't fail (with error return code) if there are no files to be removed? – Pavel P Sep 27 '13 at 01:47
-
3
-
I had trouble in OS X running ZSH because it interprets the ^ in the grep as a [word designator](http://tutarticle.com/technology/zsh/), so I had to wrap it in double quotes, i.e.: `svn status | grep "^\?" | cut -c9- | tr '\n' '\0' | xargs -0 rm` – HerbCSO Feb 15 '14 at 16:38
-
Usable on Windows if you have GOW installed provided you add something like `sed s=\\=/=g` before the `xargs` part to deal with the Unix-Windows path separator difference. – Joseph Wright Jan 29 '16 at 08:46
-
amazing so many up votes on something that does not work... this misses ignored files – Gus Jun 28 '16 at 18:28
-
@Gus In most cases you probably want to ignore files that you've explicitly Ignored. If not there's Craig McQueen's --no-ignore suggestion in the comments above. – Ken Jun 30 '16 at 09:02
-
@Ken that assumption is not in the question, and it was not true of my needs when I found this answer. I tried it it and it didn't work as advertised. Down vote is for wasting my time, and making me go back and read a long comment list and a bunch of other answers to find out what went wrong. If you were making additional assumptions you felt were relevant, that should be called out in your answer. This answer was not useful to me. (note the tooltip on the down vote). You are free to improve your answer by editing it. – Gus Jun 30 '16 at 12:44
-
@Gus Fair point, although I'd still argue that anything you've told subversion about explicitly is effectively under version control (even though you aren't maintaining history.) Obviously not everyone shares that assumption so I've added a couple of lines to the reply to try to clarify that. – Ken Jun 30 '16 at 14:27
-
-
WARNING: If there is a nested repository in a subdirectory, and you run this command on the outer directory, then this command deletes the nested repository. – Serge Rogatch Sep 06 '16 at 14:21
I ran across this page while looking to do the same thing, though not for an automated build.
After a bit more looking I discovered the 'Extended Context Menu' in TortoiseSVN. Hold down the shift key and right click on the working copy. There are now additional options under the TortoiseSVN menu including 'Delete unversioned items...'.
Though perhaps not applicable for this specific question (i.e. within the context of an automated build), I thought it might be helpful for others looking to do the same thing.

- 8,110
- 5
- 38
- 48
-
Great! On XP it only works in the list view (right side of explorer) not in the tree view (left side). – Christopher Oezbek Sep 29 '10 at 15:06
-
Fantastic, only send it to recycle bin, would be nice to do a straight delete. Just what i needed. – Dean Thomas Nov 16 '10 at 09:08
-
You can also automate this on the command line with TortoiseSVN's TortoiseProc.exe: details in my answer below. – stevek_mcc Sep 14 '16 at 21:40
Edit:
Subversion 1.9.0 introduced an option to do this:
svn cleanup --remove-unversioned
Before that, I use this python script to do that:
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))
It seems to do the job pretty well.

- 4,903
- 4
- 24
- 23
-
1Still works for me with Python 2.7.2. Warren P: Can you provider more details? – Thomas Watnedal Jun 23 '14 at 10:42
-
I think it was just a problem with Python 2.6. Works again for me in 2.7. – Warren P Jun 23 '14 at 14:12
-
1Downvote: The other solution from bellow `svn cleanup --remove-unversioned` is better. And it is for Subversion 1.9.0 (this version is from 2015). It is stable and standar. – tres.14159 Nov 21 '18 at 08:19
If you are on windows command line,
for /f "tokens=2*" %i in ('svn status ^| find "?"') do del %i
Improved version:
for /f "usebackq tokens=2*" %i in (`svn status ^| findstr /r "^\?"`) do svn delete --force "%i %j"
If you use this in a batch file you need to double the %
:
for /f "usebackq tokens=2*" %%i in (`svn status ^| findstr /r "^\?"`) do svn delete --force "%%i %%j"

- 5
- 2

- 91
- 1
- 1
-
1This kinda worked for me. Seemed to choke on some unversioned folders though. – jpierson Sep 21 '10 at 14:06
I added this to my windows powershell profile
function svnclean {
svn status | foreach { if($_.StartsWith("?")) { Remove-Item $_.substring(8) -Verbose } }
}

- 12,610
- 5
- 43
- 51

- 3,775
- 6
- 37
- 47
-
2@FelipeAlvarez Yes. Yes, we do. It's not the greatest thing since sliced bread, but it beats batch. I'd say it's at least as useful as bash, probably a bit more so since you can pull in .NET assemblies. – jpmc26 Mar 31 '14 at 23:03
-
It suffers from microsoft's abominable tendency towards verbosity (not just in command name length, but in overall impossibility of getting anything done without copying giant snippets from the internet), but it's shockingly useful, and rather well thought-through. – Warren P Jun 23 '14 at 14:13
-
1You may want to add `--no-ignore` to `svn status` and `-Recurse` to `Remove-Item` – Kevin Smyth Jan 07 '15 at 15:03
Just do it on unix-shell with:
rm -rf `svn st . | grep "^?" | cut -f2-9 -d' '`

- 5,233
- 2
- 41
- 40
-
This does not work if the number of to be deleted files exceeds the maximal number of command line arguments. See also the xargs based answers. – maxschlepzig Jul 22 '14 at 20:30
Subversion 1.9.0 introduced option to remove unversioned items [1]
svn cleanup --remove-unversioned
[1] https://subversion.apache.org/docs/release-notes/1.9.html#svn-cleanup-options

- 3,981
- 28
- 24
Linux command line:
svn status --no-ignore | egrep '^[?I]' | cut -c9- | xargs -d \\n rm -r
Or, if some of your files are owned by root:
svn status --no-ignore | egrep '^[?I]' | cut -c9- | sudo xargs -d \\n rm -r
This is based on Ken's answer. (Ken's answer skips ignored files; my answer deletes them).

- 10,954
- 6
- 44
- 66
Can you not just do an export to a new location and build from there?

- 115,091
- 17
- 196
- 297
-
1
-
1Ideally, you would do this, but this is problematic if your checkout is very large. That is likely the reason the OP asked: to make the build shorter. – jpmc26 Mar 31 '14 at 23:06
If you are using tortoise svn there is a hidden command to do this. Hold shift whilst right clicking on a folder to launch the context menu in windows explorer. You will get a "Delete Unversioned Items" command.
see the bottom of this page for details, or the screen shot below which highlights the extended features with the green stars, and the one of interest with the yellow rectangle...

- 7,356
- 6
- 57
- 105

- 133
- 1
- 6
If you have TortoiseSVN on your path and you are in the right directory:
TortoiseProc.exe /command:cleanup /path:"%CD%" /delunversioned /delignored /nodlg /noui
The options are described in the TortoiseSVN help for /command:cleanup
:
Use /noui to prevent the result dialog from popping up either telling about the cleanup being finished or showing an error message). /noprogressui also disables the progress dialog. /nodlg disables showing the cleanup dialog where the user can choose what exactly should be done in the cleanup. The available actions can be specified with the options /cleanup for status cleanup, /revert, /delunversioned, /delignored, /refreshshell and /externals.

- 360
- 4
- 9
My C# conversion of Thomas Watnedals Python script:
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();
}
}

- 9,240
- 6
- 35
- 42
-
I would rather move the unversioned files, just in case you need them somewhere later. – leppie Oct 27 '08 at 09:24
-
On a development machine, of course - but in the build VMware, that wouldn't make any sense cause nobody logs on to it and creates files. – Stefan Schultze Oct 28 '08 at 16:39
-
Thanks, I used this as part of my MSBuild script in cruisecontrol to clean up my source dir prior to builds – gregmac Nov 27 '09 at 15:40
-
Started off based on your code and went a ways further: https://github.com/tgmayfield/svn-clean-sharp/downloads – Tom Mayfield Oct 21 '11 at 18:26
svn st --no-ignore | grep '^[?I]' | sed 's/^[?I] *//' | xargs -r -d '\n' rm -r
This is a unix shell command to delete all files not under subversion control.
Notes:
- the
st
insvn st
is an build-in alias forstatus
, i.e. the command is equivalent tosvn status
--no-ignore
also includes non-repository files in the status output, otherwise ignores via mechanisms like.cvsignore
etc. - since the goal is to have a clean starting point for builds this switch is a must- the
grep
filters the output such that only files unknown to subversion are left - the lines beginning with?
list files unknown to subversion that would be ignored without the--no-ignore
option - the prefix up to the filename is remove via
sed
- the
xargs
command is instructed via-r
to not executerm
, when the argument list would be empty - the
-d '\n'
option tellsxargs
to use a newline as delimiter such the command also works for filenames with spaces rm -r
is used in case complete directories (that are not part of the repository) need to be removed

- 35,645
- 14
- 145
- 182
Since everyone else is doing it...
svn status | grep ^? | awk '{print $2}' | sed 's/^/.\//g' | xargs rm -R

- 4,997
- 7
- 35
- 55
svn status --no-ignore | awk '/^[I\?]/ {system("echo rm -r " $2)}'
remove the echo if that's sure what you want to do.

- 1,877
- 1
- 12
- 8
-
1This is inferior to the xargs based answers because for n to be deleted files there are n `/bin/sh` and n `rm` processes forked. – maxschlepzig Jul 22 '14 at 20:33
-
I couldn't get any of the above to work without additional dependencies I didn't want to have to add to my automated build system on win32. So I put together the following Ant commands - note these require the Ant-contrib JAR to be installed in (I was using version 1.0b3, the latest, with Ant 1.7.0).
Note this deletes all unversioned files without warning.
<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 "${basedir}""
outputProperty="status" />
<echo message="Deleting any unversioned files:" />
<for list="${status}" param="p" delimiter="
" 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>
For a different folder, change the ${basedir}
reference.
-
1Note: only deletes unversioned files; does not remove empty unversioned folders. – Apr 23 '09 at 12:45
I stumbled on svn-clean on my RH5 machine. Its located at /usr/bin/svn-clean
http://svn.apache.org/repos/asf/subversion/trunk/contrib/client-side/svn-clean

- 877
- 1
- 12
- 25
Pure windows cmd/bat solution:
@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

- 3,569
- 1
- 29
- 30

- 2,467
- 1
- 25
- 23
-
Actually this script did not delete my files. Maybe due to spaces in it. The one-line answer by @SukeshNambiar did work. – Christiaan Westerbeek Sep 19 '14 at 10:24
I've tried Seth Reno's version from this answer but it didn't worked for me. I've had 8 characters before filename, not 9 used in cut -c9-
.
So this is my version with sed
instead of cut
:
svn status | grep ^\? | sed -e 's/\?\s*//g' | xargs -d \\n rm -r

- 1
- 1

- 101
- 2
- 9
If you're cool with powershell:
svn status --no-ignore | ?{$_.SubString(0,1).Equals("?")} | foreach { remove-item -Path (join-Path .\ $_.Replace("?","").Trim()) -WhatIf }
Take out the -WhatIf flag to make the command actually perform the deletes. Otherwise it will just output what it would do if run without the -WhatIf.

- 4,569
- 1
- 22
- 24
I would add this as a comment to Thomas Watnedal's answer , but can't yet.
A minor issue with it (which won't affect Windows) is that it only checks for files or directories. For Unix like systems where symbolic links may be present, it is necessary to change the line:
if os.path.isfile(fullpath):
to
if os.path.isfile(fullpath) or os.path.islink(fullpath):
to also remove links.
For me, changing the last line if match: removeall(match.group(1))
into
if match:
print "Removing " + match.group(1)
removeall(match.group(1))
so that it displays what it is removing was useful too.
Depending on the use case, the ?[\?ID]
part of the regular expression may be better as ?[\?I]
, as the D
also removes deleted files, which were under version control. I want to use this to build in a clean, checked in folder, so there should be no files in a D
state.

- 482
- 5
- 11
@zhoufei I tested your answer and here is updated version:
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"
- You must use two
%
marks in front of G and H - Switch the order: first remove all files, then remove all directories
- (optional:) In place of
%~1
can be used any directory name, I used this as a function in a bat file, so%~1
is first input paramter

- 9,412
- 4
- 36
- 48

- 125
- 1
- 8
Might as well contribute another option
svn status | awk '{if($2 !~ /(config|\.ini)/ && !system("test -e \"" $2 "\"")) {print $2; system("rm -Rf \"" $2 "\"");}}'
The /(config|.ini)/ is for my own purposes.
And might be a good idea to add --no-ignore to the svn command

- 41
- 2
For the people that like to do this with perl instead of python, Unix shell, java, etc. Hereby a small perl script that does the jib as well.
Note: This also removes all unversioned directories
#!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();

- 41,871
- 30
- 130
- 181
A clean way to do this in PERL would be:
#!/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 ()

- 19
- 2
I used ~3 hours to generate this. It would take 5 mins to do it in Unix. The mains issue were: spaces in names for Win folders, impossibility to edit %%i and problem with defining vars in Win cmd loop.
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!
)

- 14,146
- 11
- 55
- 70

- 29
- 3
C# code snipet above did not work for me - I have tortoise svn client, and lines are formatted slightly differently. Here is same code snipet as above, only rewritten to function and using 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

- 4,723
- 2
- 50
- 62
For People on windows who wants to avoid using any tool except the standart MS-Dos commands here a solution :
FOR /F "tokens=1* delims= " %G IN ('svn st ^| findstr "^?"') DO rd /s /q "%H"
FOR /F "tokens=1* delims= " %G IN ('svn st ^| findstr "^?"') DO del /s /f /q "%H"
- svn st will display the status of each files and folder in the working copy
- findstr will look for each line starting with '?', which mean the file/folder is unversioned
- FOR will use as delimiters and take the tokens after the 1st one (the 1st one is %G, the rest is %H) This way we are exctracting the file/folder from the svn st command output.
- rd will delete folders, del will delete files.

- 41
- 7
-
I don't believe this works fully, particularly if you've got files ignored (like .obj files) you need to change 'svn st ^| findstr "^?'" to 'svn st --no-ignore ^| findstr "^[?I]"' to add ignored files to the list. – Russ Schultz Sep 14 '15 at 18:26
If you don't want to write any code, svn2.exe from svn2svn does this, also there's an article on how it's implemented. Deleted folders and files are put in the recycle bin.
Run "svn2.exe sync [path]".

- 4,700
- 2
- 46
- 51
I also found and used the following: svn status --no-ignore| awk '/^?/ {print $2}'| xargs rm

- 1
- 2
Using TortoiseSVN: * right-click on working copy folder, while holding the shift-key down * choose "delete unversioned items"
How can I delete all unversioned/ignored files/folders in my working copy?