diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -1552,7 +1552,7 @@ # Calling purge with --all will cause the largefiles to be deleted. # Override repo.status to prevent this from happening. -@eh.wrapcommand(b'purge', extension=b'purge') +@eh.wrapcommand(b'purge') def overridepurge(orig, ui, repo, *dirs, **opts): # XXX Monkey patching a repoview will not work. The assigned attribute will # be set on the unfiltered repo, but we will only lookup attributes in the diff --git a/hgext/purge.py b/hgext/purge.py --- a/hgext/purge.py +++ b/hgext/purge.py @@ -22,115 +22,14 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see . -'''command to delete untracked files from the working directory''' -from __future__ import absolute_import - -from mercurial.i18n import _ -from mercurial import ( - cmdutil, - merge as mergemod, - pycompat, - registrar, - scmutil, -) - -cmdtable = {} -command = registrar.command(cmdtable) -# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for -# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should -# be specifying the version(s) of Mercurial they are tested with, or -# leave the attribute unspecified. -testedwith = b'ships-with-hg-core' - - -@command( - b'purge|clean', - [ - (b'a', b'abort-on-err', None, _(b'abort if an error occurs')), - (b'', b'all', None, _(b'purge ignored files too')), - (b'i', b'ignored', None, _(b'purge only ignored files')), - (b'', b'dirs', None, _(b'purge empty directories')), - (b'', b'files', None, _(b'purge files')), - (b'p', b'print', None, _(b'print filenames instead of deleting them')), - ( - b'0', - b'print0', - None, - _( - b'end filenames with NUL, for use with xargs' - b' (implies -p/--print)' - ), - ), - ] - + cmdutil.walkopts, - _(b'hg purge [OPTION]... [DIR]...'), - helpcategory=command.CATEGORY_WORKING_DIRECTORY, -) -def purge(ui, repo, *dirs, **opts): - '''removes files not tracked by Mercurial - - Delete files not known to Mercurial. This is useful to test local - and uncommitted changes in an otherwise-clean source tree. - - This means that purge will delete the following by default: - - - Unknown files: files marked with "?" by :hg:`status` - - Empty directories: in fact Mercurial ignores directories unless - they contain files under source control management +'''command to delete untracked files from the working directory (DEPRECATED) - But it will leave untouched: - - - Modified and unmodified tracked files - - Ignored files (unless -i or --all is specified) - - New files added to the repository (with :hg:`add`) - - The --files and --dirs options can be used to direct purge to delete - only files, only directories, or both. If neither option is given, - both will be deleted. - - If directories are given on the command line, only files in these - directories are considered. - - Be careful with purge, as you could irreversibly delete some files - you forgot to add to the repository. If you only want to print the - list of files that this program would delete, use the --print - option. - ''' - opts = pycompat.byteskwargs(opts) - cmdutil.check_at_most_one_arg(opts, b'all', b'ignored') +The functionality of this extension has been included in core Mercurial since +version 5.7. Please use :hg:`purge ...` instead. However it is not exactly +equivalent: without the extension, one of -i, -u or --all must be specified. +With the extension, -u is assumed if none of these flags are specified. - act = not opts.get(b'print') - eol = b'\n' - if opts.get(b'print0'): - eol = b'\0' - act = False # --print0 implies --print - if opts.get(b'all', False): - ignored = True - unknown = True - else: - ignored = opts.get(b'ignored', False) - unknown = not ignored - - removefiles = opts.get(b'files') - removedirs = opts.get(b'dirs') +''' - if not removefiles and not removedirs: - removefiles = True - removedirs = True - - match = scmutil.match(repo[None], dirs, opts) - - paths = mergemod.purge( - repo, - match, - unknown=unknown, - ignored=ignored, - removeemptydirs=removedirs, - removefiles=removefiles, - abortonerror=opts.get(b'abort_on_err'), - noop=not act, - ) - - for path in paths: - if not act: - ui.write(b'%s%s' % (path, eol)) +# This empty extension looks pointless, but core mercurial checks if it's loaded +# to implement the slightly different behavior documented above. diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -5382,6 +5382,112 @@ other.close() return ret +@command( + b'purge|clean', + [ + (b'a', b'abort-on-err', None, _(b'abort if an error occurs')), + (b'', b'all', None, _(b'purge ignored files too')), + (b'i', b'ignored', None, _(b'purge only ignored files')), + (b'u', b'unknown', None, _(b'purge only unknown files')), + (b'', b'dirs', None, _(b'purge empty directories')), + (b'', b'files', None, _(b'purge files')), + (b'p', b'print', None, _(b'print filenames instead of deleting them')), + ( + b'0', + b'print0', + None, + _( + b'end filenames with NUL, for use with xargs' + b' (implies -p/--print)' + ), + ), + ] + + cmdutil.walkopts, + _(b'hg purge [OPTION]... [DIR]...'), + helpcategory=command.CATEGORY_WORKING_DIRECTORY, +) +def purge(ui, repo, *dirs, **opts): + '''removes files not tracked by Mercurial + + Delete files not known to Mercurial. This is useful to test local + and uncommitted changes in an otherwise-clean source tree. + + purge can delete: + + - Unknown files: files marked with "?" by :hg:`status` + - Ignored files + - Empty directories: in fact Mercurial ignores directories unless + they contain files under source control management + + Unknown files are selected with -u, ignored files with -i, and + both with --all. At least one such flag must be provided. Empty + directories are deleted by default. + + But it will leave untouched: + + - Modified and unmodified tracked files + - New files added to the repository (with :hg:`add`) + + The --files and --dirs options can be used to direct purge to delete + only files, only directories, or both. If neither option is given, + both will be deleted. + + If directories are given on the command line, only files in these + directories are considered. + + Be careful with purge, as you could irreversibly delete some files + you forgot to add to the repository. If you only want to print the + list of files that this program would delete, use the --print + option. + ''' + opts = pycompat.byteskwargs(opts) + cmdutil.check_at_most_one_arg(opts, b'all', b'ignored') + cmdutil.check_at_most_one_arg(opts, b'all', b'unknown') + + act = not opts.get(b'print') + eol = b'\n' + if opts.get(b'print0'): + eol = b'\0' + act = False # --print0 implies --print + if opts.get(b'all', False): + ignored = True + unknown = True + else: + ignored = opts.get(b'ignored', False) + unknown = opts.get(b'unknown', False) + if not unknown and not ignored: + # If the extension is loaded, we clean unknown files for compatibility. + # If it is not loaded, we refuse to work to reduce the risk of mistakes. + try: + extensions.find(b'purge') + unknown = True + except KeyError: + raise error.Abort(_(b"please specify what to purge with -i, -u or --all")) + + removefiles = opts.get(b'files') + removedirs = opts.get(b'dirs') + + if not removefiles and not removedirs: + removefiles = True + removedirs = True + + match = scmutil.match(repo[None], dirs, opts) + + paths = mergemod.purge( + repo, + match, + unknown=unknown, + ignored=ignored, + removeemptydirs=removedirs, + removefiles=removefiles, + abortonerror=opts.get(b'abort_on_err'), + noop=not act, + ) + + for path in paths: + if not act: + ui.write(b'%s%s' % (path, eol)) + @command( b'push', diff --git a/relnotes/next b/relnotes/next --- a/relnotes/next +++ b/relnotes/next @@ -4,6 +4,9 @@ * The memory footprint per changeset and per file during pull/unbundle operations has been significantly reduced. + * `hg purge` is now a core command. See `hg help -e purge` for how it + compares to the behavior of `hg purge` when the purge extension is + loaded. == New Experimental Features == diff --git a/tests/test-completion.t b/tests/test-completion.t --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -38,6 +38,7 @@ paths phase pull + purge push recover remove @@ -352,6 +353,7 @@ paths: template phase: public, draft, secret, force, rev pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure + purge: abort-on-err, all, ignored, unknown, dirs, files, print, print0, include, exclude push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure recover: verify remove: after, force, subrepos, include, exclude, dry-run diff --git a/tests/test-globalopts.t b/tests/test-globalopts.t --- a/tests/test-globalopts.t +++ b/tests/test-globalopts.t @@ -351,6 +351,7 @@ addremove add all new files, delete all missing files files list tracked files forget forget the specified files on the next commit + purge removes files not tracked by Mercurial remove remove the specified files on the next commit rename rename files; equivalent of copy + remove resolve redo merges or set/view the merge status of files @@ -483,6 +484,7 @@ addremove add all new files, delete all missing files files list tracked files forget forget the specified files on the next commit + purge removes files not tracked by Mercurial remove remove the specified files on the next commit rename rename files; equivalent of copy + remove resolve redo merges or set/view the merge status of files diff --git a/tests/test-help-hide.t b/tests/test-help-hide.t --- a/tests/test-help-hide.t +++ b/tests/test-help-hide.t @@ -55,6 +55,7 @@ addremove add all new files, delete all missing files files list tracked files forget forget the specified files on the next commit + purge removes files not tracked by Mercurial remove remove the specified files on the next commit rename rename files; equivalent of copy + remove resolve redo merges or set/view the merge status of files @@ -191,6 +192,7 @@ addremove add all new files, delete all missing files files list tracked files forget forget the specified files on the next commit + purge removes files not tracked by Mercurial remove remove the specified files on the next commit rename rename files; equivalent of copy + remove resolve redo merges or set/view the merge status of files diff --git a/tests/test-help.t b/tests/test-help.t --- a/tests/test-help.t +++ b/tests/test-help.t @@ -107,6 +107,7 @@ addremove add all new files, delete all missing files files list tracked files forget forget the specified files on the next commit + purge removes files not tracked by Mercurial remove remove the specified files on the next commit rename rename files; equivalent of copy + remove resolve redo merges or set/view the merge status of files @@ -235,6 +236,7 @@ addremove add all new files, delete all missing files files list tracked files forget forget the specified files on the next commit + purge removes files not tracked by Mercurial remove remove the specified files on the next commit rename rename files; equivalent of copy + remove resolve redo merges or set/view the merge status of files @@ -375,8 +377,6 @@ mq manage a stack of patches notify hooks for sending email push notifications patchbomb command to send changesets as (a series of) patch emails - purge command to delete untracked files from the working - directory relink recreates hardlinks between repository clones schemes extend schemes with shortcuts to repository swarms share share a common history between several working directories @@ -2703,6 +2703,13 @@ set or show the current phase name + + purge + + + removes files not tracked by Mercurial + + recover diff --git a/tests/test-hgweb-json.t b/tests/test-hgweb-json.t --- a/tests/test-hgweb-json.t +++ b/tests/test-hgweb-json.t @@ -2190,6 +2190,10 @@ "topic": "phase" }, { + "summary": "removes files not tracked by Mercurial", + "topic": "purge" + }, + { "summary": "roll back an interrupted transaction", "topic": "recover" }, diff --git a/tests/test-purge.t b/tests/test-purge.t --- a/tests/test-purge.t +++ b/tests/test-purge.t @@ -1,8 +1,3 @@ - $ cat <> $HGRCPATH - > [extensions] - > purge = - > EOF - init $ hg init t @@ -18,6 +13,25 @@ $ echo 'ignored' > .hgignore $ hg ci -qAmr3 -d'2 0' +purge without the extension + + $ hg st + $ touch foo + $ hg purge + abort: please specify what to purge with -i, -u or --all + [255] + $ hg st + ? foo + $ hg purge -u + $ hg st + +now enabling the extension + + $ cat <> $HGRCPATH + > [extensions] + > purge = + > EOF + delete an empty directory $ mkdir empty_dir