diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py --- a/mercurial/cmdutil.py +++ b/mercurial/cmdutil.py @@ -1201,6 +1201,48 @@ def add(ui, repo, match, dryrun, listsub bad.extend(f for f in rejected if f in match.files()) return bad +def forget(ui, repo, match, prefix, explicitonly): + join = lambda f: os.path.join(prefix, f) + bad = [] + oldbad = match.bad + match.bad = lambda x, y: bad.append(x) or oldbad(x, y) + wctx = repo[None] + forgot = [] + s = repo.status(match=match, clean=True) + forget = sorted(s[0] + s[1] + s[3] + s[6]) + if explicitonly: + forget = [f for f in forget if match.exact(f)] + + for subpath in wctx.substate: + sub = wctx.sub(subpath) + try: + submatch = matchmod.narrowmatcher(subpath, match) + subbad, subforgot = sub.forget(ui, submatch, prefix) + bad.extend([subpath + '/' + f for f in subbad]) + forgot.extend([subpath + '/' + f for f in subforgot]) + except error.LookupError: + ui.status(_("skipping missing subrepository: %s\n") + % join(subpath)) + + for f in match.files(): + if match.exact(f) or not explicitonly: + if f not in repo.dirstate and not os.path.isdir(match.rel(join(f))): + if f not in forgot: + if os.path.exists(match.rel(join(f))): + ui.warn(_('not removing %s: ' + 'file is already untracked\n') + % match.rel(join(f))) + bad.append(f) + + for f in forget: + if ui.verbose or not match.exact(f): + ui.status(_('removing %s\n') % match.rel(join(f))) + + rejected = wctx.forget(forget, prefix) + bad.extend(f for f in rejected if f in match.files()) + forgot.extend(forget) + return bad, forgot + def duplicatecopies(repo, rev, p1): "Reproduce copies found in the source revision in the dirstate for grafts" for dst, src in copies.pathcopies(repo[p1], repo[rev]).iteritems(): diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -13,7 +13,6 @@ import hg, scmutil, util, revlog, extens import patch, help, url, encoding, templatekw, discovery import archival, changegroup, cmdutil, hbisect import sshserver, hgweb, hgweb.server, commandserver -import match as matchmod import merge as mergemod import minirst, revset, fileset import dagparser, context, simplemerge @@ -2449,46 +2448,9 @@ def forget(ui, repo, *pats, **opts): if not pats: raise util.Abort(_('no files specified')) - wctx = repo[None] - m = scmutil.match(wctx, pats, opts) - s = repo.status(match=m, clean=True) - forget = sorted(s[0] + s[1] + s[3] + s[6]) - subforget = {} - errs = 0 - - for subpath in wctx.substate: - sub = wctx.sub(subpath) - try: - submatch = matchmod.narrowmatcher(subpath, m) - for fsub in sub.walk(submatch): - if submatch.exact(fsub): - subforget[subpath + '/' + fsub] = (fsub, sub) - except error.LookupError: - ui.status(_("skipping missing subrepository: %s\n") % subpath) - - for f in m.files(): - if f not in repo.dirstate and not os.path.isdir(m.rel(f)): - if f not in subforget: - if os.path.exists(m.rel(f)): - ui.warn(_('not removing %s: file is already untracked\n') - % m.rel(f)) - errs = 1 - - for f in forget: - if ui.verbose or not m.exact(f): - ui.status(_('removing %s\n') % m.rel(f)) - - if ui.verbose: - for f in sorted(subforget.keys()): - ui.status(_('removing %s\n') % m.rel(f)) - - wctx.forget(forget) - - for f in sorted(subforget.keys()): - fsub, sub = subforget[f] - sub.forget([fsub]) - - return errs + m = scmutil.match(repo[None], pats, opts) + rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0] + return rejected and 1 or 0 @command( 'graft', diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -900,16 +900,20 @@ class workingctx(changectx): finally: wlock.release() - def forget(self, files): + def forget(self, files, prefix=""): + join = lambda f: os.path.join(prefix, f) wlock = self._repo.wlock() try: + rejected = [] for f in files: if self._repo.dirstate[f] != 'a': self._repo.dirstate.remove(f) elif f not in self._repo.dirstate: - self._repo.ui.warn(_("%s not tracked!\n") % f) + self._repo.ui.warn(_("%s not tracked!\n") % join(f)) + rejected.append(f) else: self._repo.dirstate.drop(f) + return rejected finally: wlock.release() diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -360,8 +360,8 @@ class abstractsubrepo(object): ''' pass - def forget(self, files): - pass + def forget(self, ui, match, prefix): + return [] class hgsubrepo(abstractsubrepo): def __init__(self, ctx, path, state): @@ -561,9 +561,9 @@ class hgsubrepo(abstractsubrepo): ctx = self._repo[None] return ctx.walk(match) - def forget(self, files): - ctx = self._repo[None] - ctx.forget(files) + def forget(self, ui, match, prefix): + return cmdutil.forget(ui, self._repo, match, + os.path.join(prefix, self._path), True) class svnsubrepo(abstractsubrepo): def __init__(self, ctx, path, state): diff --git a/tests/test-subrepo-recursion.t b/tests/test-subrepo-recursion.t --- a/tests/test-subrepo-recursion.t +++ b/tests/test-subrepo-recursion.t @@ -197,12 +197,6 @@ Test explicit path commands within subre A foo/bar/z2.txt This is expected to forget the file, but is currently broken $ hg forget foo/bar/z2.txt - not removing foo/bar/z2.txt: file is already untracked - [1] - $ hg status -S - A foo/bar/z2.txt -When fixed, remove the next two commands - $ hg forget -R foo/bar foo/bar/z2.txt $ hg status -S ? foo/bar/z2.txt $ rm foo/bar/z2.txt