~bzr/ubuntu/hardy/bzr-git/bzr-ppa

« back to all changes in this revision

Viewing changes to branch.py

  • Committer: Max Bowsher
  • Date: 2011-04-13 00:11:53 UTC
  • mfrom: (75.1.3 jaunty)
  • Revision ID: maxb@f2s.com-20110413001153-arfzlashy1m82w9d
Tags: 0.6.0-1~bazaar1~hardy1
MergeĀ 0.6.0-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
from dulwich.objects import (
23
23
    Commit,
24
24
    Tag,
 
25
    ZERO_SHA,
25
26
    )
26
27
 
27
28
from bzrlib import (
29
30
    bzrdir,
30
31
    config,
31
32
    errors,
32
 
    repository,
 
33
    repository as _mod_repository,
33
34
    revision,
34
35
    tag,
35
36
    transport,
53
54
    NoSuchRef,
54
55
    )
55
56
from bzrlib.plugins.git.refs import (
 
57
    branch_name_to_ref,
56
58
    extract_tags,
57
59
    is_tag,
58
60
    ref_to_branch_name,
100
102
        for k, v in refs.iteritems():
101
103
            if not is_tag(k):
102
104
                continue
103
 
            if overwrite or not k in self.target.repository.refs:
104
 
                target_repo.refs[k] = v
105
 
            elif target_repo.repository.refs[k] == v:
 
105
            if overwrite or not k in target_repo._git.refs:
 
106
                target_repo._git.refs[k] = v
 
107
            elif target_repo._git.refs[k] == v:
106
108
                pass
107
109
            else:
108
110
                conflicts.append((ref_to_tag_name(k), v, target_repo.refs[k]))
130
132
 
131
133
    def merge_to(self, to_tags, overwrite=False, ignore_master=False,
132
134
                 source_refs=None):
 
135
        """See Tags.merge_to."""
133
136
        if source_refs is None:
134
137
            source_refs = self.get_refs()
135
138
        if self == to_tags:
145
148
            conflicts = self._merge_to_non_git(to_tags, source_refs,
146
149
                                              overwrite=overwrite)
147
150
            if master is not None:
148
 
                conflicts += self.merge_to(to_tags, overwrite=overwrite,
 
151
                conflicts += self.merge_to(master.tags, overwrite=overwrite,
149
152
                                           source_refs=source_refs,
150
153
                                           ignore_master=ignore_master)
151
154
            return conflicts
230
233
    def supports_tags(self):
231
234
        return True
232
235
 
 
236
    def supports_leaving_lock(self):
 
237
        return False
 
238
 
 
239
    @property
 
240
    def _matchingbzrdir(self):
 
241
        from bzrlib.plugins.git.dir import LocalGitControlDirFormat
 
242
        return LocalGitControlDirFormat()
 
243
 
233
244
    def get_foreign_tests_branch_factory(self):
234
245
        from bzrlib.plugins.git.tests.test_branch import ForeignTestsBranchFactory
235
246
        return ForeignTestsBranchFactory()
241
252
        else:
242
253
            return LocalGitTagDict(branch)
243
254
 
 
255
    def initialize(self, a_bzrdir, name=None, repository=None):
 
256
        from bzrlib.plugins.git.dir import LocalGitDir
 
257
        if not isinstance(a_bzrdir, LocalGitDir):
 
258
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
 
259
        if repository is None:
 
260
            repository = a_bzrdir.open_repository()
 
261
        ref = branch_name_to_ref(name, "HEAD")
 
262
        repository._git[ref] = ZERO_SHA
 
263
        return LocalGitBranch(a_bzrdir, repository, ref, a_bzrdir._lockfiles)
 
264
 
244
265
 
245
266
class GitReadLock(object):
246
267
 
251
272
class GitWriteLock(object):
252
273
 
253
274
    def __init__(self, unlock):
 
275
        self.branch_token = None
254
276
        self.unlock = unlock
255
277
 
256
278
 
257
279
class GitBranch(ForeignBranch):
258
280
    """An adapter to git repositories for bzr Branch objects."""
259
281
 
 
282
    @property
 
283
    def control_transport(self):
 
284
        return self.bzrdir.control_transport
 
285
 
260
286
    def __init__(self, bzrdir, repository, ref, lockfiles, tagsdict=None):
261
287
        self.repository = repository
262
288
        self._format = GitBranchFormat()
300
326
            self.ref or "HEAD")
301
327
 
302
328
    def generate_revision_history(self, revid, old_revid=None):
303
 
        # FIXME: Check that old_revid is in the ancestry of revid
304
 
        newhead, self.mapping = self.mapping.revision_id_bzr_to_foreign(revid)
 
329
        if revid == NULL_REVISION:
 
330
            newhead = ZERO_SHA
 
331
        else:
 
332
            # FIXME: Check that old_revid is in the ancestry of revid
 
333
            newhead, self.mapping = self.mapping.revision_id_bzr_to_foreign(revid)
305
334
        self._set_head(newhead)
306
335
 
307
336
    def lock_write(self):
357
386
class LocalGitBranch(GitBranch):
358
387
    """A local Git branch."""
359
388
 
360
 
    def __init__(self, bzrdir, repository, name, lockfiles, tagsdict=None):
361
 
        super(LocalGitBranch, self).__init__(bzrdir, repository, name,
 
389
    def __init__(self, bzrdir, repository, ref, lockfiles, tagsdict=None):
 
390
        super(LocalGitBranch, self).__init__(bzrdir, repository, ref,
362
391
              lockfiles, tagsdict)
363
392
        refs = repository._git.get_refs()
364
 
        if not (name in refs.keys() or "HEAD" in refs.keys()):
 
393
        if not (ref in refs.keys() or "HEAD" in refs.keys()):
365
394
            raise errors.NotBranchError(self.base)
366
395
 
367
396
    def create_checkout(self, to_location, revision_id=None, lightweight=False,
524
553
 
525
554
    @staticmethod
526
555
    def _get_branch_formats_to_test():
527
 
        return []
 
556
        try:
 
557
            default_format = branch.format_registry.get_default()
 
558
        except AttributeError:
 
559
            default_format = branch.BranchFormat._default_format
 
560
        return [
 
561
            (GitBranchFormat(), GitBranchFormat()),
 
562
            (GitBranchFormat(), default_format)]
528
563
 
529
564
    @classmethod
530
565
    def _get_interrepo(self, source, target):
531
 
        return repository.InterRepository.get(source.repository,
532
 
            target.repository)
 
566
        return _mod_repository.InterRepository.get(source.repository, target.repository)
533
567
 
534
568
    @classmethod
535
569
    def is_compatible(cls, source, target):
537
571
                not isinstance(target, GitBranch) and
538
572
                (getattr(cls._get_interrepo(source, target), "fetch_objects", None) is not None))
539
573
 
540
 
    def _update_revisions(self, stop_revision=None, overwrite=False,
541
 
        graph=None, limit=None):
542
 
        """Like InterBranch.update_revisions(), but with additions.
 
574
    def fetch(self, stop_revision=None, fetch_tags=True):
 
575
        self.fetch_objects(stop_revision, fetch_tags=fetch_tags)
543
576
 
544
 
        Compared to the `update_revisions()` below, this function takes a
545
 
        `limit` argument that limits how many git commits will be converted
546
 
        and returns the new git head and remote refs.
547
 
        """
 
577
    def fetch_objects(self, stop_revision, fetch_tags):
548
578
        interrepo = self._get_interrepo(self.source, self.target)
549
579
        def determine_wants(heads):
550
580
            if self.source.ref is not None and not self.source.ref in heads:
551
581
                raise NoSuchRef(self.source.ref, heads.keys())
552
 
            if stop_revision is not None:
553
 
                self._last_revid = stop_revision
554
 
                head, mapping = self.source.repository.lookup_bzr_revision_id(
555
 
                    stop_revision)
556
 
            else:
 
582
 
 
583
            if stop_revision is None:
557
584
                if self.source.ref is not None:
558
585
                    head = heads[self.source.ref]
559
586
                else:
560
587
                    head = heads["HEAD"]
561
588
                self._last_revid = self.source.lookup_foreign_revision_id(head)
562
 
            if self.target.repository.has_revision(self._last_revid):
563
 
                return []
564
 
            return [head]
 
589
            else:
 
590
                self._last_revid = stop_revision
 
591
            real = interrepo.get_determine_wants_revids(
 
592
                [self._last_revid], include_tags=fetch_tags)
 
593
            return real(heads)
565
594
        pack_hint, head, refs = interrepo.fetch_objects(
566
 
            determine_wants, self.source.mapping, limit=limit)
 
595
            determine_wants, self.source.mapping)
567
596
        if (pack_hint is not None and
568
597
            self.target.repository._format.pack_compresses):
569
598
            self.target.repository.pack(hint=pack_hint)
570
 
        if head is not None:
571
 
            self._last_revid = self.source.lookup_foreign_revision_id(head)
 
599
        return head, refs
 
600
 
 
601
    def update_revisions(self, stop_revision=None, overwrite=False,
 
602
                         graph=None):
 
603
        """See InterBranch.update_revisions()."""
 
604
        head, refs = self.fetch_objects(stop_revision, fetch_tags=True)
572
605
        if overwrite:
573
606
            prev_last_revid = None
574
607
        else:
575
608
            prev_last_revid = self.target.last_revision()
576
609
        self.target.generate_revision_history(self._last_revid,
577
 
            prev_last_revid)
 
610
            prev_last_revid, self.source)
