1
# repo.py -- For dealing wih git repositories.
2
# Copyright (C) 2007 James Westby <jw+debian@jameswestby.net>
3
# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
5
# This program is free software; you can redistribute it and/or
6
# modify it under the terms of the GNU General Public License
7
# as published by the Free Software Foundation; version 2
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22
from commit import Commit
23
from errors import MissingCommitError
24
from objects import (ShaFile,
36
def __init__(self, name, ref):
38
self.commit = Commit(ref)
43
ref_locs = ['', 'refs', 'refs/tags', 'refs/heads', 'refs/remotes']
45
def __init__(self, root):
46
controldir = os.path.join(root, ".git")
47
if os.path.exists(os.path.join(controldir, "objects")):
49
self._basedir = controldir
53
self.path = controldir
54
self.tags = [Tag(name, ref) for name, ref in self.get_tags().items()]
60
return os.path.join(self.basedir(), objectdir)
62
def _get_ref(self, file):
66
if contents.startswith(symref):
67
ref = contents[len(symref):]
71
assert len(contents) == 41, 'Invalid ref'
77
for dir in self.ref_locs:
78
file = os.path.join(self.basedir(), dir, name)
79
if os.path.exists(file):
80
return self._get_ref(file)
84
for name in os.listdir(os.path.join(self.basedir(), 'refs', 'tags')):
85
ret[name] = self._get_ref(os.path.join(self.basedir(), 'refs', 'tags', name))
90
for name in os.listdir(os.path.join(self.basedir(), 'refs', 'heads')):
91
ret[name] = self._get_ref(os.path.join(self.basedir(), 'refs', 'heads', name))
95
return self.ref('HEAD')
97
def _get_object(self, sha, cls):
98
assert len(sha) == 40, "Incorrect length sha: %s" % str(sha)
101
path = os.path.join(self.object_dir(), dir, file)
102
if not os.path.exists(path):
103
# Should this raise instead?
105
return cls.from_file(path)
107
def get_object(self, sha):
108
return self._get_object(sha, ShaFile)
110
def commit(self, sha):
111
return self._get_object(sha, Commit)
113
def get_tree(self, sha):
114
return self._get_object(sha, Tree)
116
def get_blob(self, sha):
117
return self._get_object(sha, Blob)
119
def revision_history(self, head):
120
"""Returns a list of the commits reachable from head.
122
Returns a list of commit objects. the first of which will be the commit
123
of head, then following theat will be the parents.
125
Raises NotCommitError if any no commits are referenced, including if the
126
head parameter isn't the sha of a commit.
128
XXX: work out how to handle merges.
130
# We build the list backwards, as parents are more likely to be older
132
pending_commits = [head]
134
while pending_commits != []:
135
head = pending_commits.pop(0)
136
commit = self.commit(head)
138
raise MissingCommitError(head)
139
if commit in history:
142
for known_commit in history:
143
if known_commit.commit_time() > commit.commit_time():
146
history.insert(i, commit)
147
parents = commit.parents()
148
pending_commits += parents
153
def init_bare(cls, path, mkdir=True):
154
for d in [["objects"],
163
os.mkdir(os.path.join(path, *d))
164
open(os.path.join(path, 'HEAD'), 'w').write("ref: refs/heads/master\n")
165
open(os.path.join(path, 'description'), 'w').write("Unnamed repository")
166
open(os.path.join(path, 'info', 'excludes'), 'w').write("")