summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiana Picus <diana.picus@linaro.org>2016-12-08 13:13:35 +0200
committerDiana Picus <diana.picus@linaro.org>2016-12-08 13:13:35 +0200
commit52698c31da9d88a0117794d6b59386a2063a697f (patch)
tree1cd17175a1c04cafd4f2fc4b2d4366c5bf743963
parent3c91049161179bc3e5990fb3641d24bbafc0ff26 (diff)
Fix worktree detection
Detecting whether or not a directory is a worktree was very broken - it compared the value returned by git rev-parse --git-common-dir with ".git", which is wrong for at least 2 reasons: * when we're in a subdirectory of a worktree, that will return the common dir for the worktree, which means that we're not detecting whether the subdirectory itself is a worktree, we're detecting whether one of its parents is; this is problematic for complex worktree hierarchies like those used for llvm (where llvm is a worktree, and llvm/tools/clang is a different worktree); * when we're in a subdirectory of a git repo (main working tree as opposed to worktree), the common dir will not be just ".git", which means that we'll illegitimately think we're in a worktree. The fix is to check that we have a ".git" file right inside the given directory. This fixes the first problem because we're no longer seeing anything from the parent directories, and the second problem because we're differentiating between ".git" files (worktree) and ".git" directories (repo). Change-Id: I5b93ad7b1ab849d18a64cbed574f1b74d15678dd
-rw-r--r--linaropy/git/worktree.py57
1 files changed, 45 insertions, 12 deletions
diff --git a/linaropy/git/worktree.py b/linaropy/git/worktree.py
index 833ebfa..2f2940d 100644
--- a/linaropy/git/worktree.py
+++ b/linaropy/git/worktree.py
@@ -125,19 +125,16 @@ class Worktree(GitRepo):
if not os.path.isdir(path):
raise EnvironmentError('%s does not name a directory' % path)
- try:
- with cd(path):
- commonDir = str(git("rev-parse", "--git-common-dir"))[:-1]
- if commonDir == ".git":
- # The git common dir should point to the .git directory of
- # the repo that the worktree was created from. If we're in
- # a repo that isn't a worktree, it will point to the local
- # .git.
- raise EnvironmentError('%s is not a worktree' % path)
-
- self.repodir = path
- except ErrorReturnCode:
+ if not os.path.isfile(os.path.join(path, ".git")):
+ # A worktree always contains a .git file in its root (as opposed to
+ # a .git directory, as contained by the main working tree obtained
+ # with git init or git clone).
+ # Note that we are VERY specific about where we want that .git file
+ # to live - using git rev-parse could mislead us into thinking that
+ # any subdirectory within a worktree is itself a worktree, which
+ # makes it impossible to detect complex hierarchies of worktrees.
raise EnvironmentError('%s is not a worktree' % path)
+ self.repodir = path
def get_original_repo(self):
# The git common dir should point to the .git directory of the repo that
@@ -546,6 +543,7 @@ class TestWorktree(unittest.TestCase):
def test_not_a_worktree(self):
worktreePath = os.path.join(self.proj.projdir, "worktreedir")
+ # Test that an empty directory is not mistaken for a worktree.
os.makedirs(worktreePath)
with self.assertRaises(EnvironmentError) as context:
@@ -554,12 +552,47 @@ class TestWorktree(unittest.TestCase):
self.assertEqual(str(context.exception),
"%s is not a worktree" % worktreePath)
+ # Test that a non-empty directory that doesn't contain anything
+ # git-related is not mistaken for a worktree.
+ os.makedirs(os.path.join(worktreePath, "notempty"))
+
+ with self.assertRaises(EnvironmentError) as context:
+ self.worktree = Worktree(self.proj, worktreePath)
+
+ self.assertEqual(str(context.exception),
+ "%s is not a worktree" % worktreePath)
+
+ # Test that a main git workting tree (obtained with git init or git
+ # clone) isn't mistaken for a worktree.
with self.assertRaises(EnvironmentError) as context:
self.worktree = Worktree(self.proj, self.repo.clonedir())
self.assertEqual(str(context.exception),
"%s is not a worktree" % self.repo.clonedir())
+ # Test that a directory that contains a worktree as a subdirectory is
+ # not mistaken for a worktree.
+ childWorktreePath = os.path.join(worktreePath, "aworktree")
+ with cd(self.repo.clonedir()):
+ git("worktree", "add", "-b", "wokrtreebranch1", childWorktreePath)
+
+ with self.assertRaises(EnvironmentError) as context:
+ self.worktree = Worktree(self.proj, worktreePath)
+
+ self.assertEqual(str(context.exception),
+ "%s is not a worktree" % worktreePath)
+
+ # Test that a subdirectory of a worktree is not mistaken for a
+ # worktree.
+ worktreeSubdirPath = os.path.join(childWorktreePath, "notaworktree")
+ os.makedirs(worktreeSubdirPath)
+
+ with self.assertRaises(EnvironmentError) as context:
+ self.worktree = Worktree(self.proj, worktreeSubdirPath)
+
+ self.assertEqual(str(context.exception),
+ "%s is not a worktree" % worktreeSubdirPath)
+
def test_get_original_repo(self):
worktreePath = os.path.join(self.proj.projdir, "worktreedir")
worktreeBranch = "worktreebranch"