[PATCH 2 of 2 v3] add: notify when adding a file that would cause a case-folding collision

Kevin Gessner kevin at fogcreek.com
Sat Apr 30 07:37:08 CDT 2011


# HG changeset patch
# User Kevin Gessner <kevin at kevingessner.com>
# Date 1304159986 -7200
# Node ID ff0e87163b43ce808f9dbde1689e6bc18a0735e9
# Parent  7d8f45c157752f91ae4daa590146463c1bbb304c
add: notify when adding a file that would cause a case-folding collision

On a case-sensitive file system, files can be added with names that differ
only in case (a "case collision"). This would cause an error on case-insensitive
filesystems. A warning or error is now given for such collisions, depending on
the value of ui.portablefilenames ('warn', 'abort', or 'ignore'):

    $ touch file File
    $ hg add --config ui.portablefilenames=abort File
    abort: possible case-folding collision for File
    $ hg add File
    warning: possible case-folding collision for File

diff -r 7d8f45c15775 -r ff0e87163b43 mercurial/cmdutil.py
--- a/mercurial/cmdutil.py	Sat Apr 30 11:08:24 2011 +0200
+++ b/mercurial/cmdutil.py	Sat Apr 30 12:39:46 2011 +0200
@@ -1314,9 +1314,16 @@
     match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
     names = []
     wctx = repo[None]
+    wctx.status(clean=True)
+    existing = None
+    if scmutil.showportabilityalert(ui):
+        existing = dict([(fn.lower(), fn) for fn in
+                         wctx.added() + wctx.clean() + wctx.modified()])
     for f in repo.walk(match):
         exact = match.exact(f)
         if exact or f not in repo.dirstate:
+            if existing:
+                scmutil.checkcasecollision(ui, f, existing)
             names.append(f)
             if ui.verbose or not exact:
                 ui.status(_('adding %s\n') % match.rel(join(f)))
diff -r 7d8f45c15775 -r ff0e87163b43 mercurial/scmutil.py
--- a/mercurial/scmutil.py	Sat Apr 30 11:08:24 2011 +0200
+++ b/mercurial/scmutil.py	Sat Apr 30 12:39:46 2011 +0200
@@ -22,6 +22,11 @@
         if msg:
             portabilityalert(ui, "%s: %r" % (msg, f))
 
+def checkcasecollision(ui, f, files):
+    if f.lower() in files and files[f.lower()] != f:
+        portabilityalert(ui, _('possible case-folding collision for %s') % f)
+    files[f.lower()] = f
+
 def checkportabilityalert(ui):
     '''check if the user's config requests nothing, a warning, or abort for
     non-portable filenames'''
diff -r 7d8f45c15775 -r ff0e87163b43 tests/test-casecollision.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-casecollision.t	Sat Apr 30 12:39:46 2011 +0200
@@ -0,0 +1,34 @@
+run only on case-sensitive filesystems
+
+  $ "$TESTDIR/hghave" no-icasefs || exit 80
+
+test file addition with colliding case
+
+  $ hg init repo1
+  $ cd repo1
+  $ echo a > a
+  $ echo A > A
+  $ hg add a
+  $ hg st
+  A a
+  ? A
+  $ hg add --config ui.portablefilenames=abort A
+  abort: possible case-folding collision for A
+  [255]
+  $ hg st
+  A a
+  ? A
+  $ hg add A
+  warning: possible case-folding collision for A
+  $ hg st
+  A A
+  A a
+  $ hg forget A
+  $ hg st
+  A a
+  ? A
+  $ hg add --config ui.portablefilenames=no A
+  $ hg st
+  A A
+  A a
+  $ cd ..


More information about the Mercurial-devel mailing list