1 # repository.py -- For dealing wih git repositories.
2 # Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; version 2
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 from errors import MissingCommitError
22 from objects import (ShaFile,
31 class Repository(object):
33 ref_locs = ['', 'refs', 'refs/tags', 'refs/heads', 'refs/remotes']
35 def __init__(self, root):
36 controldir = os.path.join(root, ".git")
37 if os.path.exists(os.path.join(controldir, "objects")):
39 self._basedir = controldir
48 return os.path.join(self.basedir(), objectdir)
50 def _get_ref(self, file):
54 if contents.startswith(symref):
55 ref = contents[len(symref):]
59 assert len(contents) == 41, 'Invalid ref'
65 for dir in self.ref_locs:
66 file = os.path.join(self.basedir(), dir, name)
67 if os.path.exists(file):
68 return self._get_ref(file)
71 return self.ref('HEAD')
73 def _get_object(self, sha, cls):
74 assert len(sha) == 40, "Incorrect length sha: %s" % str(sha)
77 path = os.path.join(self.object_dir(), dir, file)
78 if not os.path.exists(path):
79 # Should this raise instead?
81 return cls.from_file(path)
83 def get_object(self, sha):
84 return self._get_object(sha, ShaFile)
86 def get_commit(self, sha):
87 return self._get_object(sha, Commit)
89 def get_tree(self, sha):
90 return self._get_object(sha, Tree)
92 def get_blob(self, sha):
93 return self._get_object(sha, Blob)
95 def revision_history(self, head):
96 """Returns a list of the commits reachable from head.
98 Returns a list of commit objects. the first of which will be the commit
99 of head, then following theat will be the parents.
101 Raises NotCommitError if any no commits are referenced, including if the
102 head parameter isn't the sha of a commit.
104 XXX: work out how to handle merges.
106 # We build the list backwards, as parents are more likely to be older
108 pending_commits = [head]
110 while pending_commits != []:
111 head = pending_commits.pop(0)
112 commit = self.get_commit(head)
114 raise MissingCommitError(head)
115 if commit in history:
118 for known_commit in history:
119 if known_commit.commit_time() > commit.commit_time():
122 history.insert(i, commit)
123 parents = commit.parents()
124 pending_commits += parents