Patchwork automv: new experimental extension

login
register
mail settings
Submitter Martijn Pieters
Date Feb. 8, 2016, 1:56 p.m.
Message ID <fb91a65f102ca34d6996.1454939798@mjpieters-mbp>
Download mbox | patch
Permalink /patch/13053/
State Accepted
Delegated to: Augie Fackler
Headers show

Comments

Martijn Pieters - Feb. 8, 2016, 1:56 p.m.
# HG changeset patch
# User Martijn Pieters <mjpieters@fb.com>
# Date 1454939571 0
#      Mon Feb 08 13:52:51 2016 +0000
# Node ID fb91a65f102ca34d69961142ad84955080ada1fc
# Parent  3026a9107f9e40ba5d63bdae7e81c48db8885fe2
automv: new experimental extension

Automatically detect moves and record them at commit time.

This extension was originally developed at
https://bitbucket.org/facebook/hg-experimental
Laurent Charignon - Feb. 8, 2016, 9:15 p.m.
This is a second version of your patch, correct?
If so, make sure that you flag it as V2:

    $ hg email --flag V2 -r ...


Laurent

On 2/8/16, 5:56 AM, "Mercurial-devel on behalf of Martijn Pieters"
<mercurial-devel-bounces@mercurial-scm.org on behalf of mj@zopatista.com>
wrote:

