Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fa98250

Browse files
committed
SymbolicReference is now the base for all references, allowing them to appear litereally anywhere. A 'default' reference is nothing more than a detached symbolic reference.
Added method iterate the packed refs file
1 parent 0d638bf commit fa98250

File tree

2 files changed

+55
-32
lines changed

2 files changed

+55
-32
lines changed

lib/git/refs.py

Lines changed: 53 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,62 @@ def name(self):
5252
def _get_path(self):
5353
return join_path_native(self.repo.path, self.path)
5454

55+
@classmethod
56+
def _iter_packed_refs(cls, repo):
57+
"""Returns an iterator yielding pairs of sha1/path pairs for the corresponding
58+
refs.
59+
NOTE: The packed refs file will be kept open as long as we iterate"""
60+
try:
61+
fp = open(os.path.join(repo.path, 'packed-refs'), 'r')
62+
for line in fp:
63+
line = line.strip()
64+
if not line:
65+
continue
66+
if line.startswith('#'):
67+
if line.startswith('# pack-refs with:') and not line.endswith('peeled'):
68+
raise TypeError("PackingType of packed-Refs not understood: %r" % line)
69+
# END abort if we do not understand the packing scheme
70+
continue
71+
# END parse comment
72+
73+
# skip dereferenced tag object entries - previous line was actual
74+
# tag reference for it
75+
if line[0] == '^':
76+
continue
77+
78+
yield tuple(line.split(' ', 1))
79+
# END for each line
80+
except (OSError,IOError):
81+
raise StopIteration
82+
# END no packed-refs file handling
83+
# NOTE: Had try-finally block around here to close the fp,
84+
# but some python version woudn't allow yields within that.
85+
# I believe files are closing themselves on destruction, so it is
86+
# alright.
87+
5588
def _get_commit(self):
5689
"""
5790
Returns:
5891
Commit object we point to, works for detached and non-detached
5992
SymbolicReferences
6093
"""
6194
# we partially reimplement it to prevent unnecessary file access
62-
fp = open(self._get_path(), 'r')
63-
value = fp.read().rstrip()
64-
fp.close()
65-
tokens = value.split(" ")
95+
tokens = None
96+
try:
97+
fp = open(self._get_path(), 'r')
98+
value = fp.read().rstrip()
99+
fp.close()
100+
tokens = value.split(" ")
101+
except (OSError,IOError):
102+
# Probably we are just packed, find our entry in the packed refs file
103+
# NOTE: We are not a symbolic ref if we are in a packed file, as these
104+
# are excluded explictly
105+
for sha, path in self._iter_packed_refs(self.repo):
106+
if path != self.path: continue
107+
tokens = (sha, path)
108+
break
109+
# END for each packed ref
110+
# END handle packed refs
66111

67112
# it is a detached reference
68113
if self.repo.re_hexsha_only.match(tokens[0]):
@@ -282,26 +327,10 @@ def iter_items(cls, repo, common_path = None, **kwargs):
282327
# END for each directory to walk
283328

284329
# read packed refs
285-
packed_refs_path = join_path_native(repo.path, 'packed-refs')
286-
if os.path.isfile(packed_refs_path):
287-
fp = open(packed_refs_path, 'r')
288-
try:
289-
for line in fp.readlines():
290-
if line.startswith('#'):
291-
continue
292-
# 439689865b9c6e2a0dad61db22a0c9855bacf597 refs/heads/hello
293-
line = line.rstrip()
294-
first_space = line.find(' ')
295-
if first_space == -1:
296-
continue
297-
298-
rela_path = line[first_space+1:]
299-
if rela_path.startswith(common_path):
300-
rela_paths.add(rela_path)
301-
# END relative path matches common path
302-
# END for each line in packed-refs
303-
finally:
304-
fp.close()
330+
for sha, rela_path in cls._iter_packed_refs(repo):
331+
if rela_path.startswith(common_path):
332+
rela_paths.add(rela_path)
333+
# END relative path matches common path
305334
# END packed refs reading
306335

307336
# return paths in sorted order

test/git/test_refs.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def test_refs(self):
6464
types_found = set()
6565
for ref in self.rorepo.refs:
6666
types_found.add(type(ref))
67-
assert len(types_found) == 4
67+
assert len(types_found) == 3
6868

6969
@with_rw_repo('0.1.6')
7070
def test_head_reset(self, rw_repo):
@@ -192,7 +192,7 @@ def test_head_reset(self, rw_repo):
192192

193193
# setting a non-commit as commit fails, but succeeds as object
194194
head_tree = head.commit.tree
195-
self.failUnlessRaises(GitCommandError, setattr, head, 'commit', head_tree)
195+
self.failUnlessRaises(ValueError, setattr, head, 'commit', head_tree)
196196
assert head.commit == old_commit # and the ref did not change
197197
self.failUnlessRaises(GitCommandError, setattr, head, 'object', head_tree)
198198

@@ -255,9 +255,3 @@ def test_head_reset(self, rw_repo):
255255
assert active_branch in heads
256256
assert rw_repo.tags
257257

258-
# NOTE: It appears git-cat-file cannot resolve refs which are packed !
259-
# At least it fails here for some reason
260-
# Couldn't reproduce the bug in a simple example though ... lets see.
261-
self.failUnlessRaises(ValueError, getattr, new_head, 'commit')
262-
self.failUnlessRaises(ValueError, getattr, symref, "commit")
263-

0 commit comments

Comments
 (0)