Skip to content

Commit a5f0343

Browse files
authored
Merge pull request #654 from vathpela/worktrees
worktrees: make non-packed refs also work correctly.
2 parents fb43244 + d1c40f4 commit a5f0343

File tree

5 files changed

+45
-29
lines changed

5 files changed

+45
-29
lines changed

‎git/refs/remote.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ def delete(cls, repo, *refs, **kwargs):
3636
# are generally ignored in the refs/ folder. We don't though
3737
# and delete remainders manually
3838
forrefinrefs:
39+
try:
40+
os.remove(osp.join(repo.common_dir, ref.path))
41+
exceptOSError:
42+
pass
3943
try:
4044
os.remove(osp.join(repo.git_dir, ref.path))
4145
exceptOSError:

‎git/refs/symbolic.py‎

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@
2626
__all__= ["SymbolicReference"]
2727

2828

29+
def_git_dir(repo, path):
30+
""" Find the git dir that's appropriate for the path"""
31+
name="%s"% (path,)
32+
ifnamein ['HEAD', 'ORIG_HEAD', 'FETCH_HEAD', 'index', 'logs']:
33+
returnrepo.git_dir
34+
returnrepo.common_dir
35+
36+
2937
classSymbolicReference(object):
3038

3139
"""Represents a special case of a reference such that this reference is symbolic.
@@ -71,16 +79,11 @@ def name(self):
7179

7280
@property
7381
defabspath(self):
74-
returnjoin_path_native(self.repo.git_dir, self.path)
82+
returnjoin_path_native(_git_dir(self.repo, self.path), self.path)
7583

7684
@classmethod
7785
def_get_packed_refs_path(cls, repo):
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')
86+
returnosp.join(repo.common_dir, 'packed-refs')
8487

8588
@classmethod
8689
def_iter_packed_refs(cls, repo):
@@ -127,11 +130,12 @@ def dereference_recursive(cls, repo, ref_path):
127130
# END recursive dereferencing
128131

129132
@classmethod
130-
def_get_ref_info_helper(cls, repo, repodir, ref_path):
133+
def_get_ref_info_helper(cls, repo, ref_path):
131134
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
132135
rela_path points to, or None. target_ref_path is the reference we
133136
point to, or None"""
134137
tokens=None
138+
repodir=_git_dir(repo, ref_path)
135139
try:
136140
withopen(osp.join(repodir, ref_path), 'rt') asfp:
137141
value=fp.read().rstrip()
@@ -169,16 +173,7 @@ def _get_ref_info(cls, repo, ref_path):
169173
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
170174
rela_path points to, or None. target_ref_path is the reference we
171175
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)
176+
returncls._get_ref_info_helper(repo, ref_path)
182177

