Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitaec58a9

Browse files
vathpelaByron
authored andcommitted
Repo: handle worktrees better
This makes Repo("foo") work when foo/.git is a file of the form createdby "git worktree add", i.e. it's a text file that says:gitdir: /home/me/project/.git/worktrees/barand where /home/me/project/.git/ is the nominal gitdir, but/home/me/project/.git/worktrees/bar has this worktree's HEAD etc and a"gitdir" file that contains the path of foo/.git .Signed-off-by: Peter Jones <pjones@redhat.com>
1 parent4bd708d commitaec58a9

File tree

6 files changed

+105
-19
lines changed

6 files changed

+105
-19
lines changed

‎AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@ Contributors are:
1818
-Bernard `Guyzmo` Pratz <guyzmo+gitpython+pub@m0g.net>
1919
-Timothy B. Hartman <tbhartman _at_ gmail.com>
2020
-Konstantin Popov <konstantin.popov.89 _at_ yandex.ru>
21+
-Peter Jones <pjones _at_ redhat.com>
2122

2223
Portions derived from other open source works and are clearly marked.

‎git/refs/symbolic.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,12 @@ def abspath(self):
7575

7676
@classmethod
7777
def_get_packed_refs_path(cls,repo):
78-
returnosp.join(repo.git_dir,'packed-refs')
78+
try:
79+
commondir=open(osp.join(repo.git_dir,'commondir'),'rt').readlines()[0].strip()
80+
except (OSError,IOError):
81+
commondir='.'
82+
repodir=osp.join(repo.git_dir,commondir)
83+
returnosp.join(repodir,'packed-refs')
7984

8085
@classmethod
8186
def_iter_packed_refs(cls,repo):
@@ -122,13 +127,13 @@ def dereference_recursive(cls, repo, ref_path):
122127
# END recursive dereferencing
123128

124129
@classmethod
125-
def_get_ref_info(cls,repo,ref_path):
130+
def_get_ref_info_helper(cls,repo,repodir,ref_path):
126131
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
127132
rela_path points to, or None. target_ref_path is the reference we
128133
point to, or None"""
129134
tokens=None
130135
try:
131-
withopen(osp.join(repo.git_dir,ref_path),'rt')asfp:
136+
withopen(osp.join(repodir,ref_path),'rt')asfp:
132137
value=fp.read().rstrip()
133138
# Don't only split on spaces, but on whitespace, which allows to parse lines like
134139
# 60b64ef992065e2600bfef6187a97f92398a9144 branch 'master' of git-server:/path/to/repo
@@ -159,6 +164,22 @@ def _get_ref_info(cls, repo, ref_path):
159164

160165
raiseValueError("Failed to parse reference information from %r"%ref_path)
161166

167+
@classmethod
168+
def_get_ref_info(cls,repo,ref_path):
169+
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
170+
rela_path points to, or None. target_ref_path is the reference we
171+
point to, or None"""
172+
try:
173+
returncls._get_ref_info_helper(repo,repo.git_dir,ref_path)
174+
exceptValueError:
175+
try:
176+
commondir=open(osp.join(repo.git_dir,'commondir'),'rt').readlines()[0].strip()
177+
except (OSError,IOError):
178+
commondir='.'
179+
180+
repodir=osp.join(repo.git_dir,commondir)
181+
returncls._get_ref_info_helper(repo,repodir,ref_path)
182+
162183
def_get_object(self):
163184
"""
164185
:return:

‎git/repo/base.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
fromgit.utilimportActor,finalize_process,decygpath,hex_to_bin
3333
importos.pathasosp
3434

35-
from .funimportrev_parse,is_git_dir,find_submodule_git_dir,touch
35+
from .funimportrev_parse,is_git_dir,find_submodule_git_dir,touch,find_worktree_git_dir
3636
importgc
3737
importgitdb
3838

@@ -138,10 +138,15 @@ def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=Fals
138138
self._working_tree_dir=os.getenv('GIT_WORK_TREE',os.path.dirname(self.git_dir))
139139
break
140140

141-
sm_gitpath=find_submodule_git_dir(osp.join(curpath,'.git'))
141+
dotgit=osp.join(curpath,'.git')
142+
sm_gitpath=find_submodule_git_dir(dotgit)
142143
ifsm_gitpathisnotNone:
143144
self.git_dir=osp.normpath(sm_gitpath)
144-
sm_gitpath=find_submodule_git_dir(osp.join(curpath,'.git'))
145+
146+
sm_gitpath=find_submodule_git_dir(dotgit)
147+
ifsm_gitpathisNone:
148+
sm_gitpath=find_worktree_git_dir(dotgit)
149+
145150
ifsm_gitpathisnotNone:
146151
self.git_dir=_expand_path(sm_gitpath)
147152
self._working_tree_dir=curpath

‎git/repo/fun.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Package with general repository related functions"""
22
importos
3+
importstat
34
fromstringimportdigits
45

56
fromgit.compatimportxrange
@@ -17,7 +18,7 @@
1718

1819

1920
__all__= ('rev_parse','is_git_dir','touch','find_submodule_git_dir','name_to_object','short_to_long','deref_tag',
20-
'to_commit')
21+
'to_commit','find_worktree_git_dir')
2122

2223

2324
deftouch(filename):
@@ -47,6 +48,25 @@ def is_git_dir(d):
4748
returnFalse
4849

4950