578
611
        return head, refs
579
612
 
580
 
    def update_revisions(self, stop_revision=None, overwrite=False,
581
 
                         graph=None):
582
 
        """See InterBranch.update_revisions()."""
583
 
        self._update_revisions(stop_revision, overwrite, graph)
584
 
 
585
613
    def pull(self, overwrite=False, stop_revision=None,
586
614
             possible_transports=None, _hook_master=None, run_hooks=True,
587
 
             _override_hook_target=None, local=False, limit=None):
 
615
             _override_hook_target=None, local=False):
588
616
        """See Branch.pull.
589
617
 
590
618
        :param _hook_master: Private parameter - set the branch to
594
622
            so it should not run its hooks.
595
623
        :param _override_hook_target: Private parameter - set the branch to be
596
624
            supplied as the target_branch to pull hooks.
597
 
        :param limit: Only import this many revisons.  `None`, the default,
598
 
            means import all revisions.
599
625
        """
600
626
        # This type of branch can't be bound.
601
627
        if local:
613
639
            graph = self.target.repository.get_graph(self.source.repository)
614
640
            (result.old_revno, result.old_revid) = \
615
641
                self.target.last_revision_info()
616
 
            result.new_git_head, remote_refs = self._update_revisions(
617
 
                stop_revision, overwrite=overwrite, graph=graph, limit=limit)
 
