D8029: copy: add option to unmark file as copied

2020-02-15 Thread martinvonz (Martin von Zweigbergk)
Closed by commit rHG8be0c63535b5: copy: add option to unmark file as copied 
(authored by martinvonz).
This revision was automatically updated to reflect the committed changes.
This revision was not accepted when it landed; it landed in state "Needs 
Review".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8029?vs=20204=20241

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  relnotes/next
  tests/test-completion.t
  tests/test-copy.t

CHANGE DETAILS

diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -262,5 +262,62 @@
   xyzzy: not overwriting - file exists
   ('hg copy --after' to record the copy)
   [1]
+  $ hg co -qC .
+  $ rm baz xyzzy
+
+
+Test unmarking copy of a single file
+
+# Set up by creating a copy
+  $ hg cp bar baz
+# Test uncopying a non-existent file
+  $ hg copy --forget non-existent
+  non-existent: $ENOENT$
+# Test uncopying an tracked but unrelated file
+  $ hg copy --forget foo
+  foo: not unmarking as copy - file is not marked as copied
+# Test uncopying a copy source
+  $ hg copy --forget bar
+  bar: not unmarking as copy - file is not marked as copied
+# baz should still be marked as a copy
+  $ hg st -C
+  A baz
+bar
+# Test the normal case
+  $ hg copy --forget baz
+  $ hg st -C
+  A baz
+# Test uncopy with matching an non-matching patterns
+  $ hg cp bar baz --after
+  $ hg copy --forget bar baz
+  bar: not unmarking as copy - file is not marked as copied
+  $ hg st -C
+  A baz
+# Test uncopy with no exact matches
+  $ hg cp bar baz --after
+  $ hg copy --forget .
+  $ hg st -C
+  A baz
+  $ hg forget baz
+  $ rm baz
+
+Test unmarking copy of a directory
+
+  $ mkdir dir
+  $ echo foo > dir/foo
+  $ echo bar > dir/bar
+  $ hg add dir
+  adding dir/bar
+  adding dir/foo
+  $ hg ci -m 'add dir/'
+  $ hg cp dir dir2
+  copying dir/bar to dir2/bar
+  copying dir/foo to dir2/foo
+  $ touch dir2/untracked
+  $ hg copy --forget dir2
+  $ hg st -C
+  A dir2/bar
+  A dir2/foo
+  ? dir2/untracked
 
   $ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -257,7 +257,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: after, force, include, exclude, dry-run
+  copy: forget, after, 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
@@ -12,6 +12,8 @@
commits that are being merged, when there are conflicts. Also works
for conflicts caused by e.g. `hg graft`.
 
