179
184
determine_wants = interrepo.determine_wants_all
180
185
interrepo.fetch_objects(determine_wants=determine_wants,
181
mapping=source_branch.mapping)
182
result_branch = source_branch.sprout(
183
result, revision_id=revision_id, repository=result_repo)
184
if (create_tree_if_local and
185
result.open_branch(name="").name == result_branch.name and
186
isinstance(target_transport, LocalTransport) and
187
(result_repo is None or result_repo.make_working_trees())):
188
wt = result.create_workingtree(
189
accelerator_tree=accelerator_tree,
186
mapping=source_branch.mapping)
187
result_branch = source_branch.sprout(result,
188
revision_id=revision_id, repository=result_repo)
189
if (create_tree_if_local
190
and isinstance(target_transport, LocalTransport)
191
and (result_repo is None or result_repo.make_working_trees())):
192
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
190
193
hardlink=hardlink, from_branch=result_branch)
193
if recurse == 'down':
194
with contextlib.ExitStack() as stack:
197
basis = wt.basis_tree()
198
elif result_branch is not None:
199
basis = result_branch.basis_tree()
200
elif source_branch is not None:
201
basis = source_branch.basis_tree()
202
if basis is not None:
203
stack.enter_context(basis.lock_read())
204
subtrees = basis.iter_references()
207
for path in subtrees:
208
target = urlutils.join(url, urlutils.escape(path))
209
sublocation = wt.reference_parent(
210
path, possible_transports=possible_transports)
211
if sublocation is None:
213
'Ignoring nested tree %s, parent location unknown.',
216
sublocation.controldir.sprout(
217
target, basis.get_reference_revision(path),
218
force_new_repo=force_new_repo, recurse=recurse,
220
if getattr(result_repo, '_git', None):
221
# Don't leak resources:
222
# TODO(jelmer): This shouldn't be git-specific, and possibly
223
# just use read locks.
224
result_repo._git.object_store.close()
227
196
def clone_on_transport(self, transport, revision_id=None,
228
force_new_repo=False, preserve_stacking=False,
229
stacked_on=None, create_prefix=False,
230
use_existing_dir=True, no_tree=False,
197
force_new_repo=False, preserve_stacking=False, stacked_on=None,
198
create_prefix=False, use_existing_dir=True, no_tree=False):
232
199
"""See ControlDir.clone_on_transport."""
233
200
from ..repository import InterRepository
234
201
from .mapping import default_mapping
235
from ..transport.local import LocalTransport
236
202
if stacked_on is not None:
237
raise _mod_branch.UnstackableBranchFormat(
238
self._format, self.user_url)
203
raise _mod_branch.UnstackableBranchFormat(self._format, self.user_url)
240
205
format = BareLocalGitControlDirFormat()
242
207
format = LocalGitControlDirFormat()
243
208
(target_repo, target_controldir, stacking,
244
repo_policy) = format.initialize_on_transport_ex(
245
transport, use_existing_dir=use_existing_dir,
246
create_prefix=create_prefix,
247
force_new_repo=force_new_repo)
209
repo_policy) = format.initialize_on_transport_ex(
210
transport, use_existing_dir=use_existing_dir,
211
create_prefix=create_prefix,
212
force_new_repo=force_new_repo)
248
213
target_repo = target_controldir.find_repository()
249
214
target_git_repo = target_repo._git
250
215
source_repo = self.find_repository()
216
source_git_repo = source_repo._git
251
217
interrepo = InterRepository.get(source_repo, target_repo)
252
218
if revision_id is not None:
253
determine_wants = interrepo.get_determine_wants_revids(
254
[revision_id], include_tags=True, tag_selector=tag_selector)
219
determine_wants = interrepo.get_determine_wants_revids([revision_id], include_tags=True)
256
221
determine_wants = interrepo.determine_wants_all
257
222
(pack_hint, _, refs) = interrepo.fetch_objects(determine_wants,
258
mapping=default_mapping)
259
for name, val in refs.items():
223
mapping=default_mapping)
224
for name, val in refs.iteritems():
260
225
target_git_repo.refs[name] = val
261
result_dir = LocalGitDir(transport, target_git_repo, format)
226
result_dir = self.__class__(transport, target_git_repo, format)
262
227
if revision_id is not None:
263
228
result_dir.open_branch().set_last_revision(revision_id)
264
if not no_tree and isinstance(result_dir.root_transport, LocalTransport):
230
# Cheaper to check if the target is not local, than to try making
232
result_dir.root_transport.local_abspath('.')
265
233
if result_dir.open_repository().make_working_trees():
267
local_wt = self.open_workingtree()
268
except brz_errors.NoWorkingTree:
270
except brz_errors.NotLocalUrl:
271
result_dir.create_workingtree(revision_id=revision_id)
273
local_wt.clone(result_dir, revision_id=revision_id)
234
self.open_workingtree().clone(result_dir, revision_id=revision_id)
235
except (bzr_errors.NoWorkingTree, bzr_errors.NotLocalUrl):
275
238
return result_dir
306
269
return UseExistingRepository(self.find_repository())
308
def branch_names(self):
309
from .refs import ref_to_branch_name
311
for ref in self.get_refs_container().keys():
313
branch_name = ref_to_branch_name(ref)
314
except UnicodeDecodeError:
315
trace.warning("Ignoring branch %r with unicode error ref", ref)
319
ret.append(branch_name)
322
271
def get_branches(self):
323
272
from .refs import ref_to_branch_name
325
274
for ref in self.get_refs_container().keys():
327
276
branch_name = ref_to_branch_name(ref)
328
279
except UnicodeDecodeError:
329
280
trace.warning("Ignoring branch %r with unicode error ref", ref)
333
282
ret[branch_name] = self.open_branch(ref=ref)
336
285
def list_branches(self):
337
return list(self.get_branches().values())
286
return self.get_branches().values()
339
288
def push_branch(self, source, revision_id=None, overwrite=False,
340
289
remember=False, create_prefix=False, lossy=False,
341
name=None, tag_selector=None):
342
291
"""Push the source branch into this ControlDir."""
343
292
push_result = GitPushResult()
344
293
push_result.workingtree_updated = None
345
294
push_result.master_branch = None
346
295
push_result.source_branch = source
347
296
push_result.stacked_on = None
297
repo = self.find_repository()
298
refname = self._get_selected_ref(name)
348
299
from .branch import GitBranch
349
300
if isinstance(source, GitBranch) and lossy:
350
raise brz_errors.LossyPushToSameVCS(source.controldir, self)
301
raise bzr_errors.LossyPushToSameVCS(source.controldir, self)
351
302
target = self.open_branch(name, nascent_ok=True)
352
303
push_result.branch_push_result = source.push(
353
target, overwrite=overwrite, stop_revision=revision_id,
354
lossy=lossy, tag_selector=tag_selector)
304
target, overwrite=overwrite, stop_revision=revision_id,
355
306
push_result.new_revid = push_result.branch_push_result.new_revid
356
307
push_result.old_revid = push_result.branch_push_result.old_revid
358
wt = self.open_workingtree()
359
except brz_errors.NoWorkingTree:
360
push_result.workingtree_updated = None
362
if self.open_branch(name="").name == target.name:
364
old_revision=push_result.old_revid,
365
new_revision=push_result.new_revid)
366
push_result.workingtree_updated = True
368
push_result.workingtree_updated = False
369
push_result.target_branch = target
308
push_result.target_branch = self.open_branch(name)
370
309
if source.get_push_location() is None or remember:
371
310
source.set_push_location(push_result.target_branch.base)
372
311
return push_result
402
341
from .transportgit import TransportRepo
404
def _open(transport):
406
return TransportRepo(transport, self.bare,
407
refs_text=getattr(self, "_refs_text", None))
408
except ValueError as e:
409
if e.args == ('Expected file to start with \'gitdir: \'', ):
410
raise brz_errors.NotBranchError(path=transport.base)
413
def redirected(transport, e, redirection_notice):
414
trace.note(redirection_notice)
415
return transport._redirected_to(e.source, e.target)
416
gitrepo = do_catching_redirections(_open, transport, redirected)
417
if not _found and not gitrepo._controltransport.has('objects'):
418
raise brz_errors.NotBranchError(path=transport.base)
342
gitrepo = TransportRepo(transport, self.bare,
343
refs_text=getattr(self, "_refs_text", None))
344
if not gitrepo._controltransport.has('HEAD'):
345
raise bzr_errors.NotBranchError(path=transport.base)
419
346
return LocalGitDir(transport, gitrepo, self)
421
348
def get_format_description(self):
424
351
def initialize_on_transport(self, transport):
425
352
from .transportgit import TransportRepo
426
git_repo = TransportRepo.init(transport, bare=self.bare)
427
return LocalGitDir(transport, git_repo, self)
353
repo = TransportRepo.init(transport, bare=self.bare)
354
return self.open(transport)
429
356
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
430
create_prefix=False, force_new_repo=False,
432
stack_on_pwd=None, repo_format_name=None,
433
make_working_trees=None,
434
shared_repo=False, vfs_only=False):
436
raise brz_errors.SharedRepositoriesUnsupported(self)
357
create_prefix=False, force_new_repo=False, stacked_on=None,
358
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
359
shared_repo=False, vfs_only=False):
438
360
def make_directory(transport):
439
361
transport.mkdir('.')
442
363
def redirected(transport, e, redirection_notice):
443
364
trace.note(redirection_notice)
444
365
return transport._redirected_to(e.source, e.target)
446
transport = do_catching_redirections(
447
make_directory, transport, redirected)
448
except brz_errors.FileExists:
367
transport = do_catching_redirections(make_directory, transport,
369
except bzr_errors.FileExists:
449
370
if not use_existing_dir:
451
except brz_errors.NoSuchFile:
372
except bzr_errors.NoSuchFile:
452
373
if not create_prefix:
454
375
transport.create_prefix()
532
451
def set_branch_reference(self, target_branch, name=None):
533
452
ref = self._get_selected_ref(name)
534
target_transport = target_branch.controldir.control_transport
535
if self.control_transport.base == target_transport.base:
453
if self.control_transport.base == target_branch.controldir.control_transport.base:
536
454
if ref == target_branch.ref:
537
455
raise BranchReferenceLoop(target_branch)
538
456
self._git.refs.set_symbolic_ref(ref, target_branch.ref)
542
target_branch.controldir.control_transport.local_abspath(
544
except brz_errors.NotLocalUrl:
545
raise brz_errors.IncompatibleFormat(
546
target_branch._format, self._format)
459
target_path = target_branch.controldir.control_transport.local_abspath('.')
460
except bzr_errors.NotLocalUrl:
461
raise bzr_errors.IncompatibleFormat(target_branch._format, self._format)
547
462
# TODO(jelmer): Do some consistency checking across branches..
548
self.control_transport.put_bytes(
549
'commondir', encode_git_path(target_path))
463
self.control_transport.put_bytes('commondir', target_path.encode('utf-8'))
550
464
# TODO(jelmer): Urgh, avoid mucking about with internals.
551
self._git._commontransport = (
552
target_branch.repository._git._commontransport.clone())
553
self._git.object_store = TransportObjectStore(
554
self._git._commontransport.clone(OBJECTDIR))
465
self._git._commontransport = target_branch.repository._git._commontransport.clone()
466
self._git.object_store = TransportObjectStore(self._git._commontransport.clone(OBJECTDIR))
555
467
self._git.refs.transport = self._git._commontransport
556
target_ref_chain, unused_sha = (
557
target_branch.controldir._git.refs.follow(target_branch.ref))
468
target_ref_chain, unused_sha = target_branch.controldir._git.refs.follow(target_branch.ref)
558
469
for target_ref in target_ref_chain:
559
470
if target_ref == b'HEAD':
563
474
# Can't create a reference to something that is not a in a repository.
564
raise brz_errors.IncompatibleFormat(
565
self.set_branch_reference, self)
475
raise bzr_errors.IncompatibleFormat(self.set_branch_reference, self)
566
476
self._git.refs.set_symbolic_ref(ref, target_ref)
568
478
def get_branch_reference(self, name=None):
601
508
return self.transport
602
509
if isinstance(branch_format, LocalGitControlDirFormat):
603
510
return self.transport
604
raise brz_errors.IncompatibleFormat(branch_format, self._format)
511
raise bzr_errors.IncompatibleFormat(branch_format, self._format)
606
513
def get_repository_transport(self, format):
607
514
if format is None:
608
515
return self.transport
609
516
if isinstance(format, LocalGitControlDirFormat):
610
517
return self.transport
611
raise brz_errors.IncompatibleFormat(format, self._format)
518
raise bzr_errors.IncompatibleFormat(format, self._format)
613
520
def get_workingtree_transport(self, format):
614
521
if format is None:
615
522
return self.transport
616
523
if isinstance(format, LocalGitControlDirFormat):
617
524
return self.transport
618
raise brz_errors.IncompatibleFormat(format, self._format)
525
raise bzr_errors.IncompatibleFormat(format, self._format)
620
527
def open_branch(self, name=None, unsupported=False, ignore_fallbacks=None,
621
ref=None, possible_transports=None, nascent_ok=False):
528
ref=None, possible_transports=None, nascent_ok=False):
622
529
"""'create' a branch for this dir."""
623
530
repo = self.find_repository()
624
531
from .branch import LocalGitBranch
625
532
ref = self._get_selected_ref(name, ref)
626
533
if not nascent_ok and ref not in self._git.refs:
627
raise brz_errors.NotBranchError(
628
self.root_transport.base, controldir=self)
534
raise bzr_errors.NotBranchError(self.root_transport.base,
629
536
ref_chain, unused_sha = self._git.refs.follow(ref)
630
537
if ref_chain[-1] == b'HEAD':
631
538
controldir = self
637
544
refname = self._get_selected_ref(name)
638
545
if refname == b'HEAD':
639
546
# HEAD can't be removed
640
raise brz_errors.UnsupportedOperation(
547
raise bzr_errors.UnsupportedOperation(
641
548
self.destroy_branch, self)
643
550
del self._git.refs[refname]
645
raise brz_errors.NotBranchError(
646
self.root_transport.base, controldir=self)
552
raise bzr_errors.NotBranchError(self.root_transport.base,
648
555
def destroy_repository(self):
649
raise brz_errors.UnsupportedOperation(self.destroy_repository, self)
556
raise bzr_errors.UnsupportedOperation(self.destroy_repository, self)
651
558
def destroy_workingtree(self):
652
raise brz_errors.UnsupportedOperation(self.destroy_workingtree, self)
559
raise bzr_errors.UnsupportedOperation(self.destroy_workingtree, self)
654
561
def destroy_workingtree_metadata(self):
655
raise brz_errors.UnsupportedOperation(
656
self.destroy_workingtree_metadata, self)
562
raise bzr_errors.UnsupportedOperation(self.destroy_workingtree_metadata, self)
658
564
def needs_format_conversion(self, format=None):
659
565
return not isinstance(self._format, format.__class__)
670
576
def open_workingtree(self, recommend_upgrade=True, unsupported=False):
671
577
if not self._git.bare:
578
from dulwich.errors import NoIndexPresent
672
579
repo = self.find_repository()
673
580
from .workingtree import GitWorkingTree
674
581
branch = self.open_branch(ref=b'HEAD', nascent_ok=True)
675
582
return GitWorkingTree(self, repo, branch)
676
583
loc = urlutils.unescape_for_display(self.root_transport.base, 'ascii')
677
raise brz_errors.NoWorkingTree(loc)
584
raise bzr_errors.NoWorkingTree(loc)
679
586
def create_repository(self, shared=False):
680
587
from .repository import GitRepositoryFormat
682
raise brz_errors.IncompatibleFormat(
683
GitRepositoryFormat(), self._format)
589
raise bzr_errors.IncompatibleFormat(GitRepositoryFormat(), self._format)
684
590
return self.find_repository()
686
592
def create_branch(self, name=None, repository=None,
687
593
append_revisions_only=None, ref=None):
688
594
refname = self._get_selected_ref(name, ref)
689
595
if refname != b'HEAD' and refname in self._git.refs:
690
raise brz_errors.AlreadyBranchError(self.user_url)
596
raise bzr_errors.AlreadyBranchError(self.user_url)
691
597
repo = self.open_repository()
692
598
if refname in self._git.refs:
693
ref_chain, unused_sha = self._git.refs.follow(
694
self._get_selected_ref(None))
599
ref_chain, unused_sha = self._git.refs.follow(self._get_selected_ref(None))
695
600
if ref_chain[0] == b'HEAD':
696
601
refname = ref_chain[1]
697
602
from .branch import LocalGitBranch