642
            result.new_git_head, remote_refs = self.update_revisions(
 
643
                stop_revision, overwrite=overwrite, graph=graph)
618
644
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
619
645
                overwrite)
620
646
            (result.new_revno, result.new_revid) = \
638
664
        result.target_branch = self.target
639
665
        graph = self.target.repository.get_graph(self.source.repository)
640
666
        result.old_revno, result.old_revid = self.target.last_revision_info()
641
 
        result.new_git_head, remote_refs = self._update_revisions(
 
667
        result.new_git_head, remote_refs = self.update_revisions(
642
668
            stop_revision, overwrite=overwrite, graph=graph)
643
669
        result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
644
670
            overwrite)
650
676
    """InterBranch implementation that pulls between Git branches."""
651
677
 
652
678
 
653
 
class InterGitLocalRemoteBranch(InterGitBranch):
 
679
class InterLocalGitRemoteGitBranch(InterGitBranch):
654
680
    """InterBranch that copies from a local to a remote git branch."""
655
681
 
656
682
    @staticmethod
657
683
    def _get_branch_formats_to_test():
 
684
        # FIXME
658
685
        return []
659
686
 
660
687
    @classmethod
664
691
                isinstance(target, RemoteGitBranch))
665
692
 
666
693
    def _basic_push(self, overwrite=False, stop_revision=None):
667
 
        from dulwich.protocol import ZERO_SHA
668
694
        result = GitBranchPushResult()
669
695
        result.source_branch = self.source
670
696
        result.target_branch = self.target
683
709
        return result
684
710
 
685
711
 
686
 
class InterGitRemoteLocalBranch(InterGitBranch):
 
712
class InterGitLocalGitBranch(InterGitBranch):
687
713
    """InterBranch that copies from a remote to a local git branch."""
688
714
 
689
715
    @staticmethod
690
716
    def _get_branch_formats_to_test():
 
717
        # FIXME
691
718
        return []
692
719
 
693
720
    @classmethod
694
721
    def is_compatible(self, source, target):
695
 
        from bzrlib.plugins.git.remote import RemoteGitBranch