># HG changeset patch
># User Martijn Pieters <mjpieters@fb.com>
># Date 1454939571 0
>#      Mon Feb 08 13:52:51 2016 +0000
># Node ID fb91a65f102ca34d69961142ad84955080ada1fc
># Parent  3026a9107f9e40ba5d63bdae7e81c48db8885fe2
>automv: new experimental extension
>
>Automatically detect moves and record them at commit time.
>
>This extension was originally developed at
>https://urldefense.proofpoint.com/v2/url?u=https-3A__bitbucket.org_faceboo
>k_hg-2Dexperimental&d=CwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=qmwlQ6ljsf0--v3ANP
>53-V-RM6PPUtJ5zK5Y1fStJGg&m=qIwYcGhHATzXgAKvdxf4O0_elNI5VhMwUJb1h89yRnk&s=
>D9UcVcSPa09NiNlteJdn66AuyOAh6005XehkKjhdD9M&e=
>
>diff --git a/hgext/automv.py b/hgext/automv.py
>new file mode 100644
>--- /dev/null
>+++ b/hgext/automv.py
>@@ -0,0 +1,83 @@
>+# automv.py
>+#
>+# Copyright 2013-2016 Facebook, Inc.
>+#
>+# This software may be used and distributed according to the terms of the
>+# GNU General Public License version 2 or any later version.
>+"""Check for unrecorded moves at commit time (EXPERIMENTAL)
>+
>+This extension checks at commit/amend time if any of the committed files
>+comes from an unrecorded mv.
>+
>+The threshold at which a file is considered a move can be set with the
>+``automv.similarity`` config option; the default value is 1.00.
>+
>+"""
>+from __future__ import absolute_import
>+
>+from mercurial import (
>+    commands,
>+    copies,
>+    extensions,
>+    scmutil,
>+    similar
>+)
>+from mercurial.i18n import _
>+
>+def extsetup(ui):
>+    entry = extensions.wrapcommand(
>+        commands.table, 'commit', mvcheck)
>+    entry[1].append(
>+        ('', 'no-automv', None,
>+         _('disable automatic file move detection')))
>+
>+def mvcheck(orig, ui, repo, *pats, **opts):
>+    disabled = opts.pop('no_automv', False)
>+    if not disabled:
>+        threshold = float(ui.config('automv', 'similarity', '1.00'))
>+        if threshold > 0:
>+            match = scmutil.match(repo[None], pats, opts)
>+            added, removed = _interestingfiles(repo, match)
>+            renames = _findrenames(repo, match, added, removed,
>threshold)
>+            _markchanges(repo, renames)
>+
>+    # developer config: automv.testmode
>+    if not ui.configbool('automv', 'testmode'):
>+        return orig(ui, repo, *pats, **opts)
>+
>+def _interestingfiles(repo, matcher):
>+    stat = repo.status(repo['.'], repo[None], matcher)
>+    added = stat[1]
>+    removed = stat[2]
>+
>+    copy = copies._forwardcopies(repo['.'], repo[None], matcher)
>+    # remove the copy files for which we already have copy info
>+    added = [f for f in added if f not in copy]
>+
>+    return added, removed
>+
>+def _findrenames(repo, matcher, added, removed, similarity):
>+    """Find renames from removed files of the current commit/amend files
>+    to the added ones"""
>+    renames = {}
>+    if similarity > 0:
>+        for src, dst, score in similar.findrenames(
>+                repo, added, removed, similarity):
>+            if repo.ui.verbose:
>+                repo.ui.status(
>+                    _('detected move of %s as %s (%d%% similar)\n') % (
>+                        matcher.rel(src), matcher.rel(dst), score * 100))
>+            renames[dst] = src
>+    if renames:
>+        repo.ui.status(_('detected move of %d files\n') % len(renames))
>+    return renames
>+
>+def _markchanges(repo, renames):
>+    """Marks the files in renames as copied."""
>+    wctx = repo[None]
>+    wlock = repo.wlock()
>+    try:
>+        for dst, src in renames.iteritems():
>+            wctx.copy(src, dst)
>+    finally:
>+        wlock.release()
>diff --git a/tests/test-automv.t b/tests/test-automv.t
>new file mode 100644
>--- /dev/null
>+++ b/tests/test-automv.t
>@@ -0,0 +1,287 @@
>+  $ cat >> $HGRCPATH << EOF
>+  > [extensions]
>+  > automv=
>+  > rebase=
>+  > EOF
>+
>+Setup repo
>+
>+  $ hg init repo
>+  $ cd repo
>+
>+Test automv command for commit
>+
>+  $ echo 'foo' > a.txt
>+  $ hg add a.txt
>+  $ hg commit -m 'init repo with a'
>+
>+mv/rm/add
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit -m 'msg'
>+  detected move of 1 files
>+  $ hg status --change . -C
>+  A b.txt
>+    a.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
>+
>+mv/rm/add/modif
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ printf '\nfoo\n' >> b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit -m 'msg'
>+  created new head
>+  $ hg status --change . -C
>+  A b.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
>+
>+mv/rm/add/modif/changethreshold
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ printf '\nfoo\n' >> b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit --config automv.similarity='0.6' -m 'msg'
>+  detected move of 1 files
>+  created new head
>+  $ hg status --change . -C
>+  A b.txt
>+    a.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
>+
>+mv
>+  $ mv a.txt b.txt
>+  $ hg status -C
>+  ! a.txt
>+  ? b.txt
>+  $ hg commit -m 'msg'
>+  nothing changed (1 missing files, see 'hg status')
>+  [1]
>+  $ hg status -C
>+  ! a.txt
>+  ? b.txt
>+  $ hg revert -aqC
>+  $ rm b.txt
>+
>+mv/rm/add/notincommitfiles
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ echo 'bar' > c.txt
>+  $ hg add c.txt
>+  $ hg status -C
>+  A b.txt
>+  A c.txt
>+  R a.txt
>+  $ hg commit c.txt -m 'msg'
>+  created new head
>+  $ hg status --change . -C
>+  A c.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg up -r 0
>+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
>+  $ hg rm a.txt
>+  $ echo 'bar' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'msg'
>+  detected move of 1 files
>+  created new head
>+  $ hg status --change . -C
>+  A b.txt
>+    a.txt
>+  A c.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
>+
>+mv/rm/add/--no-automv
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit --no-automv -m 'msg'
>+  created new head
>+  $ hg status --change . -C
>+  A b.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
>+
>+
>+Test automv command for commit --amend
>+
>+mv/rm/add
>+  $ echo 'c' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'revision to amend to'
>+  created new head
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit --amend -m 'amended'
>+  detected move of 1 files
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status --change . -C
>+  A b.txt
>+    a.txt
>+  A c.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
>+
>+mv/rm/add/modif
>+  $ echo 'c' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'revision to amend to'
>+  created new head
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ printf '\nfoo\n' >> b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit --amend -m 'amended'
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status --change . -C
>+  A b.txt
>+  A c.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
>+
>+mv/rm/add/modif/changethreshold
>+  $ echo 'c' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'revision to amend to'
>+  created new head
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ printf '\nfoo\n' >> b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit --amend --config automv.similarity='0.6' -m 'amended'
>+  detected move of 1 files
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status --change . -C
>+  A b.txt
>+    a.txt
>+  A c.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
>+
>+mv
>+  $ echo 'c' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'revision to amend to'
>+  created new head
>+  $ mv a.txt b.txt
>+  $ hg status -C
>+  ! a.txt
>+  ? b.txt
>+  $ hg commit --amend -m 'amended'
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status -C
>+  ! a.txt
>+  ? b.txt
>+  $ hg up -Cr 0
>+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
>+
>+mv/rm/add/notincommitfiles
>+  $ echo 'c' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'revision to amend to'
>+  created new head
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ echo 'bar' > d.txt
>+  $ hg add d.txt
>+  $ hg status -C
>+  A b.txt
>+  A d.txt
>+  R a.txt
>+  $ hg commit --amend -m 'amended' d.txt
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status --change . -C
>+  A c.txt
>+  A d.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit --amend -m 'amended'
>+  detected move of 1 files
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status --change . -C
>+  A b.txt
>+    a.txt
>+  A c.txt
>+  A d.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 3 files removed, 0 files unresolved
>+
>+mv/rm/add/--no-automv
>+  $ echo 'c' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'revision to amend to'
>+  created new head
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg add b.txt
>+  $ hg status -C
>+  A b.txt
>+  R a.txt
>+  $ hg commit --amend -m 'amended' --no-automv
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status --change . -C
>+  A b.txt
>+  A c.txt
>+  R a.txt
>+  $ hg up -r 0
>+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
>+
>+
>+mv/rm/commit/add/amend
>+  $ echo 'c' > c.txt
>+  $ hg add c.txt
>+  $ hg commit -m 'revision to amend to'
>+  created new head
>+  $ mv a.txt b.txt
>+  $ hg rm a.txt
>+  $ hg status -C
>+  R a.txt
>+  ? b.txt
>+  $ hg commit -m "removed a"
>+  $ hg add b.txt
>+  $ hg commit --amend -m 'amended'
>+  saved backup bundle to
>$TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
>+  $ hg status --change . -C
>+  A b.txt
>+  R a.txt
>_______________________________________________
>Mercurial-devel mailing list
>Mercurial-devel@mercurial-scm.org
>https://urldefense.proofpoint.com/v2/url?u=https-3A__www.mercurial-2Dscm.o
>rg_mailman_listinfo_mercurial-2Ddevel&d=CwIGaQ&c=5VD0RTtNlTh3ycd41b3MUw&r=
>qmwlQ6ljsf0--v3ANP53-V-RM6PPUtJ5zK5Y1fStJGg&m=qIwYcGhHATzXgAKvdxf4O0_elNI5
>VhMwUJb1h89yRnk&s=27woutqaMh903swGpw7w5Yv5B1_PXuA9u_yOulnM3b8&e=
Augie Fackler - Feb. 13, 2016, 11:20 p.m.
On Mon, Feb 08, 2016 at 01:56:38PM +0000, Martijn Pieters wrote:
> # HG changeset patch
> # User Martijn Pieters <mjpieters@fb.com>
> # Date 1454939571 0
> #      Mon Feb 08 13:52:51 2016 +0000
> # Node ID fb91a65f102ca34d69961142ad84955080ada1fc
> # Parent  3026a9107f9e40ba5d63bdae7e81c48db8885fe2
> automv: new experimental extension

