[PATCH 3 of 7 STABLE] merge: check whether existing directory is related to tracked files or not

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Mon May 6 15:35:03 CDT 2013


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1367870651 -32400
#      Tue May 07 05:04:11 2013 +0900
# Branch stable
# Node ID d12b0211d5ea3b6e30a732a9d5381314a83862b1
# Parent  1bede396d3f4dfd7763e214befd12fea9df63130
merge: check whether existing directory is related to tracked files or not

Before this patch, updating/merging is aborted and updates working
directory status incompletely, when there is the directory of which
name is as same as one in target context.

This patch checks type of the specified file in the working directory,
and check whether it is related to tracked files if it is directory.

If so, this can be ignored, because collision check in
"_checkcollision()" can recognize this directory. Otherwise, this
directory collides the file in the target context, and
merging/updating should be aborted.

This patch adds "lstat()" to vfs instead of using "os.lstat()" or
"vfs.isdir()", because:

  - "os.lstat()" requires path composition like "repo.wjoin(f)"

  - "vfs.isdir()" (= "os.isdir()") recognizes also symbolic link to
    directory as directory unexpectedly

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -9,7 +9,7 @@
 from i18n import _
 from mercurial import obsolete
 import error, util, filemerge, copies, subrepo, worker, dicthelpers, scmutil
-import errno, os, shutil
+import errno, os, shutil, stat
 
 class mergestate(object):
     '''track 3-way merge state of individual files'''
@@ -93,8 +93,15 @@
         return r
 
 def _checkunknownfile(repo, wctx, mctx, f):
+    try:
+        mode = repo.wvfs.lstat(f).st_mode
+    except OSError, err:
+        if err.errno not in (errno.ENOENT, errno.ENOTDIR):
+            raise
+        return False
+    if stat.S_ISDIR(mode):
+        return repo.dirstate.normalize(f) not in repo.dirstate.dirs()
     return (not repo.dirstate._ignore(f)
-        and os.path.isfile(repo.wjoin(f))
         and repo.dirstate.normalize(f) not in repo.dirstate
         and mctx[f].cmp(wctx[f]))
 
diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py
--- a/mercurial/scmutil.py
+++ b/mercurial/scmutil.py
@@ -247,6 +247,9 @@
     def islink(self, path=None):
         return os.path.islink(self.join(path))
 
+    def lstat(self, path=None):
+        return os.lstat(self.join(path))
+
     def makedir(self, path=None, notindexed=True):
         return util.makedir(self.join(path), notindexed)
 
diff --git a/tests/test-merge1.t b/tests/test-merge1.t
--- a/tests/test-merge1.t
+++ b/tests/test-merge1.t
@@ -196,4 +196,21 @@
   abort: collision between file c and other directory
   [255]
 
+test detecting collision between files in target context and unknown
+ones in working directory
+
+  $ hg update -q -C 1
+  $ hg manifest -r 1
+  a
+  b
+  $ hg manifest -r 3
+  a
+  b
+  c
+  $ mkdir c
+  $ hg update -q 3
+  c: untracked file differs
+  abort: untracked files in working directory differ from files in requested revision
+  [255]
+
   $ cd ..


More information about the Mercurial-devel mailing list