merge: split up checks for unknown and ignored files that differ
authorSiddharth Agarwal <sid0@fb.com>
Tue, 12 Jan 2016 18:38:49 -0800
changeset 27742 6b639caa1652
parent 27741 3951f132958f
child 27743 5dcadc6c5aed
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.
mercurial/help/config.txt
mercurial/merge.py
tests/test-merge1.t
--- a/mercurial/help/config.txt	Tue Jan 12 18:17:07 2016 -0800
+++ b/mercurial/help/config.txt	Tue Jan 12 18:38:49 2016 -0800
@@ -990,14 +990,20 @@
 
 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``
 ------------------
 
--- a/mercurial/merge.py	Tue Jan 12 18:17:07 2016 -0800
+++ b/mercurial/merge.py	Tue Jan 12 18:38:49 2016 -0800
@@ -591,7 +591,8 @@
             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 @@
                 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:
--- a/tests/test-merge1.t	Tue Jan 12 18:17:07 2016 -0800
+++ b/tests/test-merge1.t	Tue Jan 12 18:38:49 2016 -0800
@@ -152,10 +152,78 @@
   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