This looks great to me, with one minor nitpick (see below).

>
> Automatically detect moves and record them at commit time.
>
> This extension was originally developed at
> https://bitbucket.org/facebook/hg-experimental
>
> diff --git a/hgext/automv.py b/hgext/automv.py
> new file mode 100644
> --- /dev/null
> +++ b/hgext/automv.py
> @@ -0,0 +1,83 @@
> +# automv.py
> +#
> +# Copyright 2013-2016 Facebook, Inc.
> +#
> +# This software may be used and distributed according to the terms of the
> +# GNU General Public License version 2 or any later version.
> +"""Check for unrecorded moves at commit time (EXPERIMENTAL)
> +
> +This extension checks at commit/amend time if any of the committed files
> +comes from an unrecorded mv.
> +
> +The threshold at which a file is considered a move can be set with the
> +``automv.similarity`` config option; the default value is 1.00.

I think we should document this value as being something we reserve
the right to refine later, after doing some history analysis. I
suspect we can do some analysis over firefox/facebook/google/whatever
histories and come up with a better value than 1.0 as a default.

> +
> +"""
Martin von Zweigbergk - Feb. 13, 2016, 11:54 p.m.
I haven't followed this thread, but  "--config  automv.similarity=1.00" and
"hg addremove --similarity=100” seems unfortunate. Is the different "units"
wanted?

On Sat, Feb 13, 2016, 15:20 Augie Fackler <raf@durin42.com> wrote:

