Patchwork [1,of,3,V2] merge: check whether existing directory is related to tracked files or not

login
register
mail settings
Submitter Katsunori FUJIWARA
Date May 15, 2013, 3:44 p.m.
Message ID <06f5233fe026033740b5.1368632689@juju>
Download mbox | patch
Permalink /patch/1653/
State Superseded, archived
Commit 9bfa86746c9c1f6ab51deb8f174ffc482417d09f
Headers show

Comments

Katsunori FUJIWARA - May 15, 2013, 3:44 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1368632069 -32400
#      Thu May 16 00:34:29 2013 +0900
# Node ID 06f5233fe026033740b5f7ee77234bd0a9b02016
# Parent  0fbcabe523bcaa68ee3f91bddfef0af6815a2016
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 whether it is related to tracked files or not, if it is directory.

If so, such directory can be ignored, because collision should be
checked in "_checkcollision()" (if issue29 is fixed). Otherwise,
merging/updating should be aborted, because this directory collides
the file in the target context.

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

Patch

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
-import errno, os, shutil
+import errno, os, shutil, stat
 
 class mergestate(object):
     '''track 3-way merge state of individual files'''
@@ -93,8 +93,16 @@ 
         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.wopener.audit.check(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
@@ -173,4 +173,21 @@ 
   $ hg revert -r -2 b
   $ hg up -q -- -2
 
+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 ..