summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/git/refs.py77
-rw-r--r--test/git/test_refs.py10
2 files changed, 55 insertions, 32 deletions
diff --git a/lib/git/refs.py b/lib/git/refs.py
index dc92fa97..338d1c36 100644
--- a/lib/git/refs.py
+++ b/lib/git/refs.py
@@ -52,6 +52,39 @@ class SymbolicReference(object):
def _get_path(self):
return join_path_native(self.repo.path, self.path)
+ @classmethod
+ def _iter_packed_refs(cls, repo):
+ """Returns an iterator yielding pairs of sha1/path pairs for the corresponding
+ refs.
+ NOTE: The packed refs file will be kept open as long as we iterate"""
+ try:
+ fp = open(os.path.join(repo.path, 'packed-refs'), 'r')
+ for line in fp:
+ line = line.strip()
+ if not line:
+ continue
+ if line.startswith('#'):
+ if line.startswith('# pack-refs with:') and not line.endswith('peeled'):
+ raise TypeError("PackingType of packed-Refs not understood: %r" % line)
+ # END abort if we do not understand the packing scheme
+ continue
+ # END parse comment
+
+ # skip dereferenced tag object entries - previous line was actual
+ # tag reference for it
+ if line[0] == '^':
+ continue
+
+ yield tuple(line.split(' ', 1))
+ # END for each line
+ except (OSError,IOError):
+ raise StopIteration
+ # END no packed-refs file handling
+ # NOTE: Had try-finally block around here to close the fp,
+ # but some python version woudn't allow yields within that.
+ # I believe files are closing themselves on destruction, so it is
+ # alright.
+
def _get_commit(self):
"""
Returns:
@@ -59,10 +92,22 @@ class SymbolicReference(object):
SymbolicReferences
"""
# we partially reimplement it to prevent unnecessary file access
- fp = open(self._get_path(), 'r')
- value = fp.read().rstrip()
- fp.close()
- tokens = value.split(" ")
+ tokens = None
+ try:
+ fp = open(self._get_path(), 'r')
+ value = fp.read().rstrip()
+ fp.close()
+ tokens = value.split(" ")
+ except (OSError,IOError):
+ # Probably we are just packed, find our entry in the packed refs file
+ # NOTE: We are not a symbolic ref if we are in a packed file, as these
+ # are excluded explictly
+ for sha, path in self._iter_packed_refs(self.repo):
+ if path != self.path: continue
+ tokens = (sha, path)
+ break
+ # END for each packed ref
+ # END handle packed refs
# it is a detached reference
if self.repo.re_hexsha_only.match(tokens[0]):
@@ -282,26 +327,10 @@ class Reference(SymbolicReference, LazyMixin, Iterable):
# END for each directory to walk
# read packed refs
- packed_refs_path = join_path_native(repo.path, 'packed-refs')
- if os.path.isfile(packed_refs_path):
- fp = open(packed_refs_path, 'r')
- try:
- for line in fp.readlines():
- if line.startswith('#'):
- continue
- # 439689865b9c6e2a0dad61db22a0c9855bacf597 refs/heads/hello
- line = line.rstrip()
- first_space = line.find(' ')
- if first_space == -1:
- continue
-
- rela_path = line[first_space+1:]
- if rela_path.startswith(common_path):
- rela_paths.add(rela_path)
- # END relative path matches common path
- # END for each line in packed-refs
- finally:
- fp.close()
+ for sha, rela_path in cls._iter_packed_refs(repo):
+ if rela_path.startswith(common_path):
+ rela_paths.add(rela_path)
+ # END relative path matches common path
# END packed refs reading
# return paths in sorted order
diff --git a/test/git/test_refs.py b/test/git/test_refs.py
index 1eceb162..606346cf 100644
--- a/test/git/test_refs.py
+++ b/test/git/test_refs.py
@@ -64,7 +64,7 @@ class TestRefs(TestBase):
types_found = set()
for ref in self.rorepo.refs:
types_found.add(type(ref))
- assert len(types_found) == 4
+ assert len(types_found) == 3
@with_rw_repo('0.1.6')
def test_head_reset(self, rw_repo):
@@ -192,7 +192,7 @@ class TestRefs(TestBase):
# setting a non-commit as commit fails, but succeeds as object
head_tree = head.commit.tree
- self.failUnlessRaises(GitCommandError, setattr, head, 'commit', head_tree)
+ self.failUnlessRaises(ValueError, setattr, head, 'commit', head_tree)
assert head.commit == old_commit # and the ref did not change
self.failUnlessRaises(GitCommandError, setattr, head, 'object', head_tree)
@@ -255,9 +255,3 @@ class TestRefs(TestBase):
assert active_branch in heads
assert rw_repo.tags
- # NOTE: It appears git-cat-file cannot resolve refs which are packed !
- # At least it fails here for some reason
- # Couldn't reproduce the bug in a simple example though ... lets see.
- self.failUnlessRaises(ValueError, getattr, new_head, 'commit')
- self.failUnlessRaises(ValueError, getattr, symref, "commit")
-