105
75
def cloning_metadir(self, stacked=False):
106
76
return format_registry.make_bzrdir("default")
108
def _branch_name_to_ref(self, name):
109
raise NotImplementedError(self._branch_name_to_ref)
111
if bzrlib_version >= (2, 2):
112
def open_branch(self, name=None, unsupported=False,
113
ignore_fallbacks=None):
114
return self._open_branch(name=name,
115
ignore_fallbacks=ignore_fallbacks, unsupported=unsupported)
117
def open_branch(self, ignore_fallbacks=None, unsupported=False):
118
return self._open_branch(name=None,
119
ignore_fallbacks=ignore_fallbacks, unsupported=unsupported)
78
def checkout_metadir(self, stacked=False):
79
return format_registry.make_bzrdir("default")
81
def _get_default_ref(self):
84
def _get_selected_ref(self, branch, ref=None):
85
if ref is not None and branch is not None:
86
raise bzr_errors.BzrError("can't specify both ref and branch")
89
segment_parameters = getattr(
90
self.user_transport, "get_segment_parameters", lambda: {})()
91
ref = segment_parameters.get("ref")
93
return urlutils.unescape(ref)
94
if branch is None and getattr(self, "_get_selected_branch", False):
95
branch = self._get_selected_branch()
96
if branch is not None:
97
from bzrlib.plugins.git.refs import branch_name_to_ref
98
return branch_name_to_ref(branch)
99
return self._get_default_ref()
121
101
def get_config(self):
122
102
return GitDirConfig()
104
def _available_backup_name(self, base):
105
return osutils.available_backup_name(base, self.root_transport.has)
107
def sprout(self, url, revision_id=None, force_new_repo=False,
108
recurse='down', possible_transports=None,
109
accelerator_tree=None, hardlink=False, stacked=False,
110
source_branch=None, create_tree_if_local=True):
111
from bzrlib.repository import InterRepository
112
from bzrlib.transport.local import LocalTransport
113
from bzrlib.transport import get_transport
114
target_transport = get_transport(url, possible_transports)
115
target_transport.ensure_base()
116
cloning_format = self.cloning_metadir()
117
# Create/update the result branch
118
result = cloning_format.initialize_on_transport(target_transport)
119
source_branch = self.open_branch()
120
source_repository = self.find_repository()
122
result_repo = result.find_repository()
123
except bzr_errors.NoRepositoryPresent:
124
result_repo = result.create_repository()
125
target_is_empty = True
127
target_is_empty = None # Unknown
129
raise bzr_errors.IncompatibleRepositories(source_repository, result_repo)
130
interrepo = InterRepository.get(source_repository, result_repo)
132
if revision_id is not None:
133
determine_wants = interrepo.get_determine_wants_revids(
134
[revision_id], include_tags=False)
136
determine_wants = interrepo.determine_wants_all
137
interrepo.fetch_objects(determine_wants=determine_wants,
138
mapping=source_branch.mapping)
139
result_branch = source_branch.sprout(result,
140
revision_id=revision_id, repository=result_repo)
141
if (create_tree_if_local
142
and isinstance(target_transport, LocalTransport)
143
and (result_repo is None or result_repo.make_working_trees())):
144
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
145
hardlink=hardlink, from_branch=result_branch)
148
if wt.path2id('') is None:
150
wt.set_root_id(self.open_workingtree.get_root_id())
151
except bzr_errors.NoWorkingTree:
157
def clone_on_transport(self, transport, revision_id=None,
158
force_new_repo=False, preserve_stacking=False, stacked_on=None,
159
create_prefix=False, use_existing_dir=True, no_tree=False):
160
"""See ControlDir.clone_on_transport."""
161
from bzrlib.repository import InterRepository
162
from bzrlib.plugins.git.mapping import default_mapping
164
format = BareLocalGitControlDirFormat()
166
format = LocalGitControlDirFormat()
167
(target_repo, target_controldir, stacking, repo_policy) = format.initialize_on_transport_ex(transport, use_existing_dir=use_existing_dir, create_prefix=create_prefix, force_new_repo=force_new_repo)
168
target_git_repo = target_repo._git
169
source_repo = self.open_repository()
170
source_git_repo = source_repo._git
171
interrepo = InterRepository.get(source_repo, target_repo)
172
if revision_id is not None:
173
determine_wants = interrepo.get_determine_wants_revids([revision_id], include_tags=True)
175
determine_wants = interrepo.determine_wants_all
176
(pack_hint, _, refs) = interrepo.fetch_objects(determine_wants,
177
mapping=default_mapping)
178
for name, val in refs.iteritems():
179
target_git_repo.refs[name] = val
180
return self.__class__(transport, target_git_repo, format)
182
def find_repository(self):
183
"""Find the repository that should be used.
185
This does not require a branch as we use it to find the repo for
186
new branches as well as to hook existing branches up to their
189
return self.open_repository()
191
def get_refs_container(self):
192
"""Retrieve the refs container.
194
raise NotImplementedError(self.get_refs_container)
197
class LocalGitControlDirFormat(GitControlDirFormat):
198
"""The .git directory control format."""
203
def _known_formats(self):
204
return set([LocalGitControlDirFormat()])
207
def repository_format(self):
208
from bzrlib.plugins.git.repository import GitRepositoryFormat
209
return GitRepositoryFormat()
211
def get_branch_format(self):
212
from bzrlib.plugins.git.branch import GitBranchFormat
213
return GitBranchFormat()
215
def open(self, transport, _found=None):
216
"""Open this directory.
219
from bzrlib.plugins.git.transportgit import TransportRepo
220
gitrepo = TransportRepo(transport, self.bare,
221
refs_text=getattr(self, "_refs_text", None))
222
return LocalGitDir(transport, gitrepo, self)
224
def get_format_description(self):
225
return "Local Git Repository"
227
def initialize_on_transport(self, transport):
228
from bzrlib.plugins.git.transportgit import TransportRepo
229
repo = TransportRepo.init(transport, bare=self.bare)
230
del repo.refs["HEAD"]
231
return self.open(transport)
233
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
234
create_prefix=False, force_new_repo=False, stacked_on=None,
235
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
236
shared_repo=False, vfs_only=False):
237
def make_directory(transport):
240
def redirected(transport, e, redirection_notice):
241
trace.note(redirection_notice)
242
return transport._redirected_to(e.source, e.target)
244
transport = do_catching_redirections(make_directory, transport,
246
except bzr_errors.FileExists:
247
if not use_existing_dir:
249
except bzr_errors.NoSuchFile:
250
if not create_prefix:
252
transport.create_prefix()
253
controldir = self.initialize_on_transport(transport)
254
repository = controldir.open_repository()
255
repository.lock_write()
256
return (repository, controldir, False, CreateRepository(controldir))
258
def is_supported(self):
261
def supports_transport(self, transport):
263
external_url = transport.external_url()
264
except bzr_errors.InProcessTransport:
265
raise bzr_errors.NotBranchError(path=transport.base)
266
return (external_url.startswith("http:") or
267
external_url.startswith("https:") or
268
external_url.startswith("file:"))
271
class BareLocalGitControlDirFormat(LocalGitControlDirFormat):
274
supports_workingtrees = False
276
def get_format_description(self):
277
return "Local Git Repository (bare)"
125
280
class LocalGitDir(GitDir):
126
281
"""An adapter to the '.git' dir used by git."""
148
307
self.transport = transport
150
309
self.transport = transport.clone('.git')
151
self._lockfiles = lockfiles
152
310
self._mode_check_done = None
154
def _branch_name_to_ref(self, name):
155
from bzrlib.plugins.git.refs import branch_name_to_ref
156
ref = branch_name_to_ref(name, None)
158
from dulwich.repo import SYMREF
159
refcontents = self._git.refs.read_ref(ref)
160
if refcontents.startswith(SYMREF):
161
ref = refcontents[len(SYMREF):]
164
312
def is_control_filename(self, filename):
165
return filename == '.git' or filename.startswith('.git/')
313
return (filename == '.git' or filename.startswith('.git/'))
315
def _get_symref(self, ref):
316
from dulwich.repo import SYMREF
317
refcontents = self._git.refs.read_ref(ref)
318
if refcontents is None: # no such ref
320
if refcontents.startswith(SYMREF):
321
return refcontents[len(SYMREF):].rstrip("\n")
324
def set_branch_reference(self, target, name=None):
325
if self.control_transport.base != target.bzrdir.control_transport.base:
326
raise bzr_errors.IncompatibleFormat(target._format, self._format)
327
ref = self._get_selected_ref(name)
328
self._git.refs.set_symbolic_ref(ref, target.ref)
330
def get_branch_reference(self, name=None):
331
ref = self._get_selected_ref(name)
332
target_ref = self._get_symref(ref)
333
if target_ref is not None:
334
return urlutils.join_segment_parameters(
335
self.user_url.rstrip("/"), {"ref": urllib.quote(target_ref, '')})
338
def find_branch_format(self, name=None):
339
from bzrlib.plugins.git.branch import (
341
GitSymrefBranchFormat,
343
ref = self._get_selected_ref(name)
344
if self._get_symref(ref) is not None:
345
return GitSymrefBranchFormat()
347
return GitBranchFormat()
167
349
def get_branch_transport(self, branch_format, name=None):
168
350
if branch_format is None:
185
367
return self.transport
186
368
raise bzr_errors.IncompatibleFormat(format, self._format)
188
def _open_branch(self, name=None, ignore_fallbacks=None, unsupported=False):
370
def open_branch(self, name=None, unsupported=False, ignore_fallbacks=None,
371
ref=None, possible_transports=None):
189
372
"""'create' a branch for this dir."""
190
373
repo = self.open_repository()
191
374
from bzrlib.plugins.git.branch import LocalGitBranch
192
return LocalGitBranch(self, repo, self._branch_name_to_ref(name),
375
ref = self._get_selected_ref(name, ref)
376
ref, sha = self._git.refs._follow(ref)
377
if not ref in self._git.refs:
378
raise bzr_errors.NotBranchError(self.root_transport.base,
380
return LocalGitBranch(self, repo, ref)
195
382
def destroy_branch(self, name=None):
196
refname = self._branch_name_to_ref(name)
197
if not refname in self._git.refs:
383
refname = self._get_selected_ref(name)
385
del self._git.refs[refname]
198
387
raise bzr_errors.NotBranchError(self.root_transport.base,
200
del self._git.refs[refname]
202
390
def destroy_repository(self):
203
391
raise bzr_errors.UnsupportedOperation(self.destroy_repository, self)
205
393
def destroy_workingtree(self):
206
raise bzr_errors.UnsupportedOperation(self.destroy_workingtree, self)
394
wt = self.open_workingtree(recommend_upgrade=False)
395
repository = wt.branch.repository
396
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
397
# We ignore the conflicts returned by wt.revert since we're about to
398
# delete the wt metadata anyway, all that should be left here are
399
# detritus. But see bug #634470 about subtree .bzr dirs.
400
conflicts = wt.revert(old_tree=empty)
401
self.destroy_workingtree_metadata()
403
def destroy_workingtree_metadata(self):
404
self.transport.delete('index')
208
406
def needs_format_conversion(self, format=None):
209
407
return not isinstance(self._format, format.__class__)
211
409
def list_branches(self):
213
for name in self._git.get_refs():
214
if name.startswith("refs/heads/"):
215
ret.append(self.open_branch(name=name))
410
return self.get_branches().values()
412
def get_branches(self):
413
from bzrlib.plugins.git.refs import ref_to_branch_name
415
for ref in self._git.refs.keys():
417
branch_name = ref_to_branch_name(ref)
420
except UnicodeDecodeError:
421
trace.warning("Ignoring branch %r with unicode error ref", ref)
423
ret[branch_name] = self.open_branch(ref=ref)
218
def open_repository(self, shared=False):
426
def open_repository(self):
219
427
"""'open' a repository for this dir."""
220
return self._gitrepository_class(self, self._lockfiles)
428
return self._gitrepository_class(self)
222
def open_workingtree(self, recommend_upgrade=True):
430
def open_workingtree(self, recommend_upgrade=True, unsupported=False):
223
431
if not self._git.bare:
224
432
from dulwich.errors import NoIndexPresent
225
433
repo = self.open_repository()
239
447
raise bzr_errors.NoWorkingTree(loc)
241
449
def create_repository(self, shared=False):
450
from bzrlib.plugins.git.repository import GitRepositoryFormat
452
raise bzr_errors.IncompatibleFormat(GitRepositoryFormat(), self._format)
242
453
return self.open_repository()
244
def create_branch(self, name=None):
245
refname = self._branch_name_to_ref(name)
455
def create_branch(self, name=None, repository=None,
456
append_revisions_only=None, ref=None):
457
refname = self._get_selected_ref(name, ref)
246
458
from dulwich.protocol import ZERO_SHA
247
self._git.refs[refname or "HEAD"] = ZERO_SHA
248
return self.open_branch(name)
459
if refname in self._git.refs:
460
raise bzr_errors.AlreadyBranchError(self.user_url)
461
self._git.refs[refname] = ZERO_SHA
462
branch = self.open_branch(name)
463
if append_revisions_only:
464
branch.set_append_revisions_only(append_revisions_only)
250
467
def backup_bzrdir(self):
468
if not self._git.bare:
252
469
self.root_transport.copy_tree(".git", ".git.backup")
253
470
return (self.root_transport.abspath(".git"),
254
471
self.root_transport.abspath(".git.backup"))
256
raise bzr_errors.BzrError("Unable to backup bare repositories")
473
basename = urlutils.basename(self.root_transport.base)
474
parent = self.root_transport.clone('..')
475
parent.copy_tree(basename, basename + ".backup")
258
477
def create_workingtree(self, revision_id=None, from_branch=None,
259
478
accelerator_tree=None, hardlink=False):
260
479
if self._git.bare:
261
raise bzr_errors.BzrError("Can't create working tree in a bare repo")
480
raise bzr_errors.UnsupportedOperation(self.create_workingtree, self)
262
481
from dulwich.index import write_index
263
482
from dulwich.pack import SHA1Writer
264
483
f = open(self.transport.local_abspath("index"), 'w+')