D8030: uncopy: add support for unmarking committed copies
martinvonz (Martin von Zweigbergk)
phabricator at mercurial-scm.org
Tue Jan 28 18:59:08 EST 2020
martinvonz updated this revision to Diff 19670.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D8030?vs=19663&id=19670
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 uncopy -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 uncopy -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
@@ -357,7 +357,7 @@
tags: template
tip: patch, git, style, template
unbundle: update
- uncopy: include, exclude
+ uncopy: rev, include, exclude
unshelve: abort, continue, interactive, keep, name, tool, date
update: clean, check, merge, date, rev, tool
verify: full
diff --git a/relnotes/next b/relnotes/next
--- a/relnotes/next
+++ b/relnotes/next
@@ -1,6 +1,7 @@
== New Features ==
- * `hg uncopy` can be used to unmark a file as copied.
+ * `hg uncopy` can be used to unmark a file as copied. Use `hg uncopy -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
@@ -2488,6 +2488,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
@@ -7493,7 +7493,8 @@
@command(
b'uncopy',
- walkopts,
+ [(b'r', b'rev', b'', _(b'unmark copies in the given revision'), _(b'REV'))]
+ + walkopts,
_(b'[OPTION]... DEST...'),
helpcategory=command.CATEGORY_FILE_CONTENTS,
)
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1695,7 +1695,23 @@
def uncopy(ui, repo, pats, opts):
- ctx = repo[None]
+ 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)
@@ -1705,13 +1721,24 @@
uipathfn = scmutil.getuipathfn(repo)
for f in ctx.walk(match):
if f in current_copies:
- ctx[f].markcopied(None)
+ new_ctx[f].markcopied(None)
elif match.exact(f):
ui.warn(
_(b'%s: not uncopying - file is not marked as copied\n')
% 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)
+
## facility to let extension process additional data into an import patch
# list of identifier to be executed in order
To: martinvonz, #hg-reviewers
Cc: mercurial-devel
More information about the Mercurial-devel
mailing list