From patchwork Wed May 15 15:44:49 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [1, of, 3, V2] merge: check whether existing directory is related to tracked files or not From: Katsunori FUJIWARA X-Patchwork-Id: 1653 Message-Id: <06f5233fe026033740b5.1368632689@juju> To: mercurial-devel@selenic.com Date: Thu, 16 May 2013 00:44:49 +0900 # HG changeset patch # User FUJIWARA Katsunori # 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 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 ..