108
116
def checkout_metadir(self, stacked=False):
109
117
return format_registry.make_controldir("git")
111
def _get_default_ref(self):
114
119
def _get_selected_ref(self, branch, ref=None):
115
120
if ref is not None and branch is not None:
116
121
raise bzr_errors.BzrError("can't specify both ref and branch")
117
122
if ref is not None:
124
if branch is not None:
125
from .refs import branch_name_to_ref
126
return branch_name_to_ref(branch)
119
127
segment_parameters = getattr(
120
128
self.user_transport, "get_segment_parameters", lambda: {})()
121
129
ref = segment_parameters.get("ref")
123
131
return urlutils.unescape(ref)
124
132
if branch is None and getattr(self, "_get_selected_branch", False):
125
133
branch = self._get_selected_branch()
126
if branch is not None:
127
from .refs import branch_name_to_ref
128
return branch_name_to_ref(branch)
129
return self._get_default_ref()
134
if branch is not None:
135
from .refs import branch_name_to_ref
136
return branch_name_to_ref(branch)
131
139
def get_config(self):
132
140
return GitDirConfig()
145
153
target_transport.ensure_base()
146
154
cloning_format = self.cloning_metadir()
147
155
# Create/update the result branch
148
result = cloning_format.initialize_on_transport(target_transport)
157
result = ControlDir.open_from_transport(target_transport)
158
except bzr_errors.NotBranchError:
159
result = cloning_format.initialize_on_transport(target_transport)
149
160
source_branch = self.open_branch()
150
161
source_repository = self.find_repository()
216
227
target_git_repo.refs[name] = val
217
228
return self.__class__(transport, target_git_repo, format)
230
def _find_commondir(self):
232
commondir = self.control_transport.get_bytes('commondir')
233
except bzr_errors.NoSuchFile:
236
commondir = commondir.rstrip('/.git/')
237
return ControlDir.open_from_transport(get_transport_from_path(commondir))
219
239
def find_repository(self):
220
240
"""Find the repository that should be used.
278
298
from .transportgit import TransportRepo
279
299
gitrepo = TransportRepo(transport, self.bare,
280
300
refs_text=getattr(self, "_refs_text", None))
301
if not gitrepo._controltransport.has('HEAD'):
302
raise bzr_errors.NotBranchError(path=transport.base)
281
303
return LocalGitDir(transport, gitrepo, self)
283
305
def get_format_description(self):
377
398
def _get_symref(self, ref):
378
399
from dulwich.repo import SYMREF
379
refcontents = self._git.refs.read_ref(ref)
380
if refcontents is None: # no such ref
400
ref_chain, unused_sha = self._git.refs.follow(ref)
401
if len(ref_chain) == 1:
382
if refcontents.startswith(SYMREF):
383
return refcontents[len(SYMREF):].rstrip("\n")
386
405
def set_branch_reference(self, target_branch, name=None):
387
if self.control_transport.base != target_branch.controldir.control_transport.base:
388
raise bzr_errors.IncompatibleFormat(target_branch._format, self._format)
389
406
ref = self._get_selected_ref(name)
390
self._git.refs.set_symbolic_ref(ref, target_branch.ref)
407
if self.control_transport.base == target_branch.controldir.control_transport.base:
408
self._git.refs.set_symbolic_ref(ref, target_branch.ref)
411
target_path = target_branch.controldir.control_transport.local_abspath('.')
412
except bzr_errors.NotLocalUrl:
413
raise bzr_errors.IncompatibleFormat(target_branch._format, self._format)
414
# TODO(jelmer): Do some consistency checking across branches..
415
self.control_transport.put_bytes('commondir', target_path.encode('utf-8'))
416
# TODO(jelmer): Urgh, avoid mucking about with internals.
417
self._git._commontransport = target_branch.repository._git._commontransport.clone()
418
self._git.object_store = TransportObjectStore(self._git._commontransport.clone(OBJECTDIR))
419
self._git.refs.transport = self._git._commontransport
420
target_ref_chain, unused_sha = target_branch.controldir._git.refs.follow(target_branch.ref)
421
for target_ref in target_ref_chain:
422
if target_ref == b'HEAD':
426
# Can't create a reference to something that is not a in a repository.
427
raise bzr_errors.IncompatibleFormat(self.set_branch_reference, self)
428
self._git.refs.set_symbolic_ref(ref, target_ref)
392
430
def get_branch_reference(self, name=None):
393
431
ref = self._get_selected_ref(name)
394
432
target_ref = self._get_symref(ref)
395
433
if target_ref is not None:
396
return urlutils.join_segment_parameters(
397
self.user_url.rstrip("/"), {"ref": urllib.quote(target_ref, '')})
434
from .refs import ref_to_branch_name
436
branch_name = ref_to_branch_name(target_ref)
438
params = {'ref': urllib.quote(target_ref, '')}
440
if branch_name != b'':
441
params = {'branch': urllib.quote(branch_name.encode('utf-8'), '')}
445
base_url = urlutils.local_path_to_url(self.control_transport.get_bytes('commondir')).rstrip('/.git/')+'/'
446
except bzr_errors.NoSuchFile:
447
base_url = self.user_url.rstrip('/')
448
return urlutils.join_segment_parameters(base_url, params)
400
451
def find_branch_format(self, name=None):
430
481
raise bzr_errors.IncompatibleFormat(format, self._format)
432
483
def open_branch(self, name=None, unsupported=False, ignore_fallbacks=None,
433
ref=None, possible_transports=None):
484
ref=None, possible_transports=None, nascent_ok=False):
434
485
"""'create' a branch for this dir."""
435
486
repo = self.find_repository()
436
487
from .branch import LocalGitBranch
437
488
ref = self._get_selected_ref(name, ref)
438
ref_chain, sha = self._git.refs.follow(ref)
489
if not nascent_ok and ref not in self._git.refs:
440
490
raise bzr_errors.NotBranchError(self.root_transport.base,
442
return LocalGitBranch(self, repo, ref_chain[-1])
492
ref_chain, unused_sha = self._git.refs.follow(ref)
493
if ref_chain[-1] == b'HEAD':
496
controldir = self._find_commondir()
497
return LocalGitBranch(controldir, repo, ref_chain[-1])
444
499
def destroy_branch(self, name=None):
445
500
refname = self._get_selected_ref(name)
501
if refname == b'HEAD':
502
# HEAD can't be removed
503
raise bzr_errors.UnsupportedOperation(
504
self.destroy_branch, self)
447
506
del self._git.refs[refname]
453
512
raise bzr_errors.UnsupportedOperation(self.destroy_repository, self)
455
514
def destroy_workingtree(self):
456
wt = self.open_workingtree(recommend_upgrade=False)
457
repository = wt.branch.repository
458
empty = repository.revision_tree(_mod_revision.NULL_REVISION)
459
# We ignore the conflicts returned by wt.revert since we're about to
460
# delete the wt metadata anyway, all that should be left here are
461
# detritus. But see bug #634470 about subtree .bzr dirs.
462
conflicts = wt.revert(old_tree=empty)
463
self.destroy_workingtree_metadata()
515
raise bzr_errors.UnsupportedOperation(self.destroy_workingtree, self)
465
517
def destroy_workingtree_metadata(self):
466
self.transport.delete('index')
518
raise bzr_errors.UnsupportedOperation(self.destroy_workingtree_metadata, self)
468
520
def needs_format_conversion(self, format=None):
469
521
return not isinstance(self._format, format.__class__)
503
558
from .workingtree import GitWorkingTree
505
branch = self.open_branch()
506
except bzr_errors.NotBranchError:
509
return GitWorkingTree(self, repo, branch, index)
559
branch = self.open_branch(ref=b'HEAD', nascent_ok=True)
560
return GitWorkingTree(self, repo, branch, index)
510
561
loc = urlutils.unescape_for_display(self.root_transport.base, 'ascii')
511
562
raise bzr_errors.NoWorkingTree(loc)
519
570
def create_branch(self, name=None, repository=None,
520
571
append_revisions_only=None, ref=None):
521
572
refname = self._get_selected_ref(name, ref)
522
from dulwich.protocol import ZERO_SHA
573
if refname != b'HEAD' and refname in self._git.refs:
574
raise bzr_errors.AlreadyBranchError(self.user_url)
575
repo = self.open_repository()
576
from dulwich.objects import ZERO_SHA
523
577
if refname in self._git.refs:
524
raise bzr_errors.AlreadyBranchError(self.user_url)
525
self._git.refs[refname] = ZERO_SHA
526
branch = self.open_branch(name)
578
ref_chain, unused_sha = self._git.refs.follow(self._get_selected_ref(None))
579
if ref_chain[0] == b'HEAD':
580
refname = ref_chain[1]
581
self._git.refs[refname] = ZERO_SHA
582
from .branch import LocalGitBranch
583
branch = LocalGitBranch(self, repo, refname)
527
584
if append_revisions_only:
528
585
branch.set_append_revisions_only(append_revisions_only)