+ * `hg copy --forget` can be used to unmark a file as copied.
+
 
 == New Experimental Features ==
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2309,6 +2309,7 @@
 @command(
 b'copy|cp',
 [
+(b'', b'forget', None, _(b'unmark a file as copied')),
 (b'A', b'after', None, _(b'record a copy that has already occurred')),
 (
 b'f',
@@ -2333,8 +2334,11 @@
 exist in the working directory. If invoked with -A/--after, the
 operation is recorded, but no copying is performed.
 
-This command takes effect with the next commit. To undo a copy
-before that, see :hg:`revert`.
+To undo marking a file as copied, use --forget. With that option,
+all given (positional) arguments are unmarked as copies. The destination
+file(s) will be left in place (still tracked).
+
+This command takes effect with the next commit.
 
 Returns 0 on success, 1 if errors are encountered.
 """
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1410,12 +1410,15 @@
 
 
 def copy(ui, repo, pats, opts, rename=False):
+check_incompatible_arguments(opts, b'forget', [b'dry_run'])
+
 # called with the repo lock held
 #
 # hgsep => pathname that uses "/" to separate directories
 # ossep => pathname that uses os.sep to separate directories
 cwd = repo.getcwd()
 targets = {}
+forget = opts.get(b"forget")
 after = opts.get(b"after")
 dryrun = opts.get(b"dry_run")
 ctx = repo[None]
@@ -1423,6 +1426,24 @@
 
 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):
+if f in current_copies:
+wctx[f].markcopied(None)
+

D8029: copy: add option to unmark file as copied

2020-02-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> marmoute wrote in commands.py:2339
> The other command with variable number of arguments I can think of usually 
> mark them as optional in their synopsis (eg: `hg bookmarks`), but I feel like 
> the situation in a bit different.
> 
> The new doc is clearer, but still not very clear. Can you try adding the 
> synopsis to see how it looks like?
> 
> An alternative is to augment the help test to support multiple synopsys, "it 
> can't be that hard".

I'll let other reviewers decide if it's worth blocking the patch or series for 
that. I think it's quite clear already.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread marmoute (Pierre-Yves David)
marmoute added inline comments.

INLINE COMMENTS

> martinvonz wrote in commands.py:2339
> Hmm, do we do that elsewhere? It would seem out of place to me, but if 
> there's precedent for doing it, I can do it here too.

The other command with variable number of arguments I can think of usually mark 
them as optional in their synopsis (eg: `hg bookmarks`), but I feel like the 
situation in a bit different.

The new doc is clearer, but still not very clear. Can you try adding the 
synopsis to see how it looks like?

An alternative is to augment the help test to support multiple synopsys, "it 
can't be that hard".

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> marmoute wrote in commands.py:2339
> What i mean is to put the equivalent of a synopsys line inside the 
> documentation text at tle location where --forget is defined.

Hmm, do we do that elsewhere? It would seem out of place to me, but if there's 
precedent for doing it, I can do it here too.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread marmoute (Pierre-Yves David)
marmoute added inline comments.

INLINE COMMENTS

> martinvonz wrote in commands.py:2339
> > What I find the most confusing part is the piece refering to SOURCE and 
> > DEST for an 
> > operation that as no such pair. I would refer to an explicite TARGET 
> > argument and
> > include some kind of synopsys (at that location in the documentation)
> 
> I tried to add a separate synopsis line for `--forget`, as I said in 
> https://phab.mercurial-scm.org/D8029#120191.
> 
> I'll still update the comment here to not refer to SOURCE and DEST since it's 
> clearly confusing you, but I don't want to refer to TARGET or FILE either 
> since that's not defined anywhere.

What i mean is to put the equivalent of a synopsys line inside the 
documentation text at tle location where --forget is defined.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz updated this revision to Diff 20204.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8029?vs=20199=20204

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  relnotes/next
  tests/test-completion.t
  tests/test-copy.t

CHANGE DETAILS

diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -262,5 +262,62 @@
   xyzzy: not overwriting - file exists
   ('hg copy --after' to record the copy)
   [1]
+  $ hg co -qC .
+  $ rm baz xyzzy
+
+
+Test unmarking copy of a single file
+
+# Set up by creating a copy
+  $ hg cp bar baz
+# Test uncopying a non-existent file
+  $ hg copy --forget non-existent
+  non-existent: $ENOENT$
+# Test uncopying an tracked but unrelated file
+  $ hg copy --forget foo
+  foo: not unmarking as copy - file is not marked as copied
+# Test uncopying a copy source
+  $ hg copy --forget bar
+  bar: not unmarking as copy - file is not marked as copied
+# baz should still be marked as a copy
+  $ hg st -C
+  A baz
+bar
+# Test the normal case
+  $ hg copy --forget baz
+  $ hg st -C
+  A baz
+# Test uncopy with matching an non-matching patterns
+  $ hg cp bar baz --after
+  $ hg copy --forget bar baz
+  bar: not unmarking as copy - file is not marked as copied
+  $ hg st -C
+  A baz
+# Test uncopy with no exact matches
+  $ hg cp bar baz --after
+  $ hg copy --forget .
+  $ hg st -C
+  A baz
+  $ hg forget baz
+  $ rm baz
+
+Test unmarking copy of a directory
+
+  $ mkdir dir
+  $ echo foo > dir/foo
+  $ echo bar > dir/bar
+  $ hg add dir
+  adding dir/bar
+  adding dir/foo
+  $ hg ci -m 'add dir/'
+  $ hg cp dir dir2
+  copying dir/bar to dir2/bar
+  copying dir/foo to dir2/foo
+  $ touch dir2/untracked
+  $ hg copy --forget dir2
+  $ hg st -C
+  A dir2/bar
+  A dir2/foo
+  ? dir2/untracked
 
   $ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -257,7 +257,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: after, force, include, exclude, dry-run
+  copy: forget, after, 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
@@ -12,6 +12,8 @@
commits that are being merged, when there are conflicts. Also works
for conflicts caused by e.g. `hg graft`.
 
+ * `hg copy --forget` can be used to unmark a file as copied.
+
 
 == New Experimental Features ==
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2309,6 +2309,7 @@
 @command(
 b'copy|cp',
 [
+(b'', b'forget', None, _(b'unmark a file as copied')),
 (b'A', b'after', None, _(b'record a copy that has already occurred')),
 (
 b'f',
@@ -2333,8 +2334,11 @@
 exist in the working directory. If invoked with -A/--after, the
 operation is recorded, but no copying is performed.
 
-This command takes effect with the next commit. To undo a copy
-before that, see :hg:`revert`.
+To undo marking a file as copied, use --forget. With that option,
+all given (positional) arguments are unmarked as copies. The destination
+file(s) will be left in place (still tracked).
+
+This command takes effect with the next commit.
 
 Returns 0 on success, 1 if errors are encountered.
 """
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1410,12 +1410,15 @@
 
 
 def copy(ui, repo, pats, opts, rename=False):
+check_incompatible_arguments(opts, b'forget', [b'dry_run'])
+
 # called with the repo lock held
 #
 # hgsep => pathname that uses "/" to separate directories
 # ossep => pathname that uses os.sep to separate directories
 cwd = repo.getcwd()
 targets = {}
+forget = opts.get(b"forget")
 after = opts.get(b"after")
 dryrun = opts.get(b"dry_run")
 ctx = repo[None]
@@ -1423,6 +1426,24 @@
 
 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):
+if f in current_copies:
+wctx[f].markcopied(None)
+elif match.exact(f):
+ui.warn(
+_(
+b'%s: not unmarking as copy - file is not marked as 
copied\n'
+)
+   

D8029: copy: add option to unmark file as copied

2020-02-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> marmoute wrote in commands.py:2339
> doing `hg cp a b` does not add copies information to `a`, so I don't think 
> there would be confusion from the users.
> 
> What I find the most confusing part is the piece refering to `SOURCE` and 
> `DEST` for an operation that as no such pair. I would refer to an explicite 
> `TARGET` argument and include some kind of synopsys (at that location in the 
> documentation)

> What I find the most confusing part is the piece refering to SOURCE and DEST 
> for an 
> operation that as no such pair. I would refer to an explicite TARGET argument 
> and
> include some kind of synopsys (at that location in the documentation)

I tried to add a separate synopsis line for `--forget`, as I said in 
https://phab.mercurial-scm.org/D8029#120191.

I'll still update the comment here to not refer to SOURCE and DEST since it's 
clearly confusing you, but I don't want to refer to TARGET or FILE either since 
that's not defined anywhere.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread marmoute (Pierre-Yves David)
marmoute added inline comments.

INLINE COMMENTS

> martinvonz wrote in commands.py:2339
> If you first do `hg cp a b`, you can't then do `hg cp --forget a`, it needs 
> to be the destination. The "SOURCE" and "DEST" names refer to the names in 
> the synopsis. I was trying to clarify that that they're treated the same, but 
> maybe there will be no confusion and I should not mention it?

doing `hg cp a b` does not add copies information to `a`, so I don't think 
there would be confusion from the users.

What I find the most confusing part is the piece refering to `SOURCE` and 
`DEST` for an operation that as no such pair. I would refer to an explicite 
`TARGET` argument and include some kind of synopsys (at that location in the 
documentation)

> martinvonz wrote in test-copy.t:304
> I'll leave that for a follow-up. I don't think it should be a requirement.

Okay that seems fair. Do you think you could impletement that before 5.4 ?

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz added inline comments.

INLINE COMMENTS

> marmoute wrote in cmdutil.py:1413
> Why are these two incompatible ? I can imagine running `--forget` with 
> `--dryrun`

Just not implemented yet. Are you asking just out of curiosity or do you think 
it needs to be clarified to the user?

> marmoute wrote in commands.py:2339
> I find this text a bit confusing. Do you mean the the synopsys is `hg copy 
> --forget FILE` ?
> 
> If so, what about something like:
> 
>   To undo marking a file as copied, use --forget. In that case, any copy 
> informations attached to the command argument will be forgotten: `hg copy 
> --forget FILE+`. The target file(s) will be left in place (still tracked).

If you first do `hg cp a b`, you can't then do `hg cp --forget a`, it needs to 
be the destination. The "SOURCE" and "DEST" names refer to the names in the 
synopsis. I was trying to clarify that that they're treated the same, but maybe 
there will be no confusion and I should not mention it?

> marmoute wrote in test-copy.t:304
> This block will be a great place to add a `--dry-run` test ;-).

I'll leave that for a follow-up. I don't think it should be a requirement.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread marmoute (Pierre-Yves David)
This revision now requires changes to proceed.
marmoute added a comment.
marmoute requested changes to this revision.


  The UI seems good, but it seems like we should have `--dry-run` supports and 
I find the help text confusing (I made improvement suggestion).

INLINE COMMENTS

> cmdutil.py:1413
>  def copy(ui, repo, pats, opts, rename=False):
> +check_incompatible_arguments(opts, b'forget', [b'dry_run'])
> +

Why are these two incompatible ? I can imagine running `--forget` with 
`--dryrun`

> cmdutil.py:1421
>  targets = {}
> +forget = opts.get(b"forget")
>  after = opts.get(b"after")

Thanks for updating the UI to forget ☺

> commands.py:2339
> +both SOURCE and DEST are interpreted as destinations. The destination
> +file(s) will be left in place (still tracked).
> +

I find this text a bit confusing. Do you mean the the synopsys is `hg copy 
--forget FILE` ?

If so, what about something like:

  To undo marking a file as copied, use --forget. In that case, any copy 
informations attached to the command argument will be forgotten: `hg copy 
--forget FILE+`. The target file(s) will be left in place (still tracked).

> test-copy.t:304
> +
> +Test unmarking copy of a directory
> +

This block will be a great place to add a `--dry-run` test ;-).

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz updated this revision to Diff 20199.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8029?vs=20174=20199

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  relnotes/next
  tests/test-completion.t
  tests/test-copy.t

CHANGE DETAILS

diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -262,5 +262,62 @@
   xyzzy: not overwriting - file exists
   ('hg copy --after' to record the copy)
   [1]
+  $ hg co -qC .
+  $ rm baz xyzzy
+
+
+Test unmarking copy of a single file
+
+# Set up by creating a copy
+  $ hg cp bar baz
+# Test uncopying a non-existent file
+  $ hg copy --forget non-existent
+  non-existent: $ENOENT$
+# Test uncopying an tracked but unrelated file
+  $ hg copy --forget foo
+  foo: not unmarking as copy - file is not marked as copied
+# Test uncopying a copy source
+  $ hg copy --forget bar
+  bar: not unmarking as copy - file is not marked as copied
+# baz should still be marked as a copy
+  $ hg st -C
+  A baz
+bar
+# Test the normal case
+  $ hg copy --forget baz
+  $ hg st -C
+  A baz
+# Test uncopy with matching an non-matching patterns
+  $ hg cp bar baz --after
+  $ hg copy --forget bar baz
+  bar: not unmarking as copy - file is not marked as copied
+  $ hg st -C
+  A baz
+# Test uncopy with no exact matches
+  $ hg cp bar baz --after
+  $ hg copy --forget .
+  $ hg st -C
+  A baz
+  $ hg forget baz
+  $ rm baz
+
+Test unmarking copy of a directory
+
+  $ mkdir dir
+  $ echo foo > dir/foo
+  $ echo bar > dir/bar
+  $ hg add dir
+  adding dir/bar
+  adding dir/foo
+  $ hg ci -m 'add dir/'
+  $ hg cp dir dir2
+  copying dir/bar to dir2/bar
+  copying dir/foo to dir2/foo
+  $ touch dir2/untracked
+  $ hg copy --forget dir2
+  $ hg st -C
+  A dir2/bar
+  A dir2/foo
+  ? dir2/untracked
 
   $ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -257,7 +257,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: after, force, include, exclude, dry-run
+  copy: forget, after, 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
@@ -12,6 +12,8 @@
commits that are being merged, when there are conflicts. Also works
for conflicts caused by e.g. `hg graft`.
 
+ * `hg copy --forget` can be used to unmark a file as copied.
+
 
 == New Experimental Features ==
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2309,6 +2309,7 @@
 @command(
 b'copy|cp',
 [
+(b'', b'forget', None, _(b'unmark a file as copied')),
 (b'A', b'after', None, _(b'record a copy that has already occurred')),
 (
 b'f',
@@ -2333,8 +2334,11 @@
 exist in the working directory. If invoked with -A/--after, the
 operation is recorded, but no copying is performed.
 
-This command takes effect with the next commit. To undo a copy
-before that, see :hg:`revert`.
+To undo marking a file as copied, use --forget. With that option,
+both SOURCE and DEST are interpreted as destinations. The destination
+file(s) will be left in place (still tracked).
+
+This command takes effect with the next commit.
 
 Returns 0 on success, 1 if errors are encountered.
 """
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1410,12 +1410,15 @@
 
 
 def copy(ui, repo, pats, opts, rename=False):
+check_incompatible_arguments(opts, b'forget', [b'dry_run'])
+
 # called with the repo lock held
 #
 # hgsep => pathname that uses "/" to separate directories
 # ossep => pathname that uses os.sep to separate directories
 cwd = repo.getcwd()
 targets = {}
+forget = opts.get(b"forget")
 after = opts.get(b"after")
 dryrun = opts.get(b"dry_run")
 ctx = repo[None]
@@ -1423,6 +1426,24 @@
 
 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):
+if f in current_copies:
+wctx[f].markcopied(None)
+elif match.exact(f):
+ui.warn(
+_(
+b'%s: not unmarking as copy - file is not marked as 
copied\n'
+)
+  

D8029: copy: add option to unmark file as copied

2020-02-13 Thread martinvonz (Martin von Zweigbergk)
martinvonz added a comment.


  In D8029#120701 , @pulkit wrote:
  
  > The commit message has a mention of `uncopy` which needs to be removed.
  
  Good catch. Done.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-13 Thread pulkit (Pulkit Goyal)
pulkit added a comment.


  The commit message has a mention of `uncopy` which needs to be removed.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-12 Thread martinvonz (Martin von Zweigbergk)
martinvonz updated this revision to Diff 20174.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8029?vs=20148=20174

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  relnotes/next
  tests/test-completion.t
  tests/test-copy.t

CHANGE DETAILS

diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -262,5 +262,62 @@
   xyzzy: not overwriting - file exists
   ('hg copy --after' to record the copy)
   [1]
+  $ hg co -qC .
+  $ rm baz xyzzy
+
+
+Test unmarking copy of a single file
+
+# Set up by creating a copy
+  $ hg cp bar baz
+# Test uncopying a non-existent file
+  $ hg copy --forget non-existent
+  non-existent: $ENOENT$
+# Test uncopying an tracked but unrelated file
+  $ hg copy --forget foo
+  foo: not unmarking as copy - file is not marked as copied
+# Test uncopying a copy source
+  $ hg copy --forget bar
+  bar: not unmarking as copy - file is not marked as copied
+# baz should still be marked as a copy
+  $ hg st -C
+  A baz
+bar
+# Test the normal case
+  $ hg copy --forget baz
+  $ hg st -C
+  A baz
+# Test uncopy with matching an non-matching patterns
+  $ hg cp bar baz --after
+  $ hg copy --forget bar baz
+  bar: not unmarking as copy - file is not marked as copied
+  $ hg st -C
+  A baz
+# Test uncopy with no exact matches
+  $ hg cp bar baz --after
+  $ hg copy --forget .
+  $ hg st -C
+  A baz
+  $ hg forget baz
+  $ rm baz
+
+Test unmarking copy of a directory
+
+  $ mkdir dir
+  $ echo foo > dir/foo
+  $ echo bar > dir/bar
+  $ hg add dir
+  adding dir/bar
+  adding dir/foo
+  $ hg ci -m 'add dir/'
+  $ hg cp dir dir2
+  copying dir/bar to dir2/bar
+  copying dir/foo to dir2/foo
+  $ touch dir2/untracked
+  $ hg copy --forget dir2
+  $ hg st -C
+  A dir2/bar
+  A dir2/foo
+  ? dir2/untracked
 
   $ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -257,7 +257,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: after, force, include, exclude, dry-run
+  copy: forget, after, 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
@@ -12,6 +12,8 @@
commits that are being merged, when there are conflicts. Also works
for conflicts caused by e.g. `hg graft`.
 
+ * `hg copy --forget` can be used to unmark a file as copied.
+
 
 == New Experimental Features ==
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2309,6 +2309,7 @@
 @command(
 b'copy|cp',
 [
+(b'', b'forget', None, _(b'unmark a file as copied')),
 (b'A', b'after', None, _(b'record a copy that has already occurred')),
 (
 b'f',
@@ -2333,8 +2334,11 @@
 exist in the working directory. If invoked with -A/--after, the
 operation is recorded, but no copying is performed.
 
-This command takes effect with the next commit. To undo a copy
-before that, see :hg:`revert`.
+To undo marking a file as copied, use --forget. With that option,
+both SOURCE and DEST are interpreted as destinations. The destination
+file(s) will be left in place (still tracked).
+
+This command takes effect with the next commit.
 
 Returns 0 on success, 1 if errors are encountered.
 """
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1410,12 +1410,15 @@
 
 
 def copy(ui, repo, pats, opts, rename=False):
+check_incompatible_arguments(opts, b'forget', [b'dry_run'])
+
 # called with the repo lock held
 #
 # hgsep => pathname that uses "/" to separate directories
 # ossep => pathname that uses os.sep to separate directories
 cwd = repo.getcwd()
 targets = {}
+forget = opts.get(b"forget")
 after = opts.get(b"after")
 dryrun = opts.get(b"dry_run")
 wctx = repo[None]
@@ -1423,6 +1426,24 @@
 
 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):
+if f in current_copies:
+wctx[f].markcopied(None)
+elif match.exact(f):
+ui.warn(
+_(
+b'%s: not unmarking as copy - file is not marked as 
copied\n'
+)
+ 

D8029: copy: add option to unmark file as copied

2020-02-12 Thread durin42 (Augie Fackler)
durin42 added a comment.
durin42 accepted this revision.


  LGTM, would like @marmoute to chime in.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-10 Thread martinvonz (Martin von Zweigbergk)
martinvonz updated this revision to Diff 20148.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8029?vs=20081=20148

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  relnotes/next
  tests/test-completion.t
  tests/test-copy.t

CHANGE DETAILS

diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -262,5 +262,62 @@
   xyzzy: not overwriting - file exists
   ('hg copy --after' to record the copy)
   [1]
+  $ hg co -qC .
+  $ rm baz xyzzy
+
+
+Test unmarking copy of a single file
+
+# Set up by creating a copy
+  $ hg cp bar baz
+# Test uncopying a non-existent file
+  $ hg copy --forget non-existent
+  non-existent: $ENOENT$
+# Test uncopying an tracked but unrelated file
+  $ hg copy --forget foo
+  foo: not unmarking as copy - file is not marked as copied
+# Test uncopying a copy source
+  $ hg copy --forget bar
+  bar: not unmarking as copy - file is not marked as copied
+# baz should still be marked as a copy
+  $ hg st -C
+  A baz
+bar
+# Test the normal case
+  $ hg copy --forget baz
+  $ hg st -C
+  A baz
+# Test uncopy with matching an non-matching patterns
+  $ hg cp bar baz --after
+  $ hg copy --forget bar baz
+  bar: not unmarking as copy - file is not marked as copied
+  $ hg st -C
+  A baz
+# Test uncopy with no exact matches
+  $ hg cp bar baz --after
+  $ hg copy --forget .
+  $ hg st -C
+  A baz
+  $ hg forget baz
+  $ rm baz
+
+Test unmarking copy of a directory
+
+  $ mkdir dir
+  $ echo foo > dir/foo
+  $ echo bar > dir/bar
+  $ hg add dir
+  adding dir/bar
+  adding dir/foo
+  $ hg ci -m 'add dir/'
+  $ hg cp dir dir2
+  copying dir/bar to dir2/bar
+  copying dir/foo to dir2/foo
+  $ touch dir2/untracked
+  $ hg copy --forget dir2
+  $ hg st -C
+  A dir2/bar
+  A dir2/foo
+  ? dir2/untracked
 
   $ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -257,7 +257,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: after, force, include, exclude, dry-run
+  copy: forget, after, 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
@@ -12,6 +12,8 @@
commits that are being merged, when there are conflicts. Also works
for conflicts caused by e.g. `hg graft`.
 
+ * `hg copy --forget` can be used to unmark a file as copied.
+
 
 == New Experimental Features ==
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2309,6 +2309,7 @@
 @command(
 b'copy|cp',
 [
+(b'', b'forget', None, _(b'unmark a file as copied')),
 (b'A', b'after', None, _(b'record a copy that has already occurred')),
 (
 b'f',
@@ -2333,8 +2334,11 @@
 exist in the working directory. If invoked with -A/--after, the
 operation is recorded, but no copying is performed.
 
-This command takes effect with the next commit. To undo a copy
-before that, see :hg:`revert`.
+To undo marking a file as copied, use --forget. With that option,
+both SOURCE and DEST are interpreted as destinations. The destination
+file(s) will be left in place (still tracked).
+
+This command takes effect with the next commit.
 
 Returns 0 on success, 1 if errors are encountered.
 """
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1410,18 +1410,39 @@
 
 
 def copy(ui, repo, pats, opts, rename=False):
+check_incompatible_arguments(opts, b'forget', [b'dry_run'])
+
 # called with the repo lock held
 #
 # hgsep => pathname that uses "/" to separate directories
 # ossep => pathname that uses os.sep to separate directories
 cwd = repo.getcwd()
 targets = {}
+forget = opts.get(b"forget")
 after = opts.get(b"after")
 dryrun = opts.get(b"dry_run")
 wctx = repo[None]
 
 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):
+if f in current_copies:
+wctx[f].markcopied(None)
+elif match.exact(f):
+ui.warn(
+_(
+b'%s: not unmarking as copy - file is not marked as 
copied\n'
+)
+% 

D8029: copy: add option to unmark file as copied

2020-02-10 Thread martinvonz (Martin von Zweigbergk)
martinvonz updated this revision to Diff 20081.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8029?vs=20068=20081

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  relnotes/next
  tests/test-completion.t
  tests/test-copy.t

CHANGE DETAILS

diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -262,5 +262,62 @@
   xyzzy: not overwriting - file exists
   ('hg copy --after' to record the copy)
   [1]
+  $ hg co -qC .
+  $ rm baz xyzzy
+
+
+Test unmarking copy of a single file
+
+# Set up by creating a copy
+  $ hg cp bar baz
+# Test uncopying a non-existent file
+  $ hg copy --forget non-existent
+  non-existent: $ENOENT$
+# Test uncopying an tracked but unrelated file
+  $ hg copy --forget foo
+  foo: not unmarking as copy - file is not marked as copied
+# Test uncopying a copy source
+  $ hg copy --forget bar
+  bar: not unmarking as copy - file is not marked as copied
+# baz should still be marked as a copy
+  $ hg st -C
+  A baz
+bar
+# Test the normal case
+  $ hg copy --forget baz
+  $ hg st -C
+  A baz
+# Test uncopy with matching an non-matching patterns
+  $ hg cp bar baz --after
+  $ hg copy --forget bar baz
+  bar: not unmarking as copy - file is not marked as copied
+  $ hg st -C
+  A baz
+# Test uncopy with no exact matches
+  $ hg cp bar baz --after
+  $ hg copy --forget .
+  $ hg st -C
+  A baz
+  $ hg forget baz
+  $ rm baz
+
+Test unmarking copy of a directory
+
+  $ mkdir dir
+  $ echo foo > dir/foo
+  $ echo bar > dir/bar
+  $ hg add dir
+  adding dir/bar
+  adding dir/foo
+  $ hg ci -m 'add dir/'
+  $ hg cp dir dir2
+  copying dir/bar to dir2/bar
+  copying dir/foo to dir2/foo
+  $ touch dir2/untracked
+  $ hg copy --forget dir2
+  $ hg st -C
+  A dir2/bar
+  A dir2/foo
+  ? dir2/untracked
 
   $ 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: after, force, include, exclude, dry-run
+  copy: forget, after, 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,6 +3,9 @@
  * `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.
+
+
 == New Experimental Features ==
 
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2309,6 +2309,7 @@
 @command(
 b'copy|cp',
 [
+(b'', b'forget', None, _(b'unmark a file as copied')),
 (b'A', b'after', None, _(b'record a copy that has already occurred')),
 (
 b'f',
@@ -2333,8 +2334,11 @@
 exist in the working directory. If invoked with -A/--after, the
 operation is recorded, but no copying is performed.
 
-This command takes effect with the next commit. To undo a copy
-before that, see :hg:`revert`.
+To undo marking a file as copied, use --forget. With that option,
+both SOURCE and DEST are interpreted as destinations. The destination
+file(s) will be left in place (still tracked).
+
+This command takes effect with the next commit.
 
 Returns 0 on success, 1 if errors are encountered.
 """
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1403,18 +1403,39 @@
 
 
 def copy(ui, repo, pats, opts, rename=False):
+check_incompatible_arguments(opts, b'forget', [b'dry_run'])
+
 # called with the repo lock held
 #
 # hgsep => pathname that uses "/" to separate directories
 # ossep => pathname that uses os.sep to separate directories
 cwd = repo.getcwd()
 targets = {}
+forget = opts.get(b"forget")
 after = opts.get(b"after")
 dryrun = opts.get(b"dry_run")
 wctx = repo[None]
 
 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):
+if f in current_copies:
+wctx[f].markcopied(None)
+elif match.exact(f):
+ui.warn(
+_(
+b'%s: not unmarking as copy - file is not marked as 
copied\n'
+)
+% uipathfn(f)
+ 

D8029: copy: add option to unmark file as copied

2020-02-10 Thread martinvonz (Martin von Zweigbergk)
martinvonz added a comment.


  In D8029#119818 , @martinvonz 
wrote:
  
  > In D8029#119813 , @marmoute 
wrote:
  >
  >> I am still not convinced by the command name.
  >>
  >> In D8029#118464 , @martinvonz 
wrote:
  >>
  >>> In D8029#118463 , @marmoute 
wrote:
  >>>
   Coudl we use a flag for to `hg copy` for that ? something like `hg copy 
--forget`
  >>>
  >>> Why would you prefer that? Discoverability?
  >>
  >> Discoverability, avoiding command creep, interface clarify, avoiding 
interface of similar command drifting appart from each other. The two command 
really deal with the same data in the same way. Having them one would
  >>
  >>> An argument against it is that the commands take different flags and 
arguments (for example, `hg uncopy` takes only the destination, no source).
  >>
  >> I don't think it is a big deal `hg copy source dest`, `hg copy --forget 
dest` seems clear enough to me.
  >> One of the thing that bother me is that `hg uncopy` is not reverse of `hg 
copy`, it is the reverse `hg copy --after` I expect it can be a source of 
confusion. using `--after` better map the behavior of the function, that is 
closer to `hg forget` as you point out in your changeset description.
  >
  > You're saying you want the user to say `hg copy --forget --after dest` to 
unmark it as copied?
  
  Since both you and @durin42 wanted `hg copy --forget`, I've updated the 
series to do it that way. I decided not to require `hg --after` since 
`--forget` could be interpreted to mean both "forget the copy" and "forget the 
file" (i.e. untrack but don't remove) at the same time. That's convenient :)
  
  Note that the synopsis of the command is now not quite correct because `hg 
copy --forget` doesn't have `SOURCE... DEST` but `DEST...`. timeless suggested 
adding multiple synopsis lines à la `man cp`, but our help system decided not 
to respect my newline. So I just gave up on it. I described it in the help text 
instead.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

To: martinvonz, #hg-reviewers, durin42, marmoute
Cc: pulkit, durin42, marmoute, mercurial-devel
___
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


D8029: copy: add option to unmark file as copied

2020-02-10 Thread martinvonz (Martin von Zweigbergk)
martinvonz edited the summary of this revision.
martinvonz retitled this revision from "uncopy: add new `hg uncopy` command" to 
"copy: add option to unmark file as copied".
martinvonz updated this revision to Diff 20068.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D8029?vs=19725=20068

BRANCH
  default

CHANGES SINCE LAST ACTION
  https://phab.mercurial-scm.org/D8029/new/

REVISION DETAIL
  https://phab.mercurial-scm.org/D8029

AFFECTED FILES
  mercurial/cmdutil.py
  mercurial/commands.py
  relnotes/next
  tests/test-completion.t
  tests/test-copy.t

CHANGE DETAILS

diff --git a/tests/test-copy.t b/tests/test-copy.t
--- a/tests/test-copy.t
+++ b/tests/test-copy.t
@@ -262,5 +262,62 @@
   xyzzy: not overwriting - file exists
   ('hg copy --after' to record the copy)
   [1]
+  $ hg co -qC .
+  $ rm baz xyzzy
+
+
+Test unmarking copy of a single file
+
+# Set up by creating a copy
+  $ hg cp bar baz
+# Test uncopying a non-existent file
+  $ hg copy --forget non-existent
+  non-existent: $ENOENT$
+# Test uncopying an tracked but unrelated file
+  $ hg copy --forget foo
+  foo: not unmarking as copy - file is not marked as copied
+# Test uncopying a copy source
+  $ hg copy --forget bar
+  bar: not unmarking as copy - file is not marked as copied
+# baz should still be marked as a copy
+  $ hg st -C
+  A baz
+bar
+# Test the normal case
+  $ hg copy --forget baz
+  $ hg st -C
+  A baz
+# Test uncopy with matching an non-matching patterns
+  $ hg cp bar baz --after
+  $ hg copy --forget bar baz
+  bar: not unmarking as copy - file is not marked as copied
+  $ hg st -C
+  A baz
+# Test uncopy with no exact matches
+  $ hg cp bar baz --after
+  $ hg copy --forget .
+  $ hg st -C
+  A baz
+  $ hg forget baz
+  $ rm baz
+
+Test unmarking copy of a directory
+
+  $ mkdir dir
+  $ echo foo > dir/foo
+  $ echo bar > dir/bar
+  $ hg add dir
+  adding dir/bar
+  adding dir/foo
+  $ hg ci -m 'add dir/'
+  $ hg cp dir dir2
+  copying dir/bar to dir2/bar
+  copying dir/foo to dir2/foo
+  $ touch dir2/untracked
+  $ hg copy --forget dir2
+  $ hg st -C
+  A dir2/bar
+  A dir2/foo
+  ? dir2/untracked
 
   $ cd ..
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -255,7 +255,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: after, force, include, exclude, dry-run
+  copy: forget, after, 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
@@ -1,5 +1,7 @@
 == New Features ==
 
+ * `hg copy --forget` can be used to unmark a file as copied.
+
 
 == New Experimental Features ==
 
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -2309,6 +2309,7 @@
 @command(
 b'copy|cp',
 [
+(b'', b'forget', None, _(b'unmark a file as copied')),
 (b'A', b'after', None, _(b'record a copy that has already occurred')),
 (
 b'f',
@@ -2333,8 +2334,11 @@
 exist in the working directory. If invoked with -A/--after, the
 operation is recorded, but no copying is performed.
 
-This command takes effect with the next commit. To undo a copy
-before that, see :hg:`revert`.
+To undo marking a file as copied, use --forget. With that option,
+both SOURCE and DEST are interpreted as destinations. The destination
+file(s) will be left in place (still tracked).
+
+This command takes effect with the next commit.
 
 Returns 0 on success, 1 if errors are encountered.
 """
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1403,18 +1403,39 @@
 
 
 def copy(ui, repo, pats, opts, rename=False):
+check_incompatible_arguments(opts, b'forget', [b'dry_run'])
+
 # called with the repo lock held
 #
 # hgsep => pathname that uses "/" to separate directories
 # ossep => pathname that uses os.sep to separate directories
 cwd = repo.getcwd()
 targets = {}
+forget = opts.get(b"forget")
 after = opts.get(b"after")
 dryrun = opts.get(b"dry_run")
 wctx = repo[None]
 
 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):
+if f in current_copies:
+wctx[f].markcopied(None)
+elif match.exact(f):
+ui.warn(
+_(
+b'%s: not unmarking as copy - file is not