Patchwork [3,of,3,checkunknown] merge: split up checks for unknown and ignored files that differ

login
register
mail settings
Submitter Siddharth Agarwal
Date Jan. 13, 2016, 2:40 a.m.
Message ID <7160b97f606adce4534d.1452652846@dev666.prn1.facebook.com>
Download mbox | patch
Permalink /patch/12742/
State Accepted
Headers show

Comments

Siddharth Agarwal - Jan. 13, 2016, 2:40 a.m.
# HG changeset patch
# User Siddharth Agarwal <sid0@fb.com>
# Date 1452652729 28800
#      Tue Jan 12 18:38:49 2016 -0800
# Node ID 7160b97f606adce4534d3f6eed6a8c1328adad88
# Parent  e66b50d246a8d2c1e8649b6a4067070e241e0d64
# Available At http://42.netv6.net/sid0-wip/hg/
#              hg pull http://42.netv6.net/sid0-wip/hg/ -r 7160b97f606a
merge: split up checks for unknown and ignored files that differ

In some real-world cases it is preferable to allow overwriting ignored files
while continuing to abort on unknown files. This primarily happens when we're
replacing build artifacts (which are ignored) with checked in files, but
continuing to abort on differing files that aren't ignored.

We're redefining merge.checkunknown to only control the behavior for files
that aren't ignored. That's fine because this config was only very recently
introduced and has not made its way into any Mercurial releases yet.
Martin von Zweigbergk - Jan. 13, 2016, 7:44 a.m.
Pushed to the clowncopter, thanks!

On Tue, Jan 12, 2016 at 6:42 PM Siddharth Agarwal <sid0@fb.com> wrote:

