merge: while checking for unknown files don't follow symlinks (issue5027) stable
authorSiddharth Agarwal <sid0@fb.com>
Mon, 28 Dec 2015 22:51:37 -0800
branchstable
changeset 27571 6a6e78f84cc6
parent 27555 ca8ada499529
child 27573 ea389970c084
merge: while checking for unknown files don't follow symlinks (issue5027) Previously, we were using Python's native 'os.path.isfile' method which follows symlinks. In this case, since we're operating on repo contents, we don't want to follow symlinks. There's a behaviour change here, as shown by the second part of the added test. Consider a symlink 'f' pointing to a file containing 'abc'. If we try and replace it with a file with contents 'abc', previously we would have let it though. Now we don't. Although this breaks naive inspection with tools like 'cat' and 'diff', on balance I believe this is the right change.
mercurial/merge.py
mercurial/scmutil.py
tests/test-merge1.t
--- a/mercurial/merge.py	Sat Dec 26 15:18:16 2015 +0900
+++ b/mercurial/merge.py	Mon Dec 28 22:51:37 2015 -0800
@@ -404,7 +404,7 @@
 def _checkunknownfile(repo, wctx, mctx, f, f2=None):
     if f2 is None:
         f2 = f
-    return (os.path.isfile(repo.wjoin(f))
+    return (repo.wvfs.isfileorlink(f)
         and repo.wvfs.audit.check(f)
         and repo.dirstate.normalize(f) not in repo.dirstate
         and mctx[f2].cmp(wctx[f]))
--- a/mercurial/scmutil.py	Sat Dec 26 15:18:16 2015 +0900
+++ b/mercurial/scmutil.py	Mon Dec 28 22:51:37 2015 -0800
@@ -312,6 +312,17 @@
     def islink(self, path=None):
         return os.path.islink(self.join(path))
 
+    def isfileorlink(self, path=None):
+        '''return whether path is a regular file or a symlink
+
+        Unlike isfile, this doesn't follow symlinks.'''
+        try:
+            st = self.lstat(path)
+        except OSError:
+            return False
+        mode = st.st_mode
+        return stat.S_ISREG(mode) or stat.S_ISLNK(mode)
+
     def reljoin(self, *paths):
         """join various elements of a path together (as os.path.join would do)
 
--- a/tests/test-merge1.t	Sat Dec 26 15:18:16 2015 +0900
+++ b/tests/test-merge1.t	Mon Dec 28 22:51:37 2015 -0800
@@ -102,6 +102,28 @@
   b: untracked file differs
   abort: untracked files in working directory differ from files in requested revision
   [255]
+
+#if symlink
+symlinks to directories should be treated as regular files (issue5027)
+  $ rm b
+  $ ln -s 'This is file b2' b
+  $ hg merge 1
+  b: untracked file differs
+  abort: untracked files in working directory differ from files in requested revision
+  [255]
+symlinks shouldn't be followed
+  $ rm b
+  $ echo This is file b1 > .hg/b
+  $ ln -s .hg/b b
+  $ hg merge 1
+  b: untracked file differs
+  abort: untracked files in working directory differ from files in requested revision
+  [255]
+
+  $ rm b
+  $ echo This is file b2 > b
+#endif
+
 merge of b expected
   $ hg merge -f 1
   merging b