diff --git a/rhodecode/lib/vcs/backends/git/changeset.py b/rhodecode/lib/vcs/backends/git/changeset.py --- a/rhodecode/lib/vcs/backends/git/changeset.py +++ b/rhodecode/lib/vcs/backends/git/changeset.py @@ -10,7 +10,8 @@ from rhodecode.lib.vcs.exceptions import from rhodecode.lib.vcs.exceptions import ChangesetDoesNotExistError from rhodecode.lib.vcs.exceptions import ImproperArchiveTypeError from rhodecode.lib.vcs.backends.base import BaseChangeset -from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, RemovedFileNode +from rhodecode.lib.vcs.nodes import FileNode, DirNode, NodeKind, RootNode, \ + RemovedFileNode, SubModuleNode from rhodecode.lib.vcs.utils import safe_unicode from rhodecode.lib.vcs.utils import date_fromtimestamp from rhodecode.lib.vcs.utils.lazy import LazyProperty @@ -66,26 +67,12 @@ class GitChangeset(BaseChangeset): @LazyProperty def branch(self): - # TODO: Cache as we walk (id <-> branch name mapping) - refs = self.repository._repo.get_refs() - heads = {} - for key, val in refs.items(): - for ref_key in ['refs/heads/', 'refs/remotes/origin/']: - if key.startswith(ref_key): - n = key[len(ref_key):] - if n not in ['HEAD']: - heads[n] = val + + heads = self.repository._heads(reverse=False) - for name, id in heads.iteritems(): - walker = self.repository._repo.object_store.get_graph_walker([id]) - while True: - id_ = walker.next() - if not id_: - break - if id_ == self.id: - return safe_unicode(name) - raise ChangesetError("This should not happen... Have you manually " - "change id of the changeset?") + ref = heads.get(self.raw_id) + if ref: + return safe_unicode(ref) def _fix_path(self, path): """ @@ -144,7 +131,6 @@ class GitChangeset(BaseChangeset): name = item self._paths[name] = id self._stat_modes[name] = stat - if not path in self._paths: raise NodeDoesNotExistError("There is no file nor directory " "at the given path %r at revision %r" @@ -344,7 +330,13 @@ class GitChangeset(BaseChangeset): tree = self.repository._repo[id] dirnodes = [] filenodes = [] + als = self.repository.alias for name, stat, id in tree.iteritems(): + if objects.S_ISGITLINK(stat): + dirnodes.append(SubModuleNode(name, url=None, changeset=id, + alias=als)) + continue + obj = self.repository._repo.get_object(id) if path != '': obj_path = '/'.join((path, name)) @@ -372,24 +364,31 @@ class GitChangeset(BaseChangeset): path = self._fix_path(path) if not path in self.nodes: try: - id = self._get_id_for_path(path) + id_ = self._get_id_for_path(path) except ChangesetError: raise NodeDoesNotExistError("Cannot find one of parents' " "directories for a given path: %s" % path) - obj = self.repository._repo.get_object(id) - if isinstance(obj, objects.Tree): - if path == '': - node = RootNode(changeset=self) + + als = self.repository.alias + _GL = lambda m: m and objects.S_ISGITLINK(m) + if _GL(self._stat_modes.get(path)): + node = SubModuleNode(path, url=None, changeset=id_, alias=als) + else: + obj = self.repository._repo.get_object(id_) + + if isinstance(obj, objects.Tree): + if path == '': + node = RootNode(changeset=self) + else: + node = DirNode(path, changeset=self) + node._tree = obj + elif isinstance(obj, objects.Blob): + node = FileNode(path, changeset=self) + node._blob = obj else: - node = DirNode(path, changeset=self) - node._tree = obj - elif isinstance(obj, objects.Blob): - node = FileNode(path, changeset=self) - node._blob = obj - else: - raise NodeDoesNotExistError("There is no file nor directory " - "at the given path %r at revision %r" - % (path, self.short_id)) + raise NodeDoesNotExistError("There is no file nor directory " + "at the given path %r at revision %r" + % (path, self.short_id)) # cache node self.nodes[path] = node return self.nodes[path] @@ -406,7 +405,7 @@ class GitChangeset(BaseChangeset): def _diff_name_status(self): output = [] for parent in self.parents: - cmd = 'diff --name-status %s %s' % (parent.raw_id, self.raw_id) + cmd = 'diff --name-status %s %s --encoding=utf8' % (parent.raw_id, self.raw_id) so, se = self.repository.run_git_command(cmd) output.append(so.strip()) return '\n'.join(output) @@ -422,13 +421,15 @@ class GitChangeset(BaseChangeset): for line in self._diff_name_status.splitlines(): if not line: continue + if line.startswith(char): - splitted = line.split(char,1) + splitted = line.split(char, 1) if not len(splitted) == 2: raise VCSError("Couldn't parse diff result:\n%s\n\n and " "particularly that line: %s" % (self._diff_name_status, line)) - paths.add(splitted[1].strip()) + _path = splitted[1].strip() + paths.add(_path) return sorted(paths) @LazyProperty