> On Mon, Feb 08, 2016 at 01:56:38PM +0000, Martijn Pieters wrote:
> > # HG changeset patch
> > # User Martijn Pieters <mjpieters@fb.com>
> > # Date 1454939571 0
> > #      Mon Feb 08 13:52:51 2016 +0000
> > # Node ID fb91a65f102ca34d69961142ad84955080ada1fc
> > # Parent  3026a9107f9e40ba5d63bdae7e81c48db8885fe2
> > automv: new experimental extension
>
> This looks great to me, with one minor nitpick (see below).
>
> >
> > Automatically detect moves and record them at commit time.
> >
> > This extension was originally developed at
> > https://bitbucket.org/facebook/hg-experimental
> >
> > diff --git a/hgext/automv.py b/hgext/automv.py
> > new file mode 100644
> > --- /dev/null
> > +++ b/hgext/automv.py
> > @@ -0,0 +1,83 @@
> > +# automv.py
> > +#
> > +# Copyright 2013-2016 Facebook, Inc.
> > +#
> > +# This software may be used and distributed according to the terms of
> the
> > +# GNU General Public License version 2 or any later version.
> > +"""Check for unrecorded moves at commit time (EXPERIMENTAL)
> > +
> > +This extension checks at commit/amend time if any of the committed files
> > +comes from an unrecorded mv.
> > +
> > +The threshold at which a file is considered a move can be set with the
> > +``automv.similarity`` config option; the default value is 1.00.
>
> I think we should document this value as being something we reserve
> the right to refine later, after doing some history analysis. I
> suspect we can do some analysis over firefox/facebook/google/whatever
> histories and come up with a better value than 1.0 as a default.
>
> > +
> > +"""
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
Augie Fackler - Feb. 13, 2016, 11:57 p.m.
> On Feb 13, 2016, at 6:54 PM, Martin von Zweigbergk <martinvonz@google.com> wrote:
> 
> I haven't followed this thread, but  "--config  automv.similarity=1.00" and "hg addremove --similarity=100” seems unfortunate. Is the different "units" wanted?
> 

Valid point. Probably worth standardizing on the integer range since it’s part of addremove already.

> 
> On Sat, Feb 13, 2016, 15:20 Augie Fackler <raf@durin42.com <mailto:raf@durin42.com>> wrote:
> On Mon, Feb 08, 2016 at 01:56:38PM +0000, Martijn Pieters wrote:
> > # HG changeset patch
> > # User Martijn Pieters <mjpieters@fb.com <mailto:mjpieters@fb.com>>
> > # Date 1454939571 0
> > #      Mon Feb 08 13:52:51 2016 +0000
> > # Node ID fb91a65f102ca34d69961142ad84955080ada1fc
> > # Parent  3026a9107f9e40ba5d63bdae7e81c48db8885fe2
> > automv: new experimental extension
> 
> This looks great to me, with one minor nitpick (see below).
> 
> >
> > Automatically detect moves and record them at commit time.
> >
> > This extension was originally developed at
> > https://bitbucket.org/facebook/hg-experimental <https://bitbucket.org/facebook/hg-experimental>
> >
> > diff --git a/hgext/automv.py b/hgext/automv.py
> > new file mode 100644
> > --- /dev/null
> > +++ b/hgext/automv.py
> > @@ -0,0 +1,83 @@
> > +# automv.py
> > +#
> > +# Copyright 2013-2016 Facebook, Inc.
> > +#
> > +# This software may be used and distributed according to the terms of the
> > +# GNU General Public License version 2 or any later version.
> > +"""Check for unrecorded moves at commit time (EXPERIMENTAL)
> > +
> > +This extension checks at commit/amend time if any of the committed files
> > +comes from an unrecorded mv.
> > +
> > +The threshold at which a file is considered a move can be set with the
> > +``automv.similarity`` config option; the default value is 1.00.
> 
> I think we should document this value as being something we reserve
> the right to refine later, after doing some history analysis. I
> suspect we can do some analysis over firefox/facebook/google/whatever
> histories and come up with a better value than 1.0 as a default.
> 
> > +
> > +"""
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org <mailto:Mercurial-devel@mercurial-scm.org>
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel <https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel>
Pierre-Yves David - Feb. 14, 2016, 5:36 p.m.
On 02/08/2016 01:56 PM, Martijn Pieters wrote:
> # HG changeset patch
> # User Martijn Pieters <mjpieters@fb.com>
> # Date 1454939571 0
> #      Mon Feb 08 13:52:51 2016 +0000
> # Node ID fb91a65f102ca34d69961142ad84955080ada1fc
> # Parent  3026a9107f9e40ba5d63bdae7e81c48db8885fe2
> automv: new experimental extension

After discussion with Augie, I'll take this patch as is. We both have 
multiple reservation of some aspect of the UI or the code, but the point 
of being more welcoming to experimental extension is reduce the barrier 
of entry, allowing code with some problematic aspects or interface 
without backward compatibility commitment to make it into the core 
repository.

As a first experiment I've pushed this patch to the clowncopter and will 
see with Martijn to get multiple concern fixed or discussed on this list.