> # HG changeset patch
> # User Siddharth Agarwal <sid0@fb.com>
> # Date 1452652729 28800
> #      Tue Jan 12 18:38:49 2016 -0800
> # Node ID 7160b97f606adce4534d3f6eed6a8c1328adad88
> # Parent  e66b50d246a8d2c1e8649b6a4067070e241e0d64
> # Available At http://42.netv6.net/sid0-wip/hg/
> #              hg pull http://42.netv6.net/sid0-wip/hg/ -r 7160b97f606a
> merge: split up checks for unknown and ignored files that differ
>
> In some real-world cases it is preferable to allow overwriting ignored
> files
> while continuing to abort on unknown files. This primarily happens when
> we're
> replacing build artifacts (which are ignored) with checked in files, but
> continuing to abort on differing files that aren't ignored.
>
> We're redefining merge.checkunknown to only control the behavior for files
> that aren't ignored. That's fine because this config was only very recently
> introduced and has not made its way into any Mercurial releases yet.
>
> diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
> --- a/mercurial/help/config.txt
> +++ b/mercurial/help/config.txt
> @@ -992,14 +992,20 @@ proxy.
>
>  This section specifies behavior during merges and updates.
>
> -``checkunknown``
> -   Controls behavior when an unknown file on disk has the same name as a
> tracked
> +``checkignored``
> +   Controls behavior when an ignored file on disk has the same name as a
> tracked
>     file in the changeset being merged or updated to, and has different
>     contents. Options are ``abort``, ``warn`` and ``ignore``. With
> ``abort``,
>     abort on such files. With ``warn``, warn on such files and back them
> up as
>     .orig. With ``ignore``, don't print a warning and back them up as
>     .orig. (default: ``abort``)
>
> +``checkunknown``
> +   Controls behavior when an unknown file that isn't ignored has the same
> name
> +   as a tracked file in the changeset being merged or updated to, and has
> +   different contents. Similar to ``merge.checkignored``, except for
> files that
> +   are not ignored. (default: ``abort``)
> +
>  ``merge-patterns``
>  ------------------
>
> diff --git a/mercurial/merge.py b/mercurial/merge.py
> --- a/mercurial/merge.py
> +++ b/mercurial/merge.py
> @@ -591,7 +591,8 @@ def _checkunknownfiles(repo, wctx, mctx,
>              elif config == 'warn':
>                  warnconflicts.update(conflicts)
>
> -        config = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
> +        unknownconfig = _getcheckunknownconfig(repo, 'merge',
> 'checkunknown')
> +        ignoredconfig = _getcheckunknownconfig(repo, 'merge',
> 'checkignored')
>          for f, (m, args, msg) in actions.iteritems():
>              if m in ('c', 'dc'):
>                  if _checkunknownfile(repo, wctx, mctx, f):
> @@ -600,7 +601,11 @@ def _checkunknownfiles(repo, wctx, mctx,
>                  if _checkunknownfile(repo, wctx, mctx, f, args[0]):
>                      conflicts.add(f)
>
> -        collectconflicts(conflicts, config)
> +        ignoredconflicts = set([c for c in conflicts
> +                                if repo.dirstate._ignore(c)])
> +        unknownconflicts = conflicts - ignoredconflicts
> +        collectconflicts(ignoredconflicts, ignoredconfig)
> +        collectconflicts(unknownconflicts, unknownconfig)
>          for f in sorted(abortconflicts):
>              repo.ui.warn(_("%s: untracked file differs\n") % f)
>          if abortconflicts:
> diff --git a/tests/test-merge1.t b/tests/test-merge1.t
> --- a/tests/test-merge1.t
> +++ b/tests/test-merge1.t
> @@ -152,10 +152,78 @@ this merge should silently ignore
>    1 files updated, 0 files merged, 0 files removed, 0 files unresolved
>    (branch merge, don't forget to commit)
>
> +merge.checkignored
> +  $ hg up --clean 1
> +  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  $ cat >> .hgignore << EOF
> +  > remoteignored
> +  > EOF
> +  $ echo This is file localignored3 > localignored
> +  $ echo This is file remoteignored3 > remoteignored
> +  $ hg add .hgignore localignored remoteignored
> +  $ hg commit -m "commit #3"
> +
> +  $ hg up 2
> +  1 files updated, 0 files merged, 4 files removed, 0 files unresolved
> +  $ cat >> .hgignore << EOF
> +  > localignored
> +  > EOF
> +  $ hg add .hgignore
> +  $ hg commit -m "commit #4"
> +
> +remote .hgignore shouldn't be used for determining whether a file is
> ignored
> +  $ echo This is file remoteignored4 > remoteignored
> +  $ hg merge 3 --config merge.checkignored=ignore --config
> merge.checkunknown=abort
> +  remoteignored: untracked file differs
> +  abort: untracked files in working directory differ from files in
> requested revision
> +  [255]
> +  $ hg merge 3 --config merge.checkignored=abort --config
> merge.checkunknown=ignore
> +  merging .hgignore
> +  merging for .hgignore
> +  3 files updated, 1 files merged, 0 files removed, 0 files unresolved
> +  (branch merge, don't forget to commit)
> +  $ cat remoteignored
> +  This is file remoteignored3
> +  $ cat remoteignored.orig
> +  This is file remoteignored4
> +  $ rm remoteignored.orig
> +
> +local .hgignore should be used for that
> +  $ hg up --clean 4
> +  1 files updated, 0 files merged, 3 files removed, 0 files unresolved
> +  $ echo This is file localignored4 > localignored
> +also test other conflicting files to see we output the full set of
> warnings
> +  $ echo This is file b2 > b
> +  $ hg merge 3 --config merge.checkignored=abort --config
> merge.checkunknown=abort
> +  b: untracked file differs
> +  localignored: untracked file differs
> +  abort: untracked files in working directory differ from files in
> requested revision
> +  [255]
> +  $ hg merge 3 --config merge.checkignored=abort --config
> merge.checkunknown=ignore
> +  localignored: untracked file differs
> +  abort: untracked files in working directory differ from files in
> requested revision
> +  [255]
> +  $ hg merge 3 --config merge.checkignored=warn --config
> merge.checkunknown=abort
> +  b: untracked file differs
> +  abort: untracked files in working directory differ from files in
> requested revision
> +  [255]
> +  $ hg merge 3 --config merge.checkignored=warn --config
> merge.checkunknown=warn
> +  b: replacing untracked file
> +  localignored: replacing untracked file
> +  merging .hgignore
> +  merging for .hgignore
> +  3 files updated, 1 files merged, 0 files removed, 0 files unresolved
> +  (branch merge, don't forget to commit)
> +  $ cat localignored
> +  This is file localignored3
> +  $ cat localignored.orig
> +  This is file localignored4
> +  $ rm localignored.orig
> +
>    $ cat b.orig
>    This is file b2
>    $ hg up --clean 2
> -  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  0 files updated, 0 files merged, 4 files removed, 0 files unresolved
>    $ mv b.orig b
>
>  this merge of b should work
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel
>

Patch

diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
--- a/mercurial/help/config.txt
+++ b/mercurial/help/config.txt
@@ -992,14 +992,20 @@  proxy.
 
 This section specifies behavior during merges and updates.
 
-``checkunknown``
-   Controls behavior when an unknown file on disk has the same name as a tracked
+``checkignored``
+   Controls behavior when an ignored file on disk has the same name as a tracked
    file in the changeset being merged or updated to, and has different
    contents. Options are ``abort``, ``warn`` and ``ignore``. With ``abort``,
    abort on such files. With ``warn``, warn on such files and back them up as
    .orig. With ``ignore``, don't print a warning and back them up as
    .orig. (default: ``abort``)
 
+``checkunknown``
+   Controls behavior when an unknown file that isn't ignored has the same name
+   as a tracked file in the changeset being merged or updated to, and has
+   different contents. Similar to ``merge.checkignored``, except for files that
+   are not ignored. (default: ``abort``)
+
 ``merge-patterns``
 ------------------
 
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -591,7 +591,8 @@  def _checkunknownfiles(repo, wctx, mctx,
             elif config == 'warn':
                 warnconflicts.update(conflicts)
 
-        config = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
+        unknownconfig = _getcheckunknownconfig(repo, 'merge', 'checkunknown')
+        ignoredconfig = _getcheckunknownconfig(repo, 'merge', 'checkignored')
         for f, (m, args, msg) in actions.iteritems():
             if m in ('c', 'dc'):
                 if _checkunknownfile(repo, wctx, mctx, f):
@@ -600,7 +601,11 @@  def _checkunknownfiles(repo, wctx, mctx,
                 if _checkunknownfile(repo, wctx, mctx, f, args[0]):
                     conflicts.add(f)
 
-        collectconflicts(conflicts, config)
+        ignoredconflicts = set([c for c in conflicts
+                                if repo.dirstate._ignore(c)])
+        unknownconflicts = conflicts - ignoredconflicts
+        collectconflicts(ignoredconflicts, ignoredconfig)
+        collectconflicts(unknownconflicts, unknownconfig)
         for f in sorted(abortconflicts):
             repo.ui.warn(_("%s: untracked file differs\n") % f)
         if abortconflicts:
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
--- a/tests/test-merge1.t
+++ b/tests/test-merge1.t
@@ -152,10 +152,78 @@  this merge should silently ignore
   1 files updated, 0 files merged, 0 files removed, 0 files unresolved
   (branch merge, don't forget to commit)
 
+merge.checkignored
+  $ hg up --clean 1
+  1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  $ cat >> .hgignore << EOF
+  > remoteignored
+  > EOF
+  $ echo This is file localignored3 > localignored
+  $ echo This is file remoteignored3 > remoteignored
+  $ hg add .hgignore localignored remoteignored
+  $ hg commit -m "commit #3"
+
+  $ hg up 2
+  1 files updated, 0 files merged, 4 files removed, 0 files unresolved
+  $ cat >> .hgignore << EOF
+  > localignored
+  > EOF
+  $ hg add .hgignore
+  $ hg commit -m "commit #4"
+
+remote .hgignore shouldn't be used for determining whether a file is ignored
+  $ echo This is file remoteignored4 > remoteignored
+  $ hg merge 3 --config merge.checkignored=ignore --config merge.checkunknown=abort
+  remoteignored: untracked file differs
+  abort: untracked files in working directory differ from files in requested revision
+  [255]
+  $ hg merge 3 --config merge.checkignored=abort --config merge.checkunknown=ignore
+  merging .hgignore
+  merging for .hgignore
+  3 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ cat remoteignored
+  This is file remoteignored3
+  $ cat remoteignored.orig
+  This is file remoteignored4
+  $ rm remoteignored.orig
+
+local .hgignore should be used for that
+  $ hg up --clean 4
+  1 files updated, 0 files merged, 3 files removed, 0 files unresolved
+  $ echo This is file localignored4 > localignored
+also test other conflicting files to see we output the full set of warnings
+  $ echo This is file b2 > b
+  $ hg merge 3 --config merge.checkignored=abort --config merge.checkunknown=abort
+  b: untracked file differs
+  localignored: untracked file differs
+  abort: untracked files in working directory differ from files in requested revision
+  [255]
+  $ hg merge 3 --config merge.checkignored=abort --config merge.checkunknown=ignore
+  localignored: untracked file differs
+  abort: untracked files in working directory differ from files in requested revision
+  [255]
+  $ hg merge 3 --config merge.checkignored=warn --config merge.checkunknown=abort
+  b: untracked file differs
+  abort: untracked files in working directory differ from files in requested revision
+  [255]
+  $ hg merge 3 --config merge.checkignored=warn --config merge.checkunknown=warn
+  b: replacing untracked file
+  localignored: replacing untracked file
+  merging .hgignore
+  merging for .hgignore
+  3 files updated, 1 files merged, 0 files removed, 0 files unresolved
+  (branch merge, don't forget to commit)
+  $ cat localignored
+  This is file localignored3
+  $ cat localignored.orig
+  This is file localignored4
+  $ rm localignored.orig
+
   $ cat b.orig
   This is file b2
   $ hg up --clean 2
-  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 4 files removed, 0 files unresolved
   $ mv b.orig b
 
 this merge of b should work