D8030: copy: add support for unmarking committed copies
martinvonz (Martin von Zweigbergk)
phabricator at mercurial-scm.org
Mon Feb 10 23:35:11 UTC 2020
martinvonz updated this revision to Diff 20082.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D8030?vs=20069&id=20082
BRANCH
default
CHANGES SINCE LAST ACTION
https://phab.mercurial-scm.org/D8030/new/
REVISION DETAIL
https://phab.mercurial-scm.org/D8030
AFFECTED FILES
mercurial/cmdutil.py
mercurial/commands.py
mercurial/context.py
relnotes/next
tests/test-completion.t
tests/test-copy.t
tests/test-rename-after-merge.t
CHANGE DETAILS
diff --git a/tests/test-rename-after-merge.t b/tests/test-rename-after-merge.t
--- a/tests/test-rename-after-merge.t
+++ b/tests/test-rename-after-merge.t
@@ -120,4 +120,10 @@
$ hg log -r tip -C -v | grep copies
copies: b2 (b1)
+Test unmarking copies in merge commit
+
+ $ hg copy --forget -r . b2
+ abort: cannot unmark copy in merge commit
+ [255]
+
$ cd ..
diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -319,5 +319,56 @@
A dir2/bar
A dir2/foo
? dir2/untracked
+# Clean up for next test
+ $ hg forget dir2
+ removing dir2/bar
+ removing dir2/foo
+ $ rm -r dir2
+
+Test uncopy on committed copies
+
+# Commit some copies
+ $ hg cp bar baz
+ $ hg cp bar qux
+ $ hg ci -m copies
+ $ hg st -C --change .
+ A baz
+ bar
+ A qux
+ bar
+ $ base=$(hg log -r '.^' -T '{rev}')
+ $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base:
+ @ 5:a612dc2edfda copies
+ |
+ o 4:4800b1f1f38e add dir/
+ |
+ ~
+# Add a dirty change on top to show that it's unaffected
+ $ echo dirty >> baz
+ $ hg st
+ M baz
+ $ cat baz
+ bleah
+ dirty
+ $ hg copy --forget -r . baz
+ saved backup bundle to $TESTTMP/part2/.hg/strip-backup/a612dc2edfda-e36b4448-uncopy.hg
+# The unwanted copy is no longer recorded, but the unrelated one is
+ $ hg st -C --change .
+ A baz
+ A qux
+ bar
+# The old commit is gone and we have updated to the new commit
+ $ hg log -G -T '{rev}:{node|short} {desc}\n' -r $base:
+ @ 5:c45090e5effe copies
+ |
+ o 4:4800b1f1f38e add dir/
+ |
+ ~
+# Working copy still has the uncommitted change
+ $ hg st
+ M baz
+ $ cat baz
+ bleah
+ dirty
$ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -256,7 +256,7 @@
commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
config: untrusted, edit, local, global, template
continue: dry-run
- copy: forget, after, force, include, exclude, dry-run
+ copy: forget, after, rev, force, include, exclude, dry-run
debugancestor:
debugapplystreamclonebundle:
debugbuilddag: mergeable-file, overwritten-file, new-file
diff --git a/relnotes/next b/relnotes/next
--- a/relnotes/next
+++ b/relnotes/next
@@ -3,7 +3,8 @@
* `hg purge`/`hg clean` can now delete ignored files instead of
untracked files, with the new -i flag.
- * `hg copy --forget` can be used to unmark a file as copied.
+ * `hg copy --forget` can be used to unmark a file as copied. Use `hg
+ copy --forget -r REV` to unmark already committed copies.
== New Experimental Features ==
diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -2487,6 +2487,17 @@
editor=editor,
)
+ def tomemctx_for_amend(self, precursor):
+ extra = precursor.extra().copy()
+ extra[b'amend_source'] = precursor.hex()
+ return self.tomemctx(
+ text=precursor.description(),
+ branch=precursor.branch(),
+ extra=extra,
+ date=precursor.date(),
+ user=precursor.user(),
+ )
+
def isdirty(self, path):
return path in self._cache
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2312,6 +2312,13 @@
(b'', b'forget', None, _(b'unmark a file as copied')),
(b'A', b'after', None, _(b'record a copy that has already occurred')),
(
+ b'r',
+ b'rev',
+ b'',
+ _(b'unmark copies in the given revision'),
+ _(b'REV'),
+ ),
+ (
b'f',
b'force',
None,
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1419,14 +1419,33 @@
uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
if forget:
- match = scmutil.match(wctx, pats, opts)
-
- current_copies = wctx.p1copies()
- current_copies.update(wctx.p2copies())
-
- for f in wctx.walk(match):
+ rev = opts[b'rev']
+ if rev:
+ ctx = scmutil.revsingle(repo, rev)
+ else:
+ ctx = repo[None]
+ if ctx.rev() is None:
+ new_ctx = ctx
+ else:
+ if len(ctx.parents()) > 1:
+ raise error.Abort(_(b'cannot unmark copy in merge commit'))
+ # avoid cycle context -> subrepo -> cmdutil
+ from . import context
+
+ rewriteutil.precheck(repo, [ctx.rev()], b'uncopy')
+ new_ctx = context.overlayworkingctx(repo)
+ new_ctx.setbase(ctx.p1())
+ mergemod.graft(repo, ctx, wctx=new_ctx)
+
+ match = scmutil.match(ctx, pats, opts)
+
+ current_copies = ctx.p1copies()
+ current_copies.update(ctx.p2copies())
+
+ uipathfn = scmutil.getuipathfn(repo)
+ for f in ctx.walk(match):
if f in current_copies:
- wctx[f].markcopied(None)
+ new_ctx[f].markcopied(None)
elif match.exact(f):
ui.warn(
_(
@@ -1434,8 +1453,25 @@
)
% uipathfn(f)
)
+
+ if ctx.rev() is not None:
+ with repo.lock():
+ mem_ctx = new_ctx.tomemctx_for_amend(ctx)
+ new_node = mem_ctx.commit()
+
+ if repo.dirstate.p1() == ctx.node():
+ with repo.dirstate.parentchange():
+ scmutil.movedirstate(repo, repo[new_node])
+ replacements = {ctx.node(): [new_node]}
+ scmutil.cleanupnodes(
+ repo, replacements, b'uncopy', fixphase=True
+ )
+
return
+ if opts.get(b'rev'):
+ raise error.Abort(_("--rev is only supported with --forget"))
+
def walkpat(pat):
srcs = []
if after:
To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: marmoute, pulkit, durin42, mercurial-devel
More information about the Mercurial-devel
mailing list