Cheers,
Pierre-Yves David - Feb. 15, 2016, 1:24 p.m.
On 02/08/2016 01:56 PM, Martijn Pieters wrote:
> # HG changeset patch
> # User Martijn Pieters <mjpieters@fb.com>
> # Date 1454939571 0
> #      Mon Feb 08 13:52:51 2016 +0000
> # Node ID fb91a65f102ca34d69961142ad84955080ada1fc
> # Parent  3026a9107f9e40ba5d63bdae7e81c48db8885fe2
> automv: new experimental extension
>
> Automatically detect moves and record them at commit time.
>
> This extension was originally developed at
> https://bitbucket.org/facebook/hg-experimental

Here is group of feedback to be discussed as potential followup.

> diff --git a/hgext/automv.py b/hgext/automv.py
> new file mode 100644
> --- /dev/null
> +++ b/hgext/automv.py
> @@ -0,0 +1,83 @@
> +# automv.py
> +#
> +# Copyright 2013-2016 Facebook, Inc.
> +#
> +# This software may be used and distributed according to the terms of the
> +# GNU General Public License version 2 or any later version.
> +"""Check for unrecorded moves at commit time (EXPERIMENTAL)
> +
> +This extension checks at commit/amend time if any of the committed files
> +comes from an unrecorded mv.
> +
> +The threshold at which a file is considered a move can be set with the
> +``automv.similarity`` config option; the default value is 1.00.

1) We probably want to unify this config with addremove
2) Not super convinced by the creation of a new config section
3) we probably want a way to disable automv independantly of addremove

> +
> +"""
> +from __future__ import absolute_import
> +
> +from mercurial import (
> +    commands,
> +    copies,
> +    extensions,
> +    scmutil,
> +    similar
> +)
> +from mercurial.i18n import _
> +
> +def extsetup(ui):
> +    entry = extensions.wrapcommand(
> +        commands.table, 'commit', mvcheck)
> +    entry[1].append(
> +        ('', 'no-automv', None,
> +         _('disable automatic file move detection')))

--no-automv is the kind of name+behavior that will be a bag of regret in 
the futur. I would go for something like '--similarity X' for addremove. 
it can take 0 to disable the detection entirely. Augie mention than 
'--similarity' could be too generic for somthing we sneak into 
commitopts. '--automove X' could be a better alternative.

To be discussed.

> +
> +def mvcheck(orig, ui, repo, *pats, **opts):

I'm a huge proponent of adding basic docstring to everything!

> +    disabled = opts.pop('no_automv', False)
> +    if not disabled:
> +        threshold = float(ui.config('automv', 'similarity', '1.00'))
> +        if threshold > 0:
> +            match = scmutil.match(repo[None], pats, opts)
> +            added, removed = _interestingfiles(repo, match)
> +            renames = _findrenames(repo, match, added, removed, threshold)
> +            _markchanges(repo, renames)
> +
> +    # developer config: automv.testmode
> +    if not ui.configbool('automv', 'testmode'):
> +        return orig(ui, repo, *pats, **opts)
> +
> +def _interestingfiles(repo, matcher):

I'm still a huge proponent of adding basic docstring to everything!

> +    stat = repo.status(repo['.'], repo[None], matcher)

Do we actually need to pass all this ctx, don't we have a good top level 
function with the default value for this? (genious noob question here)

> +    added = stat[1]
> +    removed = stat[2]
> +
> +    copy = copies._forwardcopies(repo['.'], repo[None], matcher)
> +    # remove the copy files for which we already have copy info
> +    added = [f for f in added if f not in copy]
> +
> +    return added, removed
> +
> +def _findrenames(repo, matcher, added, removed, similarity):
> +    """Find renames from removed files of the current commit/amend files
> +    to the added ones"""

<chanting about dosctring>

> +    renames = {}
> +    if similarity > 0:
> +        for src, dst, score in similar.findrenames(
> +                repo, added, removed, similarity):
> +            if repo.ui.verbose:
> +                repo.ui.status(
> +                    _('detected move of %s as %s (%d%% similar)\n') % (
> +                        matcher.rel(src), matcher.rel(dst), score * 100))
> +            renames[dst] = src
> +    if renames:
> +        repo.ui.status(_('detected move of %d files\n') % len(renames))
> +    return renames
> +
> +def _markchanges(repo, renames):
> +    """Marks the files in renames as copied."""
> +    wctx = repo[None]
> +    wlock = repo.wlock()
> +    try:
> +        for dst, src in renames.iteritems():
> +            wctx.copy(src, dst)
> +    finally:
> +        wlock.release()

I'm a bit confused by the fact we need our own locking here. should'nt 
we be in the locking scope of the commit command already ? if not we are 
open to race condition. Actually, we are already open to race condition 
in this code because we build the wctx before lock the repository.

We should investigate and cleanup this locking logic.

