131
116
class GitBranch(ForeignBranch):
132
117
"""An adapter to git repositories for bzr Branch objects."""
134
def __init__(self, bzrdir, repository, name, lockfiles):
119
def __init__(self, bzrdir, repository, name, head, lockfiles):
135
120
self.repository = repository
136
121
self._format = GitBranchFormat()
137
122
self.control_files = lockfiles
138
123
self.bzrdir = bzrdir
139
124
super(GitBranch, self).__init__(repository.get_mapping())
142
127
self.base = bzrdir.transport.base
144
129
def _get_nick(self, local=False, possible_master_transports=None):
156
141
def __repr__(self):
157
142
return "%s(%r, %r)" % (self.__class__.__name__, self.repository.base, self.name)
144
def dpull(self, source, stop_revision=None):
145
if stop_revision is None:
146
stop_revision = source.last_revision()
147
# FIXME: Check for diverged branches
148
refs = { "refs/heads/master": stop_revision }
149
for name, revid in source.tags.get_tag_dict().iteritems():
150
if source.repository.has_revision(revid):
151
refs["refs/tags/%s" % name] = revid
152
revidmap, new_refs = self.repository.dfetch_refs(source.repository,
155
self.generate_revision_history(revidmap[stop_revision])
159
158
def generate_revision_history(self, revid, old_revid=None):
160
159
# FIXME: Check that old_revid is in the ancestry of revid
161
160
newhead, self.mapping = self.mapping.revision_id_bzr_to_foreign(revid)
162
161
self._set_head(newhead)
163
def _set_head(self, head):
165
self.repository._git.set_ref(self.name, self.head)
164
167
def lock_write(self):
165
168
self.control_files.lock_write()
304
282
self._show_tag_conficts(to_file)
307
class GitBranchPushResult(branch.BranchPushResult):
309
def _lookup_revno(self, revid):
310
assert isinstance(revid, str), "was %r" % revid
311
# Try in source branch first, it'll be faster
313
return self.source_branch.revision_id_to_revno(revid)
314
except errors.NoSuchRevision:
315
# FIXME: Check using graph.find_distance_to_null() ?
316
return self.target_branch.revision_id_to_revno(revid)
320
return self._lookup_revno(self.old_revid)
324
return self._lookup_revno(self.new_revid)
327
class InterFromGitBranch(branch.GenericInterBranch):
285
class InterGitGenericBranch(branch.InterBranch):
328
286
"""InterBranch implementation that pulls from Git into bzr."""
408
366
self.source.unlock()
411
def _basic_push(self, overwrite=False, stop_revision=None):
412
result = branch.BranchPushResult()
413
result.source_branch = self.source
414
result.target_branch = self.target
415
graph = self.target.repository.get_graph(self.source.repository)
416
result.old_revno, result.old_revid = self.target.last_revision_info()
417
self.update_revisions(stop_revision, overwrite=overwrite,
419
result.new_git_head = self._head
420
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
422
result.new_revno, result.new_revid = self.target.last_revision_info()
426
class InterGitBranch(branch.GenericInterBranch):
372
branch.InterBranch.register_optimiser(InterGitGenericBranch)
375
class InterGitRemoteLocalBranch(branch.InterBranch):
427
376
"""InterBranch implementation that pulls between Git branches."""
430
class InterGitLocalRemoteBranch(InterGitBranch):
431
"""InterBranch that copies from a local to a remote git branch."""
434
def is_compatible(self, source, target):
435
from bzrlib.plugins.git.remote import RemoteGitBranch
436
return (isinstance(source, LocalGitBranch) and
437
isinstance(target, RemoteGitBranch))
439
def _basic_push(self, overwrite=False, stop_revision=None):
440
result = GitBranchPushResult()
441
result.source_branch = self.source
442
result.target_branch = self.target
443
if stop_revision is None:
444
stop_revision = self.source.last_revision()
445
# FIXME: Check for diverged branches
446
def get_changed_refs(old_refs):
447
result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(old_refs.get("refs/heads/master", "0" * 40))
448
refs = { "refs/heads/master": self.source.repository.lookup_git_revid(stop_revision)[0] }
449
result.new_revid = stop_revision
450
for name, sha in self.source.repository._git.refs.as_dict("refs/tags").iteritems():
451
refs["refs/tags/%s" % name] = sha
453
self.target.repository.send_pack(get_changed_refs,
454
self.source.repository._git.object_store.generate_pack_contents)
458
class InterGitRemoteLocalBranch(InterGitBranch):
459
"""InterBranch that copies from a remote to a local git branch."""
462
379
def is_compatible(self, source, target):
463
380
from bzrlib.plugins.git.remote import RemoteGitBranch
464
381
return (isinstance(source, RemoteGitBranch) and
465
382
isinstance(target, LocalGitBranch))
467
def _basic_push(self, overwrite=False, stop_revision=None):
468
result = branch.BranchPushResult()
469
result.source_branch = self.source
470
result.target_branch = self.target
471
result.old_revid = self.target.last_revision()
472
refs, stop_revision = self.update_refs(stop_revision)
473
self.target.generate_revision_history(stop_revision, result.old_revid)
474
self.update_tags(refs)
475
result.new_revid = self.target.last_revision()
478
def update_tags(self, refs):
479
for name, revid in extract_tags(refs, self.target.mapping).iteritems():
480
self.target.tags.set_tag(name, revid)
482
def update_refs(self, stop_revision=None):
483
interrepo = repository.InterRepository.get(self.source.repository,
484
self.target.repository)
485
if stop_revision is None:
486
refs = interrepo.fetch_refs(branches=["HEAD"])
487
stop_revision = self.target.mapping.revision_id_foreign_to_bzr(refs["HEAD"])
489
refs = interrepo.fetch_refs(revision_id=stop_revision)
490
return refs, stop_revision
492
384
def pull(self, stop_revision=None, overwrite=False,
493
385
possible_transports=None, local=False):
494
386
# This type of branch can't be bound.
497
389
result = GitPullResult()
498
390
result.source_branch = self.source
499
391
result.target_branch = self.target
392
interrepo = repository.InterRepository.get(self.source.repository,
393
self.target.repository)
500
394
result.old_revid = self.target.last_revision()
501
refs, stop_revision = self.update_refs(stop_revision)
395
if stop_revision is None:
396
stop_revision = self.source.last_revision()
397
interrepo.fetch(revision_id=stop_revision)
502
398
self.target.generate_revision_history(stop_revision, result.old_revid)
503
self.update_tags(refs)
504
399
result.new_revid = self.target.last_revision()
508
class InterToGitBranch(branch.InterBranch):
509
"""InterBranch implementation that pulls from Git into bzr."""
512
def is_compatible(self, source, target):
513
return (not isinstance(source, GitBranch) and
514
isinstance(target, GitBranch))
516
def update_revisions(self, *args, **kwargs):
517
raise NoPushSupport()
519
def push(self, overwrite=True, stop_revision=None,
520
_override_hook_source_branch=None):
521
raise NoPushSupport()
523
def lossy_push(self, stop_revision=None):
524
result = GitBranchPushResult()
525
result.source_branch = self.source
526
result.target_branch = self.target
527
result.old_revid = self.target.last_revision()
528
if stop_revision is None:
529
stop_revision = self.source.last_revision()
530
# FIXME: Check for diverged branches
531
refs = { "refs/heads/master": stop_revision }
532
for name, revid in self.source.tags.get_tag_dict().iteritems():
533
if self.source.repository.has_revision(revid):
534
refs["refs/tags/%s" % name] = revid
535
revidmap, new_refs = self.target.repository.dfetch_refs(
536
self.source.repository, refs)
538
self.target.generate_revision_history(revidmap[stop_revision])
539
result.new_revid = revidmap[stop_revision]
541
result.new_revid = result.old_revid
542
result.revidmap = revidmap
546
403
branch.InterBranch.register_optimiser(InterGitRemoteLocalBranch)
547
branch.InterBranch.register_optimiser(InterFromGitBranch)
548
branch.InterBranch.register_optimiser(InterToGitBranch)
549
branch.InterBranch.register_optimiser(InterGitLocalRemoteBranch)