Skip to content

Commit e859042

Browse files
committed
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
1 parent 6eb3af2 commit e859042

File tree

3 files changed

+39
-10
lines changed

3 files changed

+39
-10
lines changed

‎git/exc.py

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ class InvalidGitRepositoryError(Exception):
1414
""" Thrown if the given repository appears to have an invalid format. """
1515

1616

17+
class WorkTreeRepositoryUnsupported(InvalidGitRepositoryError):
18+
""" Thrown to indicate we can't handle work tree repositories """
19+
20+
1721
class NoSuchPathError(OSError):
1822
""" Thrown if a path could not be access by the system. """
1923

‎git/repo/fun.py

+16-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from gitdb.exc import (
66
BadObject,
7-
BadName
7+
BadName,
88
)
99
from git.refs import SymbolicReference
1010
from git.objects import Object
@@ -16,6 +16,7 @@
1616
hex_to_bin,
1717
bin_to_hex
1818
)
19+
from git.exc import WorkTreeRepositoryUnsupported
1920
from git.compat import xrange
2021

2122

@@ -31,14 +32,20 @@ def touch(filename):
3132

3233
def is_git_dir(d):
3334
""" This is taken from the git setup.c:is_git_directory
34-
function."""
35-
if isdir(d) and \
36-
isdir(join(d, 'objects')) and \
37-
isdir(join(d, 'refs')):
38-
headref = join(d, 'HEAD')
39-
return isfile(headref) or \
40-
(os.path.islink(headref) and
41-
os.readlink(headref).startswith('refs'))
35+
function.
36+
37+
@throws WorkTreeRepositoryUnsupported if it sees a worktree directory. It's quite hacky to do that here,
38+
but at least clearly indicates that we don't support it.
39+
There is the unlikely danger to throw if we see directories which just look like a worktree dir,
40+
but are none."""
41+
if isdir(d):
42+
if isdir(join(d, 'objects')) and isdir(join(d, 'refs')):
43+
headref = join(d, 'HEAD')
44+
return isfile(headref) or \
45+
(os.path.islink(headref) and
46+
os.readlink(headref).startswith('refs'))
47+
elif isfile(join(d, 'gitdir')) and isfile(join(d, 'commondir')) and isfile(join(d, 'gitfile')):
48+
raise WorkTreeRepositoryUnsupported(d)
4249
return False
4350

4451

‎git/test/test_repo.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@
3333
)
3434
from git.repo.fun import touch
3535
from git.util import join_path_native
36-
from git.exc import BadObject
36+
from git.exc import (
37+
BadObject,
38+
WorkTreeRepositoryUnsupported
39+
)
3740
from gitdb.util import bin_to_hex
3841
from git.compat import string_types
3942
from gitdb.test.lib import with_rw_directory
@@ -45,6 +48,8 @@
4548
import itertools
4649
from io import BytesIO
4750

51+
from nose import SkipTest
52+
4853

4954
class TestRepo(TestBase):
5055

@@ -779,3 +784,16 @@ def test_is_ancestor(self):
779784
self.assertFalse(repo.is_ancestor("master", c1))
780785
for i, j in itertools.permutations([c1, 'ffffff', ''], r=2):
781786
self.assertRaises(GitCommandError, repo.is_ancestor, i, j)
787+
788+
@with_rw_directory
789+
def test_work_tree_unsupported(self, rw_dir):
790+
git = Git(rw_dir)
791+
if git.version_info[:3] < (2, 5, 1):
792+
raise SkipTest("worktree feature unsupported")
793+
794+
rw_master = self.rorepo.clone(join_path_native(rw_dir, 'master_repo'))
795+
rw_master.git.checkout('HEAD~10')
796+
worktree_path = join_path_native(rw_dir, 'worktree_repo')
797+
rw_master.git.worktree('add', worktree_path, 'master')
798+
799+
self.failUnlessRaises(WorkTreeRepositoryUnsupported, Repo, worktree_path)

0 commit comments

Comments
 (0)