> diff --git a/tests/test-automv.t b/tests/test-automv.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-automv.t
> @@ -0,0 +1,287 @@

Please add some documentation about what this tests file is about.

> +  $ cat >> $HGRCPATH << EOF
> +  > [extensions]
> +  > automv=
> +  > rebase=
> +  > EOF
> +
> +Setup repo
> +
> +  $ hg init repo
> +  $ cd repo
> +
> +Test automv command for commit
> +
> +  $ echo 'foo' > a.txt
> +  $ hg add a.txt
> +  $ hg commit -m 'init repo with a'
> +
> +mv/rm/add
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit -m 'msg'
> +  detected move of 1 files
> +  $ hg status --change . -C
> +  A b.txt
> +    a.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +
> +mv/rm/add/modif
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ printf '\nfoo\n' >> b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit -m 'msg'
> +  created new head
> +  $ hg status --change . -C
> +  A b.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +
> +mv/rm/add/modif/changethreshold
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ printf '\nfoo\n' >> b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit --config automv.similarity='0.6' -m 'msg'
> +  detected move of 1 files
> +  created new head
> +  $ hg status --change . -C
> +  A b.txt
> +    a.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +
> +mv
> +  $ mv a.txt b.txt
> +  $ hg status -C
> +  ! a.txt
> +  ? b.txt
> +  $ hg commit -m 'msg'
> +  nothing changed (1 missing files, see 'hg status')
> +  [1]
> +  $ hg status -C
> +  ! a.txt
> +  ? b.txt
> +  $ hg revert -aqC
> +  $ rm b.txt
> +
> +mv/rm/add/notincommitfiles
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ echo 'bar' > c.txt
> +  $ hg add c.txt
> +  $ hg status -C
> +  A b.txt
> +  A c.txt
> +  R a.txt
> +  $ hg commit c.txt -m 'msg'
> +  created new head
> +  $ hg status --change . -C
> +  A c.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg up -r 0
> +  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  $ hg rm a.txt
> +  $ echo 'bar' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'msg'
> +  detected move of 1 files
> +  created new head
> +  $ hg status --change . -C
> +  A b.txt
> +    a.txt
> +  A c.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
> +
> +mv/rm/add/--no-automv
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit --no-automv -m 'msg'
> +  created new head
> +  $ hg status --change . -C
> +  A b.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +
> +
> +Test automv command for commit --amend
> +
> +mv/rm/add
> +  $ echo 'c' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'revision to amend to'
> +  created new head
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit --amend -m 'amended'
> +  detected move of 1 files
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status --change . -C
> +  A b.txt
> +    a.txt
> +  A c.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
> +
> +mv/rm/add/modif
> +  $ echo 'c' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'revision to amend to'
> +  created new head
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ printf '\nfoo\n' >> b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit --amend -m 'amended'
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status --change . -C
> +  A b.txt
> +  A c.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
> +
> +mv/rm/add/modif/changethreshold
> +  $ echo 'c' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'revision to amend to'
> +  created new head
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ printf '\nfoo\n' >> b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit --amend --config automv.similarity='0.6' -m 'amended'
> +  detected move of 1 files
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status --change . -C
> +  A b.txt
> +    a.txt
> +  A c.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
> +
> +mv
> +  $ echo 'c' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'revision to amend to'
> +  created new head
> +  $ mv a.txt b.txt
> +  $ hg status -C
> +  ! a.txt
> +  ? b.txt
> +  $ hg commit --amend -m 'amended'
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status -C
> +  ! a.txt
> +  ? b.txt
> +  $ hg up -Cr 0
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +
> +mv/rm/add/notincommitfiles
> +  $ echo 'c' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'revision to amend to'
> +  created new head
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ echo 'bar' > d.txt
> +  $ hg add d.txt
> +  $ hg status -C
> +  A b.txt
> +  A d.txt
> +  R a.txt
> +  $ hg commit --amend -m 'amended' d.txt
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status --change . -C
> +  A c.txt
> +  A d.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit --amend -m 'amended'
> +  detected move of 1 files
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status --change . -C
> +  A b.txt
> +    a.txt
> +  A c.txt
> +  A d.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 3 files removed, 0 files unresolved
> +
> +mv/rm/add/--no-automv
> +  $ echo 'c' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'revision to amend to'
> +  created new head
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg add b.txt
> +  $ hg status -C
> +  A b.txt
> +  R a.txt
> +  $ hg commit --amend -m 'amended' --no-automv
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status --change . -C
> +  A b.txt
> +  A c.txt
> +  R a.txt
> +  $ hg up -r 0
> +  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
> +
> +
> +mv/rm/commit/add/amend
> +  $ echo 'c' > c.txt
> +  $ hg add c.txt
> +  $ hg commit -m 'revision to amend to'
> +  created new head
> +  $ mv a.txt b.txt
> +  $ hg rm a.txt
> +  $ hg status -C
> +  R a.txt
> +  ? b.txt
> +  $ hg commit -m "removed a"
> +  $ hg add b.txt
> +  $ hg commit --amend -m 'amended'
> +  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
> +  $ hg status --change . -C
> +  A b.txt
> +  R a.txt
Martijn Pieters - Feb. 15, 2016, 7:03 p.m.
On Mon, Feb 15, 2016 at 1:24 PM, Pierre-Yves David
<pierre-yves.david@ens-lyon.org> wrote:
> 1) We probably want to unify this config with addremove
> 2) Not super convinced by the creation of a new config section
> 3) we probably want a way to disable automv independantly of addremove

