diff options
-rw-r--r-- | lib/git/refs.py | 77 | ||||
-rw-r--r-- | test/git/test_refs.py | 10 |
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") - |