51+
deffind_worktree_git_dir(dotgit):
52+
"""Search for a gitdir for this worktree."""
53+
try:
54+
statbuf=os.stat(dotgit)
55+
exceptOSError:
56+
returnNone
57+
ifnotstat.S_ISREG(statbuf.st_mode):
58+
returnNone
59+
60+
try:
61+
lines=open(dotgit,'r').readlines()
62+
forkey,valuein [line.strip().split(': ')forlineinlines]:
63+
ifkey=='gitdir':
64+
returnvalue
65+
exceptValueError:
66+
pass
67+
returnNone
68+
69+
5070
deffind_submodule_git_dir(d):
5171
"""Search for a submodule repo."""
5272
ifis_git_dir(d):

‎git/test/test_fun.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
fromioimportBytesIO
22
fromstatimportS_IFDIR,S_IFREG,S_IFLNK
3+
fromosimportstat
4+
importos.pathasosp
5+
36
try:
4-
fromunittestimportskipIf
7+
fromunittestimportskipIf,SkipTest
58
exceptImportError:
6-
fromunittest2importskipIf
9+
fromunittest2importskipIf,SkipTest
710

11+
fromgitimportGit
812
fromgit.compatimportPY3
913
fromgit.indeximportIndexFile
1014
fromgit.index.funimport (
@@ -14,13 +18,18 @@
1418
traverse_tree_recursive,
1519
traverse_trees_recursive,
1620
tree_to_stream,
17-
tree_entries_from_data
21+
tree_entries_from_data,
22+
)
23+
fromgit.repo.funimport (
24+
find_worktree_git_dir
1825
)
1926
fromgit.test.libimport (
27+
assert_true,
2028
TestBase,
21-
with_rw_repo
29+
with_rw_repo,
30+
with_rw_directory
2231
)
23-
fromgit.utilimportbin_to_hex
32+
fromgit.utilimportbin_to_hex,cygpath,join_path_native
2433
fromgitdb.baseimportIStream
2534
fromgitdb.typimportstr_tree_type
2635

@@ -254,6 +263,29 @@ def test_tree_traversal_single(self):
254263
assertentries
255264
# END for each commit
256265

266+
@with_rw_directory
267+
deftest_linked_worktree_traversal(self,rw_dir):
268+
"""Check that we can identify a linked worktree based on a .git file"""
269+
git=Git(rw_dir)
270+
ifgit.version_info[:3]< (2,5,1):
271+
raiseSkipTest("worktree feature unsupported")
272+
273+
rw_master=self.rorepo.clone(join_path_native(rw_dir,'master_repo'))
274+
branch=rw_master.create_head('aaaaaaaa')
275+
worktree_path=join_path_native(rw_dir,'worktree_repo')
276+
ifGit.is_cygwin():
277+
worktree_path=cygpath(worktree_path)
278+
rw_master.git.worktree('add',worktree_path,branch.name)
279+
280+
dotgit=osp.join(worktree_path,".git")
281+
statbuf=stat(dotgit)
282+
assert_true(statbuf.st_mode&S_IFREG)
283+
284+
gitdir=find_worktree_git_dir(dotgit)
285+
self.assertIsNotNone(gitdir)
286+
statbuf=stat(gitdir)
287+
assert_true(statbuf.st_mode&S_IFDIR)
288+
257289
@skipIf(PY3,'odd types returned ... maybe figure it out one day')
258290
deftest_tree_entries_from_data_with_failing_name_decode_py2(self):
259291
r=tree_entries_from_data(b'100644\x9f\0aaa')

‎git/test/test_repo.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
NoSuchPathError,
2323
Head,
2424
Commit,
25+
Object,
2526
Tree,
2627
IndexFile,
2728
Git,
@@ -911,22 +912,28 @@ def test_is_ancestor(self):
911912
self.assertRaises(GitCommandError,repo.is_ancestor,i,j)
912913

913914
@with_rw_directory
914-
deftest_work_tree_unsupported(self,rw_dir):
915+
deftest_git_work_tree_dotgit(self,rw_dir):
916+
"""Check that we find .git as a worktree file and find the worktree
917+
based on it."""
915918
git=Git(rw_dir)
916919
ifgit.version_info[:3]< (2,5,1):
917920
raiseSkipTest("worktree feature unsupported")
918921

919922
rw_master=self.rorepo.clone(join_path_native(rw_dir,'master_repo'))
920-
rw_master.git.checkout('HEAD~10')
923+
branch=rw_master.create_head('aaaaaaaa')
921924
worktree_path=join_path_native(rw_dir,'worktree_repo')
922925
ifGit.is_cygwin():
923926
worktree_path=cygpath(worktree_path)
924-
try:
925-
rw_master.git.worktree('add',worktree_path,'master')
926-
exceptExceptionasex:
927-
raiseAssertionError(ex,"It's ok if TC not running from `master`.")
927+
rw_master.git.worktree('add',worktree_path,branch.name)
928+
929+
# this ensures that we can read the repo's gitdir correctly
930+
repo=Repo(worktree_path)
931+
self.assertIsInstance(repo,Repo)
928932

929-
self.failUnlessRaises(InvalidGitRepositoryError,Repo,worktree_path)
933+
# this ensures we're able to actually read the refs in the tree, which
934+
# means we can read commondir correctly.
935+
commit=repo.head.commit
936+
self.assertIsInstance(commit,Object)
930937

931938
@with_rw_directory
932939
deftest_git_work_tree_env(self,rw_dir):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp