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,
29
from pack import load_packs
38
def __init__(self, name, ref):
45
ref_locs = ['', 'refs', 'refs/tags', 'refs/heads', 'refs/remotes']
47
def __init__(self, root):
48
controldir = os.path.join(root, ".git")
49
if os.path.exists(os.path.join(controldir, "objects")):
51
self._basedir = controldir
55
self.path = controldir
56
self.tags = [Tag(name, ref) for name, ref in self.get_tags().items()]
63
return os.path.join(self.basedir(), OBJECTDIR)
66
return os.path.join(self.object_dir(), PACKDIR)
69
if self._packs is None:
70
self._packs = list(load_packs(self.pack_dir()))
73
def _get_ref(self, file):
77
if contents.startswith(SYMREF):
78
ref = contents[len(SYMREF):]
82
assert len(contents) == 41, 'Invalid ref'
88
for dir in self.ref_locs:
89
file = os.path.join(self.basedir(), dir, name)
90
if os.path.exists(file):
91
return self._get_ref(file)
95
for root, dirs, files in os.walk(os.path.join(self.basedir(), 'refs', 'tags')):
97
ret[name] = self._get_ref(os.path.join(root, name))
102
for root, dirs, files in os.walk(os.path.join(self.basedir(), 'refs', 'heads')):
104
ret[name] = self._get_ref(os.path.join(root, name))
108
return self.ref('HEAD')
110
def _get_object(self, sha, cls):
111
assert len(sha) == 40, "Incorrect length sha: %s" % str(sha)
114
# Check from object dir
115
path = os.path.join(self.object_dir(), dir, file)
116
if os.path.exists(path):
117
return cls.from_file(path)
119
for pack in self._get_packs():
122
# Should this raise instead?
125
def get_object(self, sha):
126
return self._get_object(sha, ShaFile)
128
def commit(self, sha):
129
return self._get_object(sha, Commit)
131
def get_tree(self, sha):
132
return self._get_object(sha, Tree)
134
def get_blob(self, sha):
135
return self._get_object(sha, Blob)
137
def revision_history(self, head):
138
"""Returns a list of the commits reachable from head.
140
Returns a list of commit objects. the first of which will be the commit
141
of head, then following theat will be the parents.
143
Raises NotCommitError if any no commits are referenced, including if the
144
head parameter isn't the sha of a commit.
146
XXX: work out how to handle merges.
148
# We build the list backwards, as parents are more likely to be older
150
pending_commits = [head]
152
while pending_commits != []:
153
head = pending_commits.pop(0)
154
commit = self.commit(head)
156
raise MissingCommitError(head)
157
if commit in history:
160
for known_commit in history:
161
if known_commit.commit_time() > commit.commit_time():
164
history.insert(i, commit)
165
parents = commit.parents()
166
pending_commits += parents
171
def init_bare(cls, path, mkdir=True):
172
for d in [["objects"],
181
os.mkdir(os.path.join(path, *d))
182
open(os.path.join(path, 'HEAD'), 'w').write("ref: refs/heads/master\n")
183
open(os.path.join(path, 'description'), 'w').write("Unnamed repository")
184
open(os.path.join(path, 'info', 'excludes'), 'w').write("")