183178
def_get_object(self):
184179
"""
@@ -433,7 +428,7 @@ def delete(cls, repo, path):
433428
or just "myreference", hence 'refs/' is implied.
434429
Alternatively the symbolic reference to be deleted"""
435430
full_ref_path=cls.to_full_path(path)
436-
abs_path=osp.join(repo.git_dir, full_ref_path)
431+
abs_path=osp.join(repo.common_dir, full_ref_path)
437432
ifosp.exists(abs_path):
438433
os.remove(abs_path)
439434
else:
@@ -484,8 +479,9 @@ def _create(cls, repo, path, resolve, reference, force, logmsg=None):
484479
a proper symbolic reference. Otherwise it will be resolved to the
485480
corresponding object and a detached symbolic reference will be created
486481
instead"""
482+
git_dir=_git_dir(repo, path)
487483
full_ref_path=cls.to_full_path(path)
488-
abs_ref_path=osp.join(repo.git_dir, full_ref_path)
484+
abs_ref_path=osp.join(git_dir, full_ref_path)
489485

490486
# figure out target data
491487
target=reference
@@ -559,8 +555,8 @@ def rename(self, new_path, force=False):
559555
ifself.path==new_path:
560556
returnself
561557

562-
new_abs_path=osp.join(self.repo.git_dir, new_path)
563-
cur_abs_path=osp.join(self.repo.git_dir, self.path)
558+
new_abs_path=osp.join(_git_dir(self.repo, new_path), new_path)
559+
cur_abs_path=osp.join(_git_dir(self.repo, self.path), self.path)
564560
ifosp.isfile(new_abs_path):
565561
ifnotforce:
566562
# if they point to the same file, its not an error
@@ -594,7 +590,7 @@ def _iter_items(cls, repo, common_path=None):
594590

595591
# walk loose refs
596592
# Currently we do not follow links
597-
forroot, dirs, filesinos.walk(join_path_native(repo.git_dir, common_path)):
593+
forroot, dirs, filesinos.walk(join_path_native(repo.common_dir, common_path)):
598594
if'refs'notinroot.split(os.sep): # skip non-refs subfolders
599595
refs_id= [dfordindirsifd=='refs']
600596
ifrefs_id:
@@ -605,7 +601,7 @@ def _iter_items(cls, repo, common_path=None):
605601
iff=='packed-refs':
606602
continue
607603
abs_path=to_native_path_linux(join_path(root, f))
608-
rela_paths.add(abs_path.replace(to_native_path_linux(repo.git_dir) +'/', ""))
604+
rela_paths.add(abs_path.replace(to_native_path_linux(repo.common_dir) +'/', ""))
609605
# END for each file in root directory
610606
# END for each directory to walk
611607

‎git/remote.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ def _get_fetch_info_from_stderr(self, proc, progress):
653653
continue
654654

655655
# read head information
656-
withopen(osp.join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') asfp:
656+
withopen(osp.join(self.repo.common_dir, 'FETCH_HEAD'), 'rb') asfp:
657657
fetch_head_info= [l.decode(defenc) forlinfp.readlines()]
658658

659659
l_fil=len(fetch_info_lines)

‎git/repo/base.py‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class Repo(object):
7171
working_dir=None
7272
_working_tree_dir=None
7373
git_dir=None
74+
_common_dir=None
7475

7576
# precompiled regex
7677
re_whitespace=re.compile(r'\s+')
@@ -172,17 +173,23 @@ def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=Fals
172173
# lets not assume the option exists, although it should
173174
pass
174175

176+
try:
177+
common_dir=open(osp.join(self.git_dir, 'commondir'), 'rt').readlines()[0].strip()
178+
self._common_dir=osp.join(self.git_dir, common_dir)
179+
except (OSError, IOError):
180+
self._common_dir=None
181+
175182
# adjust the wd in case we are actually bare - we didn't know that
176183
# in the first place
177184
ifself._bare:
178185
self._working_tree_dir=None
179186
# END working dir handling
180187

181-
self.working_dir=self._working_tree_dirorself.git_dir
188+
self.working_dir=self._working_tree_dirorself.common_dir
182189
self.git=self.GitCommandWrapperType(self.working_dir)
183190

184191
# special handling, in special times
185-
args= [osp.join(self.git_dir, 'objects')]
192+
args= [osp.join(self.common_dir, 'objects')]
186193
ifissubclass(odbt, GitCmdObjectDB):
187194
args.append(self.git)
188195
self.odb=odbt(*args)
@@ -239,6 +246,13 @@ def working_tree_dir(self):
239246
"""
240247
returnself._working_tree_dir
241248

249+
@property
250+
defcommon_dir(self):
251+
""":return: The git dir that holds everything except possibly HEAD,
252+
FETCH_HEAD, ORIG_HEAD, COMMIT_EDITMSG, index, and logs/ .
253+
"""
254+
returnself._common_dirorself.git_dir
255+
242256
@property
243257
defbare(self):
244258
""":return: True if the repository is bare"""
@@ -577,7 +591,7 @@ def _set_alternates(self, alts):
577591
:note:
578592
The method does not check for the existence of the paths in alts
579593
as the caller is responsible."""
580-
alternates_path=osp.join(self.git_dir, 'objects', 'info', 'alternates')
594+
alternates_path=osp.join(self.common_dir, 'objects', 'info', 'alternates')
581595
ifnotalts:
582596
ifosp.isfile(alternates_path):
583597
os.remove(alternates_path)
@@ -940,7 +954,7 @@ def clone(self, path, progress=None, **kwargs):
940954
* All remaining keyword arguments are given to the git-clone command
941955
942956
:return: ``git.Repo`` (the newly cloned repo)"""
943-
returnself._clone(self.git, self.git_dir, path, type(self.odb), progress, **kwargs)
957+
returnself._clone(self.git, self.common_dir, path, type(self.odb), progress, **kwargs)
944958

945959
@classmethod
946960
defclone_from(cls, url, to_path, progress=None, env=None, **kwargs):

‎git/test/test_repo.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,8 @@ def test_git_work_tree_dotgit(self, rw_dir):
935935
commit=repo.head.commit
936936
self.assertIsInstance(commit, Object)
937937

938+
self.assertIsInstance(repo.heads['aaaaaaaa'], Head)
939+
938940
@with_rw_directory
939941
deftest_git_work_tree_env(self, rw_dir):
940942
"""Check that we yield to GIT_WORK_TREE"""

0 commit comments

Comments
(0)