696
 
        return (isinstance(source, RemoteGitBranch) and
 
722
        return (isinstance(source, GitBranch) and
697
723
                isinstance(target, LocalGitBranch))
698
724
 
699
725
    def _basic_push(self, overwrite=False, stop_revision=None):
709
735
        return result
710
736
 
711
737
    def update_refs(self, stop_revision=None):
712
 
        interrepo = repository.InterRepository.get(self.source.repository,
 
738
        interrepo = _mod_repository.InterRepository.get(self.source.repository,
713
739
            self.target.repository)
714
740
        if stop_revision is None:
715
741
            refs = interrepo.fetch(branches=["HEAD"])
740
766
 
741
767
    def __init__(self, source, target):
742
768
        super(InterToGitBranch, self).__init__(source, target)
743
 
        self.interrepo = repository.InterRepository.get(source.repository,
 
769
        self.interrepo = _mod_repository.InterRepository.get(source.repository,
744
770
                                           target.repository)
745
771
 
746
772
    @staticmethod
747
773
    def _get_branch_formats_to_test():
748
 
        return []
 
774
        try:
 
775
            default_format = branch.format_registry.get_default()
 
776
        except AttributeError:
 
777
            default_format = branch.BranchFormat._default_format
 
778
        return [(default_format, GitBranchFormat())]
749
779
 
750
780
    @classmethod
751
781
    def is_compatible(self, source, target):
758
788
    def _get_new_refs(self, stop_revision=None):
759
789
        if stop_revision is None:
760
790
            (stop_revno, stop_revision) = self.source.last_revision_info()
 
791
        else:
 
792
            stop_revno = self.source.revision_id_to_revno(stop_revision)
761
793
        assert type(stop_revision) is str
762
794
        main_ref = self.target.ref or "refs/heads/master"
763
795
        refs = { main_ref: (None, stop_revision) }
767
799
        return refs, main_ref, (stop_revno, stop_revision)
768
800
 
769
801
    def pull(self, overwrite=False, stop_revision=None, local=False,
770
 
             possible_transports=None):
771
 
        from dulwich.protocol import ZERO_SHA
 
802
             possible_transports=None, run_hooks=True):
772
803
        result = GitBranchPullResult()
773
804
        result.source_branch = self.source
774
805
        result.target_branch = self.target
778
809
            # FIXME: Check for diverged branches
779
810
            refs.update(new_refs)
780
811
            return refs
781
 
        old_refs, new_refs = self.interrepo.fetch_refs(update_refs)
 
812
        try:
 
813
            old_refs, new_refs = self.interrepo.fetch_refs(update_refs)
 
814
        except NoPushSupport:
 
815
            raise errors.NoRoundtrippingSupport(self.source, self.target)
782
816
        (result.old_revid, old_sha1) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
783
817
        if result.old_revid is None:
784
818
            result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
787
821
 
788
822
    def push(self, overwrite=False, stop_revision=None,
789
823
             _override_hook_source_branch=None):
790
 
        from dulwich.protocol import ZERO_SHA
791
824
        result = GitBranchPushResult()
792
825
        result.source_branch = self.source
793
826
        result.target_branch = self.target
797
830
            # FIXME: Check for diverged branches
798
831
            refs.update(new_refs)
799
832
            return refs
800
 
        old_refs, new_refs = self.interrepo.fetch_refs(update_refs)
 
833
        try:
 
834
            old_refs, new_refs = self.interrepo.fetch_refs(update_refs)
 
835
        except NoPushSupport:
 
836
            raise errors.NoRoundtrippingSupport(self.source, self.target)
801
837
        (result.old_revid, old_sha1) = old_refs.get(main_ref, (ZERO_SHA, NULL_REVISION))
802
838
        if result.old_revid is None:
803
839
            result.old_revid = self.target.lookup_foreign_revision_id(old_sha1)
822
858
        return result
823
859
 
824
860
 
825
 
branch.InterBranch.register_optimiser(InterGitRemoteLocalBranch)
 
861
branch.InterBranch.register_optimiser(InterGitLocalGitBranch)
826
862
branch.InterBranch.register_optimiser(InterFromGitBranch)
827
863
branch.InterBranch.register_optimiser(InterToGitBranch)
828
 
branch.InterBranch.register_optimiser(InterGitLocalRemoteBranch)
 
864
branch.InterBranch.register_optimiser(InterLocalGitRemoteGitBranch)