summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2015-08-29 16:19:52 +0200
committerSebastian Thiel <byronimo@gmail.com>2015-08-29 16:20:28 +0200
commite8590424997ab1d578c777fe44bf7e4173036f93 (patch)
treeb65d2b954c878ca11439f94f42e52b40437701c7
parent6eb3af27464ffba83e3478b0a0c8b1f9ff190889 (diff)
downloadgitpython-e8590424997ab1d578c777fe44bf7e4173036f93.tar.gz
fix(repo): fail loudly if worktrees are used
As GitPython is in maintenance mode, there will be no new features. However, I believe it's good idea to explicitly state we do not support certain things if this is the case. Therefore, when worktrees are encountered, we will throw an specific exception to indicate that. The current implementation is hacky to speed up development, and increases the risk of failing due to false-positive worktree directories. Related to #344
-rw-r--r--git/exc.py4
-rw-r--r--git/repo/fun.py25
-rw-r--r--git/test/test_repo.py20
3 files changed, 39 insertions, 10 deletions
diff --git a/git/exc.py b/git/exc.py
index f5b52374..34382ecd 100644
--- a/git/exc.py
+++ b/git/exc.py
@@ -14,6 +14,10 @@ class InvalidGitRepositoryError(Exception):
""" Thrown if the given repository appears to have an invalid format. """
+class WorkTreeRepositoryUnsupported(InvalidGitRepositoryError):
+ """ Thrown to indicate we can't handle work tree repositories """
+
+
class NoSuchPathError(OSError):
""" Thrown if a path could not be access by the system. """
diff --git a/git/repo/fun.py b/git/repo/fun.py
index 049800b9..6b06663a 100644
--- a/git/repo/fun.py
+++ b/git/repo/fun.py
@@ -4,7 +4,7 @@ from string import digits
from gitdb.exc import (
BadObject,
- BadName
+ BadName,
)
from git.refs import SymbolicReference
from git.objects import Object
@@ -16,6 +16,7 @@ from gitdb.util import (
hex_to_bin,
bin_to_hex
)
+from git.exc import WorkTreeRepositoryUnsupported
from git.compat import xrange
@@ -31,14 +32,20 @@ def touch(filename):
def is_git_dir(d):
""" This is taken from the git setup.c:is_git_directory
- function."""
- if isdir(d) and \
- isdir(join(d, 'objects')) and \
- isdir(join(d, 'refs')):
- headref = join(d, 'HEAD')
- return isfile(headref) or \
- (os.path.islink(headref) and
- os.readlink(headref).startswith('refs'))
+ function.
+
+ @throws WorkTreeRepositoryUnsupported if it sees a worktree directory. It's quite hacky to do that here,
+ but at least clearly indicates that we don't support it.
+ There is the unlikely danger to throw if we see directories which just look like a worktree dir,
+ but are none."""
+ if isdir(d):
+ if isdir(join(d, 'objects')) and isdir(join(d, 'refs')):
+ headref = join(d, 'HEAD')
+ return isfile(headref) or \
+ (os.path.islink(headref) and
+ os.readlink(headref).startswith('refs'))
+ elif isfile(join(d, 'gitdir')) and isfile(join(d, 'commondir')) and isfile(join(d, 'gitfile')):
+ raise WorkTreeRepositoryUnsupported(d)
return False
diff --git a/git/test/test_repo.py b/git/test/test_repo.py
index c95592ea..2e44f0aa 100644
--- a/git/test/test_repo.py
+++ b/git/test/test_repo.py
@@ -33,7 +33,10 @@ from git import (
)
from git.repo.fun import touch
from git.util import join_path_native
-from git.exc import BadObject
+from git.exc import (
+ BadObject,
+ WorkTreeRepositoryUnsupported
+)
from gitdb.util import bin_to_hex
from git.compat import string_types
from gitdb.test.lib import with_rw_directory
@@ -45,6 +48,8 @@ import shutil
import itertools
from io import BytesIO
+from nose import SkipTest
+
class TestRepo(TestBase):
@@ -779,3 +784,16 @@ class TestRepo(TestBase):
self.assertFalse(repo.is_ancestor("master", c1))
for i, j in itertools.permutations([c1, 'ffffff', ''], r=2):
self.assertRaises(GitCommandError, repo.is_ancestor, i, j)
+
+ @with_rw_directory
+ def test_work_tree_unsupported(self, rw_dir):
+ git = Git(rw_dir)
+ if git.version_info[:3] < (2, 5, 1):
+ raise SkipTest("worktree feature unsupported")
+
+ rw_master = self.rorepo.clone(join_path_native(rw_dir, 'master_repo'))
+ rw_master.git.checkout('HEAD~10')
+ worktree_path = join_path_native(rw_dir, 'worktree_repo')
+ rw_master.git.worktree('add', worktree_path, 'master')
+
+ self.failUnlessRaises(WorkTreeRepositoryUnsupported, Repo, worktree_path)