Skip to content

Commit a5f0343

Browse files
authored
Merge pull request gitpython-developers#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
for ref in refs:
39+
try:
40+
os.remove(osp.join(repo.common_dir, ref.path))
41+
except OSError:
42+
pass
3943
try:
4044
os.remove(osp.join(repo.git_dir, ref.path))
4145
except OSError:

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+
if name in ['HEAD', 'ORIG_HEAD', 'FETCH_HEAD', 'index', 'logs']:
33+
return repo.git_dir
34+
return repo.common_dir
35+
36+
2937
class SymbolicReference(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
def abspath(self):
74-
return join_path_native(self.repo.git_dir, self.path)
82+
return join_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-
return osp.join(repodir, 'packed-refs')
86+
return osp.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
with open(osp.join(repodir, ref_path), 'rt') as fp:
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-
return cls._get_ref_info_helper(repo, repo.git_dir, ref_path)
174-
except ValueError:
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-
return cls._get_ref_info_helper(repo, repodir, ref_path)
176+
return cls._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
if osp.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
if self.path == new_path:
560556
return self
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
if osp.isfile(new_abs_path):
565561
if not force:
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-
for root, dirs, files in os.walk(join_path_native(repo.git_dir, common_path)):
593+
for root, dirs, files in os.walk(join_path_native(repo.common_dir, common_path)):
598594
if 'refs' not in root.split(os.sep): # skip non-refs subfolders
599595
refs_id = [d for d in dirs if d == 'refs']
600596
if refs_id:
@@ -605,7 +601,7 @@ def _iter_items(cls, repo, common_path=None):
605601
if f == '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-
with open(osp.join(self.repo.git_dir, 'FETCH_HEAD'), 'rb') as fp:
656+
with open(osp.join(self.repo.common_dir, 'FETCH_HEAD'), 'rb') as fp:
657657
fetch_head_info = [l.decode(defenc) for l in fp.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
if self._bare:
178185
self._working_tree_dir = None
179186
# END working dir handling
180187

181-
self.working_dir = self._working_tree_dir or self.git_dir
188+
self.working_dir = self._working_tree_dir or self.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
if issubclass(odbt, GitCmdObjectDB):
187194
args.append(self.git)
188195
self.odb = odbt(*args)
@@ -239,6 +246,13 @@ def working_tree_dir(self):
239246
"""
240247
return self._working_tree_dir
241248

249+
@property
250+
def common_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+
return self._common_dir or self.git_dir
255+
242256
@property
243257
def bare(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
if not alts:
582596
if osp.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-
return self._clone(self.git, self.git_dir, path, type(self.odb), progress, **kwargs)
957+
return self._clone(self.git, self.common_dir, path, type(self.odb), progress, **kwargs)
944958

945959
@classmethod
946960
def clone_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
def test_git_work_tree_env(self, rw_dir):
940942
"""Check that we yield to GIT_WORK_TREE"""

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy