53
from bzrlib.plugins.git.refs import (
59
54
from bzrlib.foreign import ForeignBranch
57
def extract_tags(refs):
59
for k,v in refs.iteritems():
60
if k.startswith("refs/tags/") and not k.endswith("^{}"):
61
v = refs.get(k+"^{}", v)
62
ret[k[len("refs/tags/"):]] = v
62
66
class GitPullResult(branch.PullResult):
64
68
def _lookup_revno(self, revid):
112
116
del self.repository._git[name]
114
118
def set_tag(self, name, revid):
115
self.repository._git.refs[tag_name_to_ref(name)], _ = \
119
self.repository._git.refs["refs/tags/%s" % name], _ = \
116
120
self.branch.mapping.revision_id_bzr_to_foreign(revid)
119
123
class DictTagDict(LocalGitTagDict):
121
126
def __init__(self, branch, tags):
122
127
super(DictTagDict, self).__init__(branch)
123
128
self._tags = tags
152
158
class GitBranch(ForeignBranch):
153
159
"""An adapter to git repositories for bzr Branch objects."""
155
def __init__(self, bzrdir, repository, ref, lockfiles, tagsdict=None):
161
def __init__(self, bzrdir, repository, name, lockfiles, tagsdict=None):
156
162
self.repository = repository
157
163
self._format = GitBranchFormat()
158
164
self.control_files = lockfiles
191
196
nick = property(_get_nick, _set_nick)
193
198
def __repr__(self):
194
return "<%s(%r, %r)>" % (self.__class__.__name__, self.repository.base,
199
return "%s(%r, %r)" % (self.__class__.__name__, self.repository.base, self.name)
197
201
def generate_revision_history(self, revid, old_revid=None):
198
202
# FIXME: Check that old_revid is in the ancestry of revid
242
246
class LocalGitBranch(GitBranch):
243
247
"""A local Git branch."""
245
def __init__(self, bzrdir, repository, name, lockfiles, tagsdict=None):
246
super(LocalGitBranch, self).__init__(bzrdir, repository, name,
248
if not name in repository._git.get_refs().keys():
249
raise errors.NotBranchError(self.base)
251
249
def create_checkout(self, to_location, revision_id=None, lightweight=False,
252
250
accelerator_tree=None, hardlink=False):
300
298
self.set_last_revision(revid)
302
300
def set_last_revision(self, revid):
303
(newhead, self.mapping) = self.repository.lookup_bzr_revision_id(revid)
301
(newhead, self.mapping) = self.mapping.revision_id_bzr_to_foreign(
304
303
self.head = newhead
306
305
def _set_head(self, value):
307
306
self._head = value
308
self.repository._git.refs[self.ref] = self._head
307
self.repository._git.refs[self.name] = self._head
309
308
self._clear_cached_state()
311
310
head = property(_get_head, _set_head)
333
332
if not is_quiet():
334
333
if self.old_revid == self.new_revid:
335
334
to_file.write('No revisions to pull.\n')
336
elif self.new_git_head is not None:
337
336
to_file.write('Now on revision %d (git sha: %s).\n' %
338
337
(self.new_revno, self.new_git_head))
340
to_file.write('Now on revision %d.\n' % (self.new_revno,))
341
338
self._show_tag_conficts(to_file)
375
372
not isinstance(target, GitBranch) and
376
373
(getattr(cls._get_interrepo(source, target), "fetch_objects", None) is not None))
378
def _update_revisions(self, stop_revision=None, overwrite=False,
375
def update_revisions(self, stop_revision=None, overwrite=False,
379
376
graph=None, limit=None):
380
"""Like InterBranch.update_revisions(), but with additions.
382
Compared to the `update_revisions()` below, this function takes a
383
`limit` argument that limits how many git commits will be converted
384
and returns the new git head.
377
"""See InterBranch.update_revisions()."""
386
378
interrepo = self._get_interrepo(self.source, self.target)
380
self._last_revid = None
387
381
def determine_wants(heads):
388
if not self.source.ref in heads:
389
raise NoSuchRef(self.source.ref, heads.keys())
382
if not self.source.name in heads:
383
raise NoSuchRef(self.source.name, heads.keys())
390
384
if stop_revision is not None:
391
385
self._last_revid = stop_revision
392
head, mapping = self.source.repository.lookup_bzr_revision_id(
386
self._head, mapping = self.source.repository.lookup_bzr_revision_id(
395
head = heads[self.source.ref]
396
self._last_revid = self.source.mapping.revision_id_foreign_to_bzr(
389
self._head = heads[self.source.name]
391
self.source.mapping.revision_id_foreign_to_bzr(self._head)
398
392
if self.target.repository.has_revision(self._last_revid):
401
pack_hint, head = interrepo.fetch_objects(
395
_, r = interrepo.fetch_objects(
402
396
determine_wants, self.source.mapping, limit=limit)
403
if pack_hint is not None and self.target.repository._format.pack_compresses:
404
self.target.repository.pack(hint=pack_hint)
406
self._last_revid = self.source.mapping.revision_id_foreign_to_bzr(head)
397
self._last_revid = self.source.mapping.revision_id_foreign_to_bzr(r)
408
399
prev_last_revid = None
410
401
prev_last_revid = self.target.last_revision()
411
self.target.generate_revision_history(self._last_revid,
415
def update_revisions(self, stop_revision=None, overwrite=False,
417
"""See InterBranch.update_revisions()."""
418
self._update_revisions(stop_revision, overwrite, graph)
402
self.target.generate_revision_history(self._last_revid, prev_last_revid)
420
404
def pull(self, overwrite=False, stop_revision=None,
421
405
possible_transports=None, _hook_master=None, run_hooks=True,
446
430
# We assume that during 'pull' the target repository is closer than
447
431
# the source one.
448
432
graph = self.target.repository.get_graph(self.source.repository)
449
(result.old_revno, result.old_revid) = \
433
result.old_revno, result.old_revid = \
450
434
self.target.last_revision_info()
451
result.new_git_head = self._update_revisions(
452
stop_revision, overwrite=overwrite, graph=graph, limit=limit)
435
self.update_revisions(stop_revision, overwrite=overwrite,
436
graph=graph, limit=limit)
437
result.new_git_head = self._head
453
438
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
455
(result.new_revno, result.new_revid) = \
456
self.target.last_revision_info()
440
result.new_revno, result.new_revid = self.target.last_revision_info()
458
442
result.master_branch = _hook_master
459
443
result.local_branch = result.target_branch
473
457
result.target_branch = self.target
474
458
graph = self.target.repository.get_graph(self.source.repository)
475
459
result.old_revno, result.old_revid = self.target.last_revision_info()
476
result.new_git_head = self._update_revisions(
477
stop_revision, overwrite=overwrite, graph=graph)
460
self.update_revisions(stop_revision, overwrite=overwrite, graph=graph)
461
result.new_git_head = self._head
478
462
result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
480
464
result.new_revno, result.new_revid = self.target.last_revision_info()
503
486
stop_revision = self.source.last_revision()
504
487
# FIXME: Check for diverged branches
505
488
def get_changed_refs(old_refs):
506
result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(old_refs.get(self.target.ref, ZERO_SHA))
507
refs = { self.target.ref: self.source.repository.lookup_bzr_revision_id(stop_revision)[0] }
489
result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(old_refs.get("refs/heads/master", "0" * 40))
490
refs = { "refs/heads/master": self.source.repository.lookup_bzr_revision_id(stop_revision)[0] }
508
491
result.new_revid = stop_revision
509
492
for name, sha in self.source.repository._git.refs.as_dict("refs/tags").iteritems():
510
refs[tag_name_to_ref(name)] = sha
493
refs["refs/tags/%s" % name] = sha
512
495
self.target.repository.send_pack(get_changed_refs,
513
self.source.repository._git.object_store.generate_pack_contents)
496
self.source.repository._git.object_store.generate_pack_contents)
550
533
return refs, stop_revision
552
535
def pull(self, stop_revision=None, overwrite=False,
553
possible_transports=None, run_hooks=True,local=False):
536
possible_transports=None, local=False):
554
537
# This type of branch can't be bound.
556
539
raise errors.LocalRequiresBoundBranch()
583
566
def push(self, overwrite=True, stop_revision=None,
584
567
_override_hook_source_branch=None):
585
from dulwich.protocol import ZERO_SHA
586
result = GitBranchPushResult()
587
result.source_branch = self.source
588
result.target_branch = self.target
589
if stop_revision is None:
590
stop_revision = self.source.last_revision()
591
# FIXME: Check for diverged branches
592
refs = { self.target.ref: stop_revision }
593
for name, revid in self.source.tags.get_tag_dict().iteritems():
594
if self.source.repository.has_revision(revid):
595
refs[tag_name_to_ref(name)] = revid
596
old_refs = self.target.repository._git.get_refs()
597
self.target.repository.fetch_refs(self.source.repository, refs)
598
result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(
599
old_refs.get(self.target.ref, ZERO_SHA))
600
result.new_revid = refs[self.target.ref]
568
raise NoPushSupport()
603
570
def lossy_push(self, stop_revision=None):
604
return self._push(stop_revision=stop_revision, roundtrip=False)
605
from dulwich.protocol import ZERO_SHA
606
571
result = GitBranchPushResult()
607
572
result.source_branch = self.source
608
573
result.target_branch = self.target
575
result.old_revid = self.target.last_revision()
577
result.old_revid = revision.NULL_REVISION
609
578
if stop_revision is None:
610
579
stop_revision = self.source.last_revision()
611
580
# FIXME: Check for diverged branches
612
refs = { self.target.ref: stop_revision }
581
refs = { "refs/heads/master": stop_revision }
613
582
for name, revid in self.source.tags.get_tag_dict().iteritems():
614
583
if self.source.repository.has_revision(revid):
615
refs[tag_name_to_ref(name)] = revid
616
revidmap, old_refs, new_refs = self.target.repository.dfetch_refs(
584
refs["refs/tags/%s" % name] = revid
585
revidmap, new_refs = self.target.repository.dfetch_refs(
617
586
self.source.repository, refs)
588
self.target.generate_revision_history(revidmap[stop_revision])
589
result.new_revid = revidmap[stop_revision]
591
result.new_revid = result.old_revid
618
592
result.revidmap = revidmap
619
result.old_revid = self.target.mapping.revision_id_foreign_to_bzr(
620
old_refs.get(self.target.ref, ZERO_SHA))
621
result.new_revid = self.target.mapping.revision_id_foreign_to_bzr(
622
new_refs[self.target.ref])