Currently, hg addremove --similarity has no equivalent hgrc option.
Does it make sense for hg addremove to have such an option (so it'll
look for similar files by default if set > 0)?

Unifying the options means that hg addremove will automatically detect
moves *as well*, every time you use `hg addremove`.

> --no-automv is the kind of name+behavior that will be a bag of regret in the
> futur. I would go for something like '--similarity X' for addremove. it can
> take 0 to disable the detection entirely. Augie mention than '--similarity'
> could be too generic for somthing we sneak into commitopts. '--automove X'
> could be a better alternative.
>
> To be discussed.

I do like the idea of automv using --similarity as a command-line
switch for `hg commit`, so that `hg commit --similarity 0` disables
the move detection, and setting `automv.similarity = 0` in your config
(or wherever it lives) plus `hg commit --similarity <n>` to have
similarity detection off by default but available for case-by-case
commit-time move detection.

It would echo how the switch is used by `hg addremove`.

Patch

diff --git a/hgext/automv.py b/hgext/automv.py
new file mode 100644
--- /dev/null
+++ b/hgext/automv.py
@@ -0,0 +1,83 @@ 
+# automv.py
+#
+# Copyright 2013-2016 Facebook, Inc.
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+"""Check for unrecorded moves at commit time (EXPERIMENTAL)
+
+This extension checks at commit/amend time if any of the committed files
+comes from an unrecorded mv.
+
+The threshold at which a file is considered a move can be set with the
+``automv.similarity`` config option; the default value is 1.00.
+
+"""
+from __future__ import absolute_import
+
+from mercurial import (
+    commands,
+    copies,
+    extensions,
+    scmutil,
+    similar
+)
+from mercurial.i18n import _
+
+def extsetup(ui):
+    entry = extensions.wrapcommand(
+        commands.table, 'commit', mvcheck)
+    entry[1].append(
+        ('', 'no-automv', None,
+         _('disable automatic file move detection')))
+
+def mvcheck(orig, ui, repo, *pats, **opts):
+    disabled = opts.pop('no_automv', False)
+    if not disabled:
+        threshold = float(ui.config('automv', 'similarity', '1.00'))
+        if threshold > 0:
+            match = scmutil.match(repo[None], pats, opts)
+            added, removed = _interestingfiles(repo, match)
+            renames = _findrenames(repo, match, added, removed, threshold)
+            _markchanges(repo, renames)
+
+    # developer config: automv.testmode
+    if not ui.configbool('automv', 'testmode'):
+        return orig(ui, repo, *pats, **opts)
+
+def _interestingfiles(repo, matcher):
+    stat = repo.status(repo['.'], repo[None], matcher)
+    added = stat[1]
+    removed = stat[2]
+
+    copy = copies._forwardcopies(repo['.'], repo[None], matcher)
+    # remove the copy files for which we already have copy info
+    added = [f for f in added if f not in copy]
+
+    return added, removed
+
+def _findrenames(repo, matcher, added, removed, similarity):
+    """Find renames from removed files of the current commit/amend files
+    to the added ones"""
+    renames = {}
+    if similarity > 0:
+        for src, dst, score in similar.findrenames(
+                repo, added, removed, similarity):
+            if repo.ui.verbose:
+                repo.ui.status(
+                    _('detected move of %s as %s (%d%% similar)\n') % (
+                        matcher.rel(src), matcher.rel(dst), score * 100))
+            renames[dst] = src
+    if renames:
+        repo.ui.status(_('detected move of %d files\n') % len(renames))
+    return renames
+
+def _markchanges(repo, renames):
+    """Marks the files in renames as copied."""
+    wctx = repo[None]
+    wlock = repo.wlock()
+    try:
+        for dst, src in renames.iteritems():
+            wctx.copy(src, dst)
+    finally:
+        wlock.release()
diff --git a/tests/test-automv.t b/tests/test-automv.t
new file mode 100644
--- /dev/null
+++ b/tests/test-automv.t
@@ -0,0 +1,287 @@ 
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > automv=
+  > rebase=
+  > EOF
+
+Setup repo
+
+  $ hg init repo
+  $ cd repo
+
+Test automv command for commit
+
+  $ echo 'foo' > a.txt
+  $ hg add a.txt
+  $ hg commit -m 'init repo with a'
+
+mv/rm/add
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit -m 'msg'
+  detected move of 1 files
+  $ hg status --change . -C
+  A b.txt
+    a.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+mv/rm/add/modif
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ printf '\nfoo\n' >> b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit -m 'msg'
+  created new head
+  $ hg status --change . -C
+  A b.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+mv/rm/add/modif/changethreshold
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ printf '\nfoo\n' >> b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit --config automv.similarity='0.6' -m 'msg'
+  detected move of 1 files
+  created new head
+  $ hg status --change . -C
+  A b.txt
+    a.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+mv
+  $ mv a.txt b.txt
+  $ hg status -C
+  ! a.txt
+  ? b.txt
+  $ hg commit -m 'msg'
+  nothing changed (1 missing files, see 'hg status')
+  [1]
+  $ hg status -C
+  ! a.txt
+  ? b.txt
+  $ hg revert -aqC
+  $ rm b.txt
+
+mv/rm/add/notincommitfiles
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ echo 'bar' > c.txt
+  $ hg add c.txt
+  $ hg status -C
+  A b.txt
+  A c.txt
+  R a.txt
+  $ hg commit c.txt -m 'msg'
+  created new head
+  $ hg status --change . -C
+  A c.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg up -r 0
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ hg rm a.txt
+  $ echo 'bar' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'msg'
+  detected move of 1 files
+  created new head
+  $ hg status --change . -C
+  A b.txt
+    a.txt
+  A c.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+mv/rm/add/--no-automv
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit --no-automv -m 'msg'
+  created new head
+  $ hg status --change . -C
+  A b.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+
+Test automv command for commit --amend
+
+mv/rm/add
+  $ echo 'c' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'revision to amend to'
+  created new head
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit --amend -m 'amended'
+  detected move of 1 files
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status --change . -C
+  A b.txt
+    a.txt
+  A c.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+mv/rm/add/modif
+  $ echo 'c' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'revision to amend to'
+  created new head
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ printf '\nfoo\n' >> b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit --amend -m 'amended'
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status --change . -C
+  A b.txt
+  A c.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+mv/rm/add/modif/changethreshold
+  $ echo 'c' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'revision to amend to'
+  created new head
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ printf '\nfoo\n' >> b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit --amend --config automv.similarity='0.6' -m 'amended'
+  detected move of 1 files
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status --change . -C
+  A b.txt
+    a.txt
+  A c.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+mv
+  $ echo 'c' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'revision to amend to'
+  created new head
+  $ mv a.txt b.txt
+  $ hg status -C
+  ! a.txt
+  ? b.txt
+  $ hg commit --amend -m 'amended'
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status -C
+  ! a.txt
+  ? b.txt
+  $ hg up -Cr 0
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+mv/rm/add/notincommitfiles
+  $ echo 'c' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'revision to amend to'
+  created new head
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ echo 'bar' > d.txt
+  $ hg add d.txt
+  $ hg status -C
+  A b.txt
+  A d.txt
+  R a.txt
+  $ hg commit --amend -m 'amended' d.txt
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status --change . -C
+  A c.txt
+  A d.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit --amend -m 'amended'
+  detected move of 1 files
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status --change . -C
+  A b.txt
+    a.txt
+  A c.txt
+  A d.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 3 files removed, 0 files unresolved
+
+mv/rm/add/--no-automv
+  $ echo 'c' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'revision to amend to'
+  created new head
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg add b.txt
+  $ hg status -C
+  A b.txt
+  R a.txt
+  $ hg commit --amend -m 'amended' --no-automv
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status --change . -C
+  A b.txt
+  A c.txt
+  R a.txt
+  $ hg up -r 0
+  1 files updated, 0 files merged, 2 files removed, 0 files unresolved
+
+
+mv/rm/commit/add/amend
+  $ echo 'c' > c.txt
+  $ hg add c.txt
+  $ hg commit -m 'revision to amend to'
+  created new head
+  $ mv a.txt b.txt
+  $ hg rm a.txt
+  $ hg status -C
+  R a.txt
+  ? b.txt
+  $ hg commit -m "removed a"
+  $ hg add b.txt
+  $ hg commit --amend -m 'amended'
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-amend-backup.hg (glob)
+  $ hg status --change . -C
+  A b.txt
+  R a.txt