diff --git a/hgext/mq.py b/hgext/mq.py --- a/hgext/mq.py +++ b/hgext/mq.py @@ -554,14 +554,17 @@ class queue(object): except OSError, inst: self.ui.warn(_('error removing undo: %s\n') % str(inst)) - def backup(self, repo, files): + def backup(self, repo, files, copy=False): # backup local changes in --force case for f in sorted(files): absf = repo.wjoin(f) if os.path.lexists(absf): self.ui.note(_('saving current version of %s as %s\n') % (f, f + '.orig')) - util.rename(absf, absf + '.orig') + if copy: + util.copyfile(absf, absf + '.orig') + else: + util.rename(absf, absf + '.orig') def printdiff(self, repo, diffopts, node1, node2=None, files=None, fp=None, changes=None, opts={}): @@ -677,7 +680,8 @@ class queue(object): return (False, list(files), False) def apply(self, repo, series, list=False, update_status=True, - strict=False, patchdir=None, merge=None, all_files=None): + strict=False, patchdir=None, merge=None, all_files=None, + tobackup=None): wlock = lock = tr = None try: wlock = repo.wlock() @@ -685,7 +689,8 @@ class queue(object): tr = repo.transaction("qpush") try: ret = self._apply(repo, series, list, update_status, - strict, patchdir, merge, all_files=all_files) + strict, patchdir, merge, all_files=all_files, + tobackup=tobackup) tr.close() self.savedirty() return ret @@ -702,9 +707,14 @@ class queue(object): self.removeundo(repo) def _apply(self, repo, series, list=False, update_status=True, - strict=False, patchdir=None, merge=None, all_files=None): - '''returns (error, hash) - error = 1 for unable to read, 2 for patch failed, 3 for patch fuzz''' + strict=False, patchdir=None, merge=None, all_files=None, + tobackup=None): + """returns (error, hash) + + error = 1 for unable to read, 2 for patch failed, 3 for patch + fuzz. tobackup is None or a set of files to backup before they + are modified by a patch. + """ # TODO unify with commands.py if not patchdir: patchdir = self.path @@ -736,6 +746,11 @@ class queue(object): message = '\n'.join(message) if ph.haspatch: + if tobackup: + touched = patchmod.changedfiles(self.ui, repo, pf) + touched = set(touched) & tobackup + self.backup(repo, touched, copy=True) + tobackup = tobackup - touched (patcherr, files, fuzz) = self.patch(repo, pf) if all_files is not None: all_files.update(files) @@ -1241,13 +1256,19 @@ class queue(object): else: end = self.series.index(patch, start) + 1 + tobackup = set() + if force: + m, a, r, d = self.checklocalchanges(repo, force=True) + tobackup.update(m + a) + s = self.series[start:end] all_files = set() try: if mergeq: ret = self.mergepatch(repo, mergeq, s, diffopts) else: - ret = self.apply(repo, s, list, all_files=all_files) + ret = self.apply(repo, s, list, all_files=all_files, + tobackup=tobackup) except: self.ui.warn(_('cleaning up working directory...')) node = repo.dirstate.p1() diff --git a/tests/test-mq-qpush-fail.t b/tests/test-mq-qpush-fail.t --- a/tests/test-mq-qpush-fail.t +++ b/tests/test-mq-qpush-fail.t @@ -188,3 +188,52 @@ test qpop --force and backup files bb $ cat c.orig cc + +test qpush --force and backup files + + $ echo a >> a + $ hg qnew p2 + $ echo b >> b + $ echo d > d + $ echo e > e + $ hg add d e + $ hg rm c + $ hg qnew p3 + $ hg qpop -a + popping p3 + popping p2 + patch queue now empty + $ echo a >> a + $ echo b1 >> b + $ echo d1 > d + $ hg add d + $ echo e1 > e + $ hg qpush -a --force --verbose + applying p2 + saving current version of a as a.orig + patching file a + a + applying p3 + saving current version of b as b.orig + saving current version of d as d.orig + patching file b + patching file c + patching file d + file d already exists + 1 out of 1 hunks FAILED -- saving rejects to file d.rej + patching file e + file e already exists + 1 out of 1 hunks FAILED -- saving rejects to file e.rej + patch failed to apply + b + patch failed, rejects left in working dir + errors during apply, please fix and refresh p3 + [2] + $ cat a.orig + a + a + $ cat b.orig + b + b1 + $ cat d.orig + d1 diff --git a/tests/test-mq.t b/tests/test-mq.t --- a/tests/test-mq.t +++ b/tests/test-mq.t @@ -1356,11 +1356,15 @@ qpush should fail, local changes apply force, should discard changes in hello, but not bye - $ hg qpush -f + $ hg qpush -f --verbose applying empty + saving current version of hello.txt as hello.txt.orig + patching file hello.txt + hello.txt now at: empty $ hg st M bye.txt + ? hello.txt.orig $ hg diff --config diff.nodates=True diff -r ba252371dbc1 bye.txt --- a/bye.txt