~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Jelmer Vernooij
  • Date: 2011-05-10 07:46:15 UTC
  • mfrom: (5844 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5845.
  • Revision ID: jelmer@samba.org-20110510074615-eptod049ndjxc4i7
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
        urlutils,
43
43
        )
44
44
from bzrlib.config import BranchConfig, TransportConfig
45
 
from bzrlib.repofmt.pack_repo import RepositoryFormatKnitPack5RichRoot
46
45
from bzrlib.tag import (
47
46
    BasicTags,
48
47
    DisabledTags,
57
56
    needs_write_lock,
58
57
    only_raises,
59
58
    )
60
 
from bzrlib.hooks import HookPoint, Hooks
 
59
from bzrlib.hooks import Hooks
61
60
from bzrlib.inter import InterObject
62
61
from bzrlib.lock import _RelockDebugMixin, LogicalLockResult
63
62
from bzrlib import registry
79
78
    :ivar base:
80
79
        Base directory/url of the branch; using control_url and
81
80
        control_transport is more standardized.
82
 
 
83
 
    hooks: An instance of BranchHooks.
 
81
    :ivar hooks: An instance of BranchHooks.
 
82
    :ivar _master_branch_cache: cached result of get_master_branch, see
 
83
        _clear_cached_state.
84
84
    """
85
85
    # this is really an instance variable - FIXME move it there
86
86
    # - RBC 20060112
102
102
        self._partial_revision_history_cache = []
103
103
        self._tags_bytes = None
104
104
        self._last_revision_info_cache = None
 
105
        self._master_branch_cache = None
105
106
        self._merge_sorted_revisions_cache = None
106
107
        self._open_hook()
107
108
        hooks = Branch.hooks['open']
668
669
        raise errors.UnsupportedOperation(self.get_reference_info, self)
669
670
 
670
671
    @needs_write_lock
671
 
    def fetch(self, from_branch, last_revision=None, fetch_spec=None):
 
672
    def fetch(self, from_branch, last_revision=None):
672
673
        """Copy revisions from from_branch into this branch.
673
674
 
674
675
        :param from_branch: Where to copy from.
675
676
        :param last_revision: What revision to stop at (None for at the end
676
677
                              of the branch.
677
 
        :param fetch_spec: If specified, a SearchResult or
678
 
            PendingAncestryResult that describes which revisions to copy.  This
679
 
            allows copying multiple heads at once.  Mutually exclusive with
680
 
            last_revision.
681
678
        :return: None
682
679
        """
683
 
        if fetch_spec is not None and last_revision is not None:
684
 
            raise AssertionError(
685
 
                "fetch_spec and last_revision are mutually exclusive.")
686
 
        if self.base == from_branch.base:
687
 
            return (0, [])
688
 
        from_branch.lock_read()
689
 
        try:
690
 
            if last_revision is None and fetch_spec is None:
691
 
                last_revision = from_branch.last_revision()
692
 
                last_revision = _mod_revision.ensure_null(last_revision)
693
 
            return self.repository.fetch(from_branch.repository,
694
 
                                         revision_id=last_revision,
695
 
                                         fetch_spec=fetch_spec)
696
 
        finally:
697
 
            from_branch.unlock()
 
680
        return InterBranch.get(from_branch, self).fetch(last_revision)
698
681
 
699
682
    def get_bound_location(self):
700
683
        """Return the URL of the branch we are bound to.
711
694
 
712
695
    def get_commit_builder(self, parents, config=None, timestamp=None,
713
696
                           timezone=None, committer=None, revprops=None,
714
 
                           revision_id=None):
 
697
                           revision_id=None, lossy=False):
715
698
        """Obtain a CommitBuilder for this branch.
716
699
 
717
700
        :param parents: Revision ids of the parents of the new revision.
721
704
        :param committer: Optional committer to set for commit.
722
705
        :param revprops: Optional dictionary of revision properties.
723
706
        :param revision_id: Optional revision id.
 
707
        :param lossy: Whether to discard data that can not be natively
 
708
            represented, when pushing to a foreign VCS 
724
709
        """
725
710
 
726
711
        if config is None:
727
712
            config = self.get_config()
728
713
 
729
714
        return self.repository.get_commit_builder(self, parents, config,
730
 
            timestamp, timezone, committer, revprops, revision_id)
 
715
            timestamp, timezone, committer, revprops, revision_id,
 
716
            lossy)
731
717
 
732
718
    def get_master_branch(self, possible_transports=None):
733
719
        """Return the branch we are bound to.
760
746
        """Print `file` to stdout."""
761
747
        raise NotImplementedError(self.print_file)
762
748
 
 
749
    @deprecated_method(deprecated_in((2, 4, 0)))
763
750
    def set_revision_history(self, rev_history):
764
 
        raise NotImplementedError(self.set_revision_history)
 
751
        """See Branch.set_revision_history."""
 
752
        self._set_revision_history(rev_history)
 
753
 
 
754
    @needs_write_lock
 
755
    def _set_revision_history(self, rev_history):
 
756
        if len(rev_history) == 0:
 
757
            revid = _mod_revision.NULL_REVISION
 
758
        else:
 
759
            revid = rev_history[-1]
 
760
        if rev_history != self._lefthand_history(revid):
 
761
            raise errors.NotLefthandHistory(rev_history)
 
762
        self.set_last_revision_info(len(rev_history), revid)
 
763
        self._cache_revision_history(rev_history)
 
764
        for hook in Branch.hooks['set_rh']:
 
765
            hook(self, rev_history)
 
766
 
 
767
    @needs_write_lock
 
768
    def set_last_revision_info(self, revno, revision_id):
 
769
        """Set the last revision of this branch.
 
770
 
 
771
        The caller is responsible for checking that the revno is correct
 
772
        for this revision id.
 
773
 
 
774
        It may be possible to set the branch last revision to an id not
 
775
        present in the repository.  However, branches can also be
 
776
        configured to check constraints on history, in which case this may not
 
777
        be permitted.
 
778
        """
 
779
        raise NotImplementedError(self.last_revision_info)
 
780
 
 
781
    @needs_write_lock
 
782
    def generate_revision_history(self, revision_id, last_rev=None,
 
783
                                  other_branch=None):
 
784
        """See Branch.generate_revision_history"""
 
785
        # FIXME: This shouldn't have to fetch the entire history
 
786
        history = self._lefthand_history(revision_id, last_rev, other_branch)
 
787
        revno = len(history)
 
788
        self.set_last_revision_info(revno, revision_id)
 
789
        self._cache_revision_history(history)
765
790
 
766
791
    @needs_write_lock
767
792
    def set_parent(self, url):
937
962
        self._revision_history_cache = None
938
963
        self._revision_id_to_revno_cache = None
939
964
        self._last_revision_info_cache = None
 
965
        self._master_branch_cache = None
940
966
        self._merge_sorted_revisions_cache = None
941
967
        self._partial_revision_history_cache = []
942
968
        self._partial_revision_id_to_revno_cache = {}
996
1022
        :return: A tuple (revno, revision_id).
997
1023
        """
998
1024
        if self._last_revision_info_cache is None:
999
 
            self._last_revision_info_cache = self._last_revision_info()
 
1025
            self._last_revision_info_cache = self._read_last_revision_info()
1000
1026
        return self._last_revision_info_cache
1001
1027
 
1002
 
    def _last_revision_info(self):
1003
 
        rh = self.revision_history()
1004
 
        revno = len(rh)
1005
 
        if revno:
1006
 
            return (revno, rh[-1])
1007
 
        else:
1008
 
            return (0, _mod_revision.NULL_REVISION)
1009
 
 
1010
 
    def update_revisions(self, other, stop_revision=None, overwrite=False,
1011
 
                         graph=None, fetch_tags=True):
1012
 
        """Pull in new perfect-fit revisions.
1013
 
 
1014
 
        :param other: Another Branch to pull from
1015
 
        :param stop_revision: Updated until the given revision
1016
 
        :param overwrite: Always set the branch pointer, rather than checking
1017
 
            to see if it is a proper descendant.
1018
 
        :param graph: A Graph object that can be used to query history
1019
 
            information. This can be None.
1020
 
        :param fetch_tags: Flag that specifies if tags from other should be
1021
 
            fetched too.
1022
 
        :return: None
1023
 
        """
1024
 
        return InterBranch.get(other, self).update_revisions(stop_revision,
1025
 
            overwrite, graph, fetch_tags=fetch_tags)
 
1028
    def _read_last_revision_info(self):
 
1029
        raise NotImplementedError(self._read_last_revision_info)
1026
1030
 
1027
1031
    @deprecated_method(deprecated_in((2, 4, 0)))
1028
1032
    def import_last_revision_info(self, source_repo, revno, revid):
1036
1040
            self.repository.fetch(source_repo, revision_id=revid)
1037
1041
        self.set_last_revision_info(revno, revid)
1038
1042
 
1039
 
    def import_last_revision_info_and_tags(self, source, revno, revid):
 
1043
    def import_last_revision_info_and_tags(self, source, revno, revid,
 
1044
                                           lossy=False):
1040
1045
        """Set the last revision info, importing from another repo if necessary.
1041
1046
 
1042
1047
        This is used by the bound branch code to upload a revision to
1046
1051
        :param source: Source branch to optionally fetch from
1047
1052
        :param revno: Revision number of the new tip
1048
1053
        :param revid: Revision id of the new tip
 
1054
        :param lossy: Whether to discard metadata that can not be
 
1055
            natively represented
 
1056
        :return: Tuple with the new revision number and revision id
 
1057
            (should only be different from the arguments when lossy=True)
1049
1058
        """
1050
1059
        if not self.repository.has_same_location(source.repository):
1051
 
            try:
1052
 
                tags_to_fetch = set(source.tags.get_reverse_tag_dict())
1053
 
            except errors.TagsNotSupported:
1054
 
                tags_to_fetch = set()
1055
 
            fetch_spec = _mod_graph.NotInOtherForRevs(self.repository,
1056
 
                source.repository, [revid],
1057
 
                if_present_ids=tags_to_fetch).execute()
1058
 
            self.repository.fetch(source.repository, fetch_spec=fetch_spec)
 
1060
            self.fetch(source, revid)
1059
1061
        self.set_last_revision_info(revno, revid)
 
1062
        return (revno, revid)
1060
1063
 
1061
1064
    def revision_id_to_revno(self, revision_id):
1062
1065
        """Given a revision id, return its revno"""
1302
1305
            if repository_policy is not None:
1303
1306
                repository_policy.configure_branch(result)
1304
1307
            self.copy_content_into(result, revision_id=revision_id)
1305
 
            result.set_parent(self.bzrdir.root_transport.base)
 
1308
            master_branch = self.get_master_branch()
 
1309
            if master_branch is None:
 
1310
                result.set_parent(self.bzrdir.root_transport.base)
 
1311
            else:
 
1312
                result.set_parent(master_branch.bzrdir.root_transport.base)
1306
1313
        finally:
1307
1314
            result.unlock()
1308
1315
        return result
1655
1662
        for hook in hooks:
1656
1663
            hook(params)
1657
1664
 
1658
 
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
1659
 
                           repository=None):
1660
 
        """Initialize a branch in a bzrdir, with specified files
1661
 
 
1662
 
        :param a_bzrdir: The bzrdir to initialize the branch in
1663
 
        :param utf8_files: The files to create as a list of
1664
 
            (filename, content) tuples
1665
 
        :param name: Name of colocated branch to create, if any
1666
 
        :return: a branch in this format
1667
 
        """
1668
 
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
1669
 
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
1670
 
        control_files = lockable_files.LockableFiles(branch_transport,
1671
 
            'lock', lockdir.LockDir)
1672
 
        control_files.create_lock()
1673
 
        control_files.lock_write()
1674
 
        try:
1675
 
            utf8_files += [('format', self.get_format_string())]
1676
 
            for (filename, content) in utf8_files:
1677
 
                branch_transport.put_bytes(
1678
 
                    filename, content,
1679
 
                    mode=a_bzrdir._get_file_mode())
1680
 
        finally:
1681
 
            control_files.unlock()
1682
 
        branch = self.open(a_bzrdir, name, _found=True,
1683
 
                found_repository=repository)
1684
 
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
1685
 
        return branch
1686
 
 
1687
1665
    def initialize(self, a_bzrdir, name=None, repository=None):
1688
1666
        """Create a branch of this format in a_bzrdir.
1689
1667
        
1818
1796
        These are all empty initially, because by default nothing should get
1819
1797
        notified.
1820
1798
        """
1821
 
        Hooks.__init__(self)
1822
 
        self.create_hook(HookPoint('set_rh',
 
1799
        Hooks.__init__(self, "bzrlib.branch", "Branch.hooks")
 
1800
        self.add_hook('set_rh',
1823
1801
            "Invoked whenever the revision history has been set via "
1824
1802
            "set_revision_history. The api signature is (branch, "
1825
1803
            "revision_history), and the branch will be write-locked. "
1826
1804
            "The set_rh hook can be expensive for bzr to trigger, a better "
1827
 
            "hook to use is Branch.post_change_branch_tip.", (0, 15), None))
1828
 
        self.create_hook(HookPoint('open',
 
1805
            "hook to use is Branch.post_change_branch_tip.", (0, 15))
 
1806
        self.add_hook('open',
1829
1807
            "Called with the Branch object that has been opened after a "
1830
 
            "branch is opened.", (1, 8), None))
1831
 
        self.create_hook(HookPoint('post_push',
 
1808
            "branch is opened.", (1, 8))
 
1809
        self.add_hook('post_push',
1832
1810
            "Called after a push operation completes. post_push is called "
1833
1811
            "with a bzrlib.branch.BranchPushResult object and only runs in the "
1834
 
            "bzr client.", (0, 15), None))
1835
 
        self.create_hook(HookPoint('post_pull',
 
1812
            "bzr client.", (0, 15))
 
1813
        self.add_hook('post_pull',
1836
1814
            "Called after a pull operation completes. post_pull is called "
1837
1815
            "with a bzrlib.branch.PullResult object and only runs in the "
1838
 
            "bzr client.", (0, 15), None))
1839
 
        self.create_hook(HookPoint('pre_commit',
 
1816
            "bzr client.", (0, 15))
 
1817
        self.add_hook('pre_commit',
1840
1818
            "Called after a commit is calculated but before it is "
1841
1819
            "completed. pre_commit is called with (local, master, old_revno, "
1842
1820
            "old_revid, future_revno, future_revid, tree_delta, future_tree"
1845
1823
            "basis revision. hooks MUST NOT modify this delta. "
1846
1824
            " future_tree is an in-memory tree obtained from "
1847
1825
            "CommitBuilder.revision_tree() and hooks MUST NOT modify this "
1848
 
            "tree.", (0,91), None))
1849
 
        self.create_hook(HookPoint('post_commit',
 
1826
            "tree.", (0,91))
 
1827
        self.add_hook('post_commit',
1850
1828
            "Called in the bzr client after a commit has completed. "
1851
1829
            "post_commit is called with (local, master, old_revno, old_revid, "
1852
1830
            "new_revno, new_revid). old_revid is NULL_REVISION for the first "
1853
 
            "commit to a branch.", (0, 15), None))
1854
 
        self.create_hook(HookPoint('post_uncommit',
 
1831
            "commit to a branch.", (0, 15))
 
1832
        self.add_hook('post_uncommit',
1855
1833
            "Called in the bzr client after an uncommit completes. "
1856
1834
            "post_uncommit is called with (local, master, old_revno, "
1857
1835
            "old_revid, new_revno, new_revid) where local is the local branch "
1858
1836
            "or None, master is the target branch, and an empty branch "
1859
 
            "receives new_revno of 0, new_revid of None.", (0, 15), None))
1860
 
        self.create_hook(HookPoint('pre_change_branch_tip',
 
1837
            "receives new_revno of 0, new_revid of None.", (0, 15))
 
1838
        self.add_hook('pre_change_branch_tip',
1861
1839
            "Called in bzr client and server before a change to the tip of a "
1862
1840
            "branch is made. pre_change_branch_tip is called with a "
1863
1841
            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1864
 
            "commit, uncommit will all trigger this hook.", (1, 6), None))
1865
 
        self.create_hook(HookPoint('post_change_branch_tip',
 
1842
            "commit, uncommit will all trigger this hook.", (1, 6))
 
1843
        self.add_hook('post_change_branch_tip',
1866
1844
            "Called in bzr client and server after a change to the tip of a "
1867
1845
            "branch is made. post_change_branch_tip is called with a "
1868
1846
            "bzrlib.branch.ChangeBranchTipParams. Note that push, pull, "
1869
 
            "commit, uncommit will all trigger this hook.", (1, 4), None))
1870
 
        self.create_hook(HookPoint('transform_fallback_location',
 
1847
            "commit, uncommit will all trigger this hook.", (1, 4))
 
1848
        self.add_hook('transform_fallback_location',
1871
1849
            "Called when a stacked branch is activating its fallback "
1872
1850
            "locations. transform_fallback_location is called with (branch, "
1873
1851
            "url), and should return a new url. Returning the same url "
1878
1856
            "fallback locations have not been activated. When there are "
1879
1857
            "multiple hooks installed for transform_fallback_location, "
1880
1858
            "all are called with the url returned from the previous hook."
1881
 
            "The order is however undefined.", (1, 9), None))
1882
 
        self.create_hook(HookPoint('automatic_tag_name',
 
1859
            "The order is however undefined.", (1, 9))
 
1860
        self.add_hook('automatic_tag_name',
1883
1861
            "Called to determine an automatic tag name for a revision. "
1884
1862
            "automatic_tag_name is called with (branch, revision_id) and "
1885
1863
            "should return a tag name or None if no tag name could be "
1886
1864
            "determined. The first non-None tag name returned will be used.",
1887
 
            (2, 2), None))
1888
 
        self.create_hook(HookPoint('post_branch_init',
 
1865
            (2, 2))
 
1866
        self.add_hook('post_branch_init',
1889
1867
            "Called after new branch initialization completes. "
1890
1868
            "post_branch_init is called with a "
1891
1869
            "bzrlib.branch.BranchInitHookParams. "
1892
1870
            "Note that init, branch and checkout (both heavyweight and "
1893
 
            "lightweight) will all trigger this hook.", (2, 2), None))
1894
 
        self.create_hook(HookPoint('post_switch',
 
1871
            "lightweight) will all trigger this hook.", (2, 2))
 
1872
        self.add_hook('post_switch',
1895
1873
            "Called after a checkout switches branch. "
1896
1874
            "post_switch is called with a "
1897
 
            "bzrlib.branch.SwitchHookParams.", (2, 2), None))
 
1875
            "bzrlib.branch.SwitchHookParams.", (2, 2))
1898
1876
 
1899
1877
 
1900
1878
 
2020
1998
        """What class to instantiate on open calls."""
2021
1999
        raise NotImplementedError(self._branch_class)
2022
2000
 
 
2001
    def _initialize_helper(self, a_bzrdir, utf8_files, name=None,
 
2002
                           repository=None):
 
2003
        """Initialize a branch in a bzrdir, with specified files
 
2004
 
 
2005
        :param a_bzrdir: The bzrdir to initialize the branch in
 
2006
        :param utf8_files: The files to create as a list of
 
2007
            (filename, content) tuples
 
2008
        :param name: Name of colocated branch to create, if any
 
2009
        :return: a branch in this format
 
2010
        """
 
2011
        mutter('creating branch %r in %s', self, a_bzrdir.user_url)
 
2012
        branch_transport = a_bzrdir.get_branch_transport(self, name=name)
 
2013
        control_files = lockable_files.LockableFiles(branch_transport,
 
2014
            'lock', lockdir.LockDir)
 
2015
        control_files.create_lock()
 
2016
        control_files.lock_write()
 
2017
        try:
 
2018
            utf8_files += [('format', self.get_format_string())]
 
2019
            for (filename, content) in utf8_files:
 
2020
                branch_transport.put_bytes(
 
2021
                    filename, content,
 
2022
                    mode=a_bzrdir._get_file_mode())
 
2023
        finally:
 
2024
            control_files.unlock()
 
2025
        branch = self.open(a_bzrdir, name, _found=True,
 
2026
                found_repository=repository)
 
2027
        self._run_post_branch_init_hooks(a_bzrdir, name, branch)
 
2028
        return branch
 
2029
 
2023
2030
    def network_name(self):
2024
2031
        """A simple byte string uniquely identifying this format for RPC calls.
2025
2032
 
2158
2165
                      ]
2159
2166
        return self._initialize_helper(a_bzrdir, utf8_files, name, repository)
2160
2167
 
2161
 
    def __init__(self):
2162
 
        super(BzrBranchFormat8, self).__init__()
2163
 
        self._matchingbzrdir.repository_format = \
2164
 
            RepositoryFormatKnitPack5RichRoot()
2165
 
 
2166
2168
    def make_tags(self, branch):
2167
2169
        """See bzrlib.branch.BranchFormat.make_tags()."""
2168
2170
        return BasicTags(branch)
2176
2178
    supports_reference_locations = True
2177
2179
 
2178
2180
 
2179
 
class BzrBranchFormat7(BzrBranchFormat8):
 
2181
class BzrBranchFormat7(BranchFormatMetadir):
2180
2182
    """Branch format with last-revision, tags, and a stacked location pointer.
2181
2183
 
2182
2184
    The stacked location pointer is passed down to the repository and requires
2207
2209
    def supports_set_append_revisions_only(self):
2208
2210
        return True
2209
2211
 
 
2212
    def supports_stacking(self):
 
2213
        return True
 
2214
 
 
2215
    def make_tags(self, branch):
 
2216
        """See bzrlib.branch.BranchFormat.make_tags()."""
 
2217
        return BasicTags(branch)
 
2218
 
2210
2219
    supports_reference_locations = False
2211
2220
 
2212
2221
 
2502
2511
        """See Branch.print_file."""
2503
2512
        return self.repository.print_file(file, revision_id)
2504
2513
 
2505
 
    def _write_revision_history(self, history):
2506
 
        """Factored out of set_revision_history.
2507
 
 
2508
 
        This performs the actual writing to disk.
2509
 
        It is intended to be called by BzrBranch5.set_revision_history."""
2510
 
        self._transport.put_bytes(
2511
 
            'revision-history', '\n'.join(history),
2512
 
            mode=self.bzrdir._get_file_mode())
2513
 
 
2514
 
    @needs_write_lock
2515
 
    def set_revision_history(self, rev_history):
2516
 
        """See Branch.set_revision_history."""
2517
 
        if 'evil' in debug.debug_flags:
2518
 
            mutter_callsite(3, "set_revision_history scales with history.")
2519
 
        check_not_reserved_id = _mod_revision.check_not_reserved_id
2520
 
        for rev_id in rev_history:
2521
 
            check_not_reserved_id(rev_id)
2522
 
        if Branch.hooks['post_change_branch_tip']:
2523
 
            # Don't calculate the last_revision_info() if there are no hooks
2524
 
            # that will use it.
2525
 
            old_revno, old_revid = self.last_revision_info()
2526
 
        if len(rev_history) == 0:
2527
 
            revid = _mod_revision.NULL_REVISION
2528
 
        else:
2529
 
            revid = rev_history[-1]
2530
 
        self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
2531
 
        self._write_revision_history(rev_history)
2532
 
        self._clear_cached_state()
2533
 
        self._cache_revision_history(rev_history)
2534
 
        for hook in Branch.hooks['set_rh']:
2535
 
            hook(self, rev_history)
2536
 
        if Branch.hooks['post_change_branch_tip']:
2537
 
            self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2538
 
 
2539
 
    def _synchronize_history(self, destination, revision_id):
2540
 
        """Synchronize last revision and revision history between branches.
2541
 
 
2542
 
        This version is most efficient when the destination is also a
2543
 
        BzrBranch5, but works for BzrBranch6 as long as the revision
2544
 
        history is the true lefthand parent history, and all of the revisions
2545
 
        are in the destination's repository.  If not, set_revision_history
2546
 
        will fail.
2547
 
 
2548
 
        :param destination: The branch to copy the history into
2549
 
        :param revision_id: The revision-id to truncate history at.  May
2550
 
          be None to copy complete history.
2551
 
        """
2552
 
        if not isinstance(destination._format, BzrBranchFormat5):
2553
 
            super(BzrBranch, self)._synchronize_history(
2554
 
                destination, revision_id)
2555
 
            return
2556
 
        if revision_id == _mod_revision.NULL_REVISION:
2557
 
            new_history = []
2558
 
        else:
2559
 
            new_history = self.revision_history()
2560
 
        if revision_id is not None and new_history != []:
2561
 
            try:
2562
 
                new_history = new_history[:new_history.index(revision_id) + 1]
2563
 
            except ValueError:
2564
 
                rev = self.repository.get_revision(revision_id)
2565
 
                new_history = rev.get_history(self.repository)[1:]
2566
 
        destination.set_revision_history(new_history)
2567
 
 
2568
2514
    @needs_write_lock
2569
2515
    def set_last_revision_info(self, revno, revision_id):
2570
 
        """Set the last revision of this branch.
2571
 
 
2572
 
        The caller is responsible for checking that the revno is correct
2573
 
        for this revision id.
2574
 
 
2575
 
        It may be possible to set the branch last revision to an id not
2576
 
        present in the repository.  However, branches can also be
2577
 
        configured to check constraints on history, in which case this may not
2578
 
        be permitted.
2579
 
        """
 
2516
        if not revision_id or not isinstance(revision_id, basestring):
 
2517
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2580
2518
        revision_id = _mod_revision.ensure_null(revision_id)
2581
 
        # this old format stores the full history, but this api doesn't
2582
 
        # provide it, so we must generate, and might as well check it's
2583
 
        # correct
2584
 
        history = self._lefthand_history(revision_id)
2585
 
        if len(history) != revno:
2586
 
            raise AssertionError('%d != %d' % (len(history), revno))
2587
 
        self.set_revision_history(history)
2588
 
 
2589
 
    def _gen_revision_history(self):
2590
 
        history = self._transport.get_bytes('revision-history').split('\n')
2591
 
        if history[-1:] == ['']:
2592
 
            # There shouldn't be a trailing newline, but just in case.
2593
 
            history.pop()
2594
 
        return history
2595
 
 
2596
 
    @needs_write_lock
2597
 
    def generate_revision_history(self, revision_id, last_rev=None,
2598
 
        other_branch=None):
2599
 
        """Create a new revision history that will finish with revision_id.
2600
 
 
2601
 
        :param revision_id: the new tip to use.
2602
 
        :param last_rev: The previous last_revision. If not None, then this
2603
 
            must be a ancestory of revision_id, or DivergedBranches is raised.
2604
 
        :param other_branch: The other branch that DivergedBranches should
2605
 
            raise with respect to.
2606
 
        """
2607
 
        self.set_revision_history(self._lefthand_history(revision_id,
2608
 
            last_rev, other_branch))
 
2519
        old_revno, old_revid = self.last_revision_info()
 
2520
        if self._get_append_revisions_only():
 
2521
            self._check_history_violation(revision_id)
 
2522
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
 
2523
        self._write_last_revision_info(revno, revision_id)
 
2524
        self._clear_cached_state()
 
2525
        self._last_revision_info_cache = revno, revision_id
 
2526
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2609
2527
 
2610
2528
    def basis_tree(self):
2611
2529
        """See Branch.basis_tree."""
2620
2538
                pass
2621
2539
        return None
2622
2540
 
2623
 
    def _basic_push(self, target, overwrite, stop_revision):
2624
 
        """Basic implementation of push without bound branches or hooks.
2625
 
 
2626
 
        Must be called with source read locked and target write locked.
2627
 
        """
2628
 
        result = BranchPushResult()
2629
 
        result.source_branch = self
2630
 
        result.target_branch = target
2631
 
        result.old_revno, result.old_revid = target.last_revision_info()
2632
 
        self.update_references(target)
2633
 
        if result.old_revid != stop_revision:
2634
 
            # We assume that during 'push' this repository is closer than
2635
 
            # the target.
2636
 
            graph = self.repository.get_graph(target.repository)
2637
 
            target.update_revisions(self, stop_revision,
2638
 
                overwrite=overwrite, graph=graph)
2639
 
        if self._push_should_merge_tags():
2640
 
            result.tag_conflicts = self.tags.merge_to(target.tags,
2641
 
                overwrite)
2642
 
        result.new_revno, result.new_revid = target.last_revision_info()
2643
 
        return result
2644
 
 
2645
2541
    def get_stacked_on_url(self):
2646
2542
        raise errors.UnstackableBranchFormat(self._format, self.user_url)
2647
2543
 
2658
2554
            self._transport.put_bytes('parent', url + '\n',
2659
2555
                mode=self.bzrdir._get_file_mode())
2660
2556
 
2661
 
 
2662
 
class BzrBranch5(BzrBranch):
2663
 
    """A format 5 branch. This supports new features over plain branches.
2664
 
 
2665
 
    It has support for a master_branch which is the data for bound branches.
2666
 
    """
2667
 
 
2668
 
    def get_bound_location(self):
2669
 
        try:
2670
 
            return self._transport.get_bytes('bound')[:-1]
2671
 
        except errors.NoSuchFile:
2672
 
            return None
2673
 
 
2674
 
    @needs_read_lock
2675
 
    def get_master_branch(self, possible_transports=None):
2676
 
        """Return the branch we are bound to.
2677
 
 
2678
 
        :return: Either a Branch, or None
2679
 
 
2680
 
        This could memoise the branch, but if thats done
2681
 
        it must be revalidated on each new lock.
2682
 
        So for now we just don't memoise it.
2683
 
        # RBC 20060304 review this decision.
2684
 
        """
2685
 
        bound_loc = self.get_bound_location()
2686
 
        if not bound_loc:
2687
 
            return None
2688
 
        try:
2689
 
            return Branch.open(bound_loc,
2690
 
                               possible_transports=possible_transports)
2691
 
        except (errors.NotBranchError, errors.ConnectionError), e:
2692
 
            raise errors.BoundBranchConnectionFailure(
2693
 
                    self, bound_loc, e)
2694
 
 
2695
2557
    @needs_write_lock
2696
 
    def set_bound_location(self, location):
2697
 
        """Set the target where this branch is bound to.
2698
 
 
2699
 
        :param location: URL to the target branch
2700
 
        """
2701
 
        if location:
2702
 
            self._transport.put_bytes('bound', location+'\n',
2703
 
                mode=self.bzrdir._get_file_mode())
2704
 
        else:
2705
 
            try:
2706
 
                self._transport.delete('bound')
2707
 
            except errors.NoSuchFile:
2708
 
                return False
2709
 
            return True
 
2558
    def unbind(self):
 
2559
        """If bound, unbind"""
 
2560
        return self.set_bound_location(None)
2710
2561
 
2711
2562
    @needs_write_lock
2712
2563
    def bind(self, other):
2734
2585
        # history around
2735
2586
        self.set_bound_location(other.base)
2736
2587
 
 
2588
    def get_bound_location(self):
 
2589
        try:
 
2590
            return self._transport.get_bytes('bound')[:-1]
 
2591
        except errors.NoSuchFile:
 
2592
            return None
 
2593
 
 
2594
    @needs_read_lock
 
2595
    def get_master_branch(self, possible_transports=None):
 
2596
        """Return the branch we are bound to.
 
2597
 
 
2598
        :return: Either a Branch, or None
 
2599
        """
 
2600
        if self._master_branch_cache is None:
 
2601
            self._master_branch_cache = self._get_master_branch(
 
2602
                possible_transports)
 
2603
        return self._master_branch_cache
 
2604
 
 
2605
    def _get_master_branch(self, possible_transports):
 
2606
        bound_loc = self.get_bound_location()
 
2607
        if not bound_loc:
 
2608
            return None
 
2609
        try:
 
2610
            return Branch.open(bound_loc,
 
2611
                               possible_transports=possible_transports)
 
2612
        except (errors.NotBranchError, errors.ConnectionError), e:
 
2613
            raise errors.BoundBranchConnectionFailure(
 
2614
                    self, bound_loc, e)
 
2615
 
2737
2616
    @needs_write_lock
2738
 
    def unbind(self):
2739
 
        """If bound, unbind"""
2740
 
        return self.set_bound_location(None)
 
2617
    def set_bound_location(self, location):
 
2618
        """Set the target where this branch is bound to.
 
2619
 
 
2620
        :param location: URL to the target branch
 
2621
        """
 
2622
        self._master_branch_cache = None
 
2623
        if location:
 
2624
            self._transport.put_bytes('bound', location+'\n',
 
2625
                mode=self.bzrdir._get_file_mode())
 
2626
        else:
 
2627
            try:
 
2628
                self._transport.delete('bound')
 
2629
            except errors.NoSuchFile:
 
2630
                return False
 
2631
            return True
2741
2632
 
2742
2633
    @needs_write_lock
2743
2634
    def update(self, possible_transports=None):
2756
2647
            return old_tip
2757
2648
        return None
2758
2649
 
2759
 
 
2760
 
class BzrBranch8(BzrBranch5):
 
2650
    def _read_last_revision_info(self):
 
2651
        revision_string = self._transport.get_bytes('last-revision')
 
2652
        revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
 
2653
        revision_id = cache_utf8.get_cached_utf8(revision_id)
 
2654
        revno = int(revno)
 
2655
        return revno, revision_id
 
2656
 
 
2657
    def _write_last_revision_info(self, revno, revision_id):
 
2658
        """Simply write out the revision id, with no checks.
 
2659
 
 
2660
        Use set_last_revision_info to perform this safely.
 
2661
 
 
2662
        Does not update the revision_history cache.
 
2663
        """
 
2664
        revision_id = _mod_revision.ensure_null(revision_id)
 
2665
        out_string = '%d %s\n' % (revno, revision_id)
 
2666
        self._transport.put_bytes('last-revision', out_string,
 
2667
            mode=self.bzrdir._get_file_mode())
 
2668
 
 
2669
 
 
2670
class FullHistoryBzrBranch(BzrBranch):
 
2671
    """Bzr branch which contains the full revision history."""
 
2672
 
 
2673
    @needs_write_lock
 
2674
    def set_last_revision_info(self, revno, revision_id):
 
2675
        if not revision_id or not isinstance(revision_id, basestring):
 
2676
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
 
2677
        revision_id = _mod_revision.ensure_null(revision_id)
 
2678
        # this old format stores the full history, but this api doesn't
 
2679
        # provide it, so we must generate, and might as well check it's
 
2680
        # correct
 
2681
        history = self._lefthand_history(revision_id)
 
2682
        if len(history) != revno:
 
2683
            raise AssertionError('%d != %d' % (len(history), revno))
 
2684
        self._set_revision_history(history)
 
2685
 
 
2686
    def _read_last_revision_info(self):
 
2687
        rh = self.revision_history()
 
2688
        revno = len(rh)
 
2689
        if revno:
 
2690
            return (revno, rh[-1])
 
2691
        else:
 
2692
            return (0, _mod_revision.NULL_REVISION)
 
2693
 
 
2694
    @deprecated_method(deprecated_in((2, 4, 0)))
 
2695
    @needs_write_lock
 
2696
    def set_revision_history(self, rev_history):
 
2697
        """See Branch.set_revision_history."""
 
2698
        self._set_revision_history(rev_history)
 
2699
 
 
2700
    def _set_revision_history(self, rev_history):
 
2701
        if 'evil' in debug.debug_flags:
 
2702
            mutter_callsite(3, "set_revision_history scales with history.")
 
2703
        check_not_reserved_id = _mod_revision.check_not_reserved_id
 
2704
        for rev_id in rev_history:
 
2705
            check_not_reserved_id(rev_id)
 
2706
        if Branch.hooks['post_change_branch_tip']:
 
2707
            # Don't calculate the last_revision_info() if there are no hooks
 
2708
            # that will use it.
 
2709
            old_revno, old_revid = self.last_revision_info()
 
2710
        if len(rev_history) == 0:
 
2711
            revid = _mod_revision.NULL_REVISION
 
2712
        else:
 
2713
            revid = rev_history[-1]
 
2714
        self._run_pre_change_branch_tip_hooks(len(rev_history), revid)
 
2715
        self._write_revision_history(rev_history)
 
2716
        self._clear_cached_state()
 
2717
        self._cache_revision_history(rev_history)
 
2718
        for hook in Branch.hooks['set_rh']:
 
2719
            hook(self, rev_history)
 
2720
        if Branch.hooks['post_change_branch_tip']:
 
2721
            self._run_post_change_branch_tip_hooks(old_revno, old_revid)
 
2722
 
 
2723
    def _write_revision_history(self, history):
 
2724
        """Factored out of set_revision_history.
 
2725
 
 
2726
        This performs the actual writing to disk.
 
2727
        It is intended to be called by set_revision_history."""
 
2728
        self._transport.put_bytes(
 
2729
            'revision-history', '\n'.join(history),
 
2730
            mode=self.bzrdir._get_file_mode())
 
2731
 
 
2732
    def _gen_revision_history(self):
 
2733
        history = self._transport.get_bytes('revision-history').split('\n')
 
2734
        if history[-1:] == ['']:
 
2735
            # There shouldn't be a trailing newline, but just in case.
 
2736
            history.pop()
 
2737
        return history
 
2738
 
 
2739
    def _synchronize_history(self, destination, revision_id):
 
2740
        if not isinstance(destination, FullHistoryBzrBranch):
 
2741
            super(BzrBranch, self)._synchronize_history(
 
2742
                destination, revision_id)
 
2743
            return
 
2744
        if revision_id == _mod_revision.NULL_REVISION:
 
2745
            new_history = []
 
2746
        else:
 
2747
            new_history = self.revision_history()
 
2748
        if revision_id is not None and new_history != []:
 
2749
            try:
 
2750
                new_history = new_history[:new_history.index(revision_id) + 1]
 
2751
            except ValueError:
 
2752
                rev = self.repository.get_revision(revision_id)
 
2753
                new_history = rev.get_history(self.repository)[1:]
 
2754
        destination._set_revision_history(new_history)
 
2755
 
 
2756
    @needs_write_lock
 
2757
    def generate_revision_history(self, revision_id, last_rev=None,
 
2758
        other_branch=None):
 
2759
        """Create a new revision history that will finish with revision_id.
 
2760
 
 
2761
        :param revision_id: the new tip to use.
 
2762
        :param last_rev: The previous last_revision. If not None, then this
 
2763
            must be a ancestory of revision_id, or DivergedBranches is raised.
 
2764
        :param other_branch: The other branch that DivergedBranches should
 
2765
            raise with respect to.
 
2766
        """
 
2767
        self._set_revision_history(self._lefthand_history(revision_id,
 
2768
            last_rev, other_branch))
 
2769
 
 
2770
 
 
2771
class BzrBranch5(FullHistoryBzrBranch):
 
2772
    """A format 5 branch. This supports new features over plain branches.
 
2773
 
 
2774
    It has support for a master_branch which is the data for bound branches.
 
2775
    """
 
2776
 
 
2777
 
 
2778
class BzrBranch8(BzrBranch):
2761
2779
    """A branch that stores tree-reference locations."""
2762
2780
 
2763
2781
    def _open_hook(self):
2789
2807
        self._last_revision_info_cache = None
2790
2808
        self._reference_info = None
2791
2809
 
2792
 
    def _last_revision_info(self):
2793
 
        revision_string = self._transport.get_bytes('last-revision')
2794
 
        revno, revision_id = revision_string.rstrip('\n').split(' ', 1)
2795
 
        revision_id = cache_utf8.get_cached_utf8(revision_id)
2796
 
        revno = int(revno)
2797
 
        return revno, revision_id
2798
 
 
2799
 
    def _write_last_revision_info(self, revno, revision_id):
2800
 
        """Simply write out the revision id, with no checks.
2801
 
 
2802
 
        Use set_last_revision_info to perform this safely.
2803
 
 
2804
 
        Does not update the revision_history cache.
2805
 
        Intended to be called by set_last_revision_info and
2806
 
        _write_revision_history.
2807
 
        """
2808
 
        revision_id = _mod_revision.ensure_null(revision_id)
2809
 
        out_string = '%d %s\n' % (revno, revision_id)
2810
 
        self._transport.put_bytes('last-revision', out_string,
2811
 
            mode=self.bzrdir._get_file_mode())
2812
 
 
2813
 
    @needs_write_lock
2814
 
    def set_last_revision_info(self, revno, revision_id):
2815
 
        revision_id = _mod_revision.ensure_null(revision_id)
2816
 
        old_revno, old_revid = self.last_revision_info()
2817
 
        if self._get_append_revisions_only():
2818
 
            self._check_history_violation(revision_id)
2819
 
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
2820
 
        self._write_last_revision_info(revno, revision_id)
2821
 
        self._clear_cached_state()
2822
 
        self._last_revision_info_cache = revno, revision_id
2823
 
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2824
 
 
2825
 
    def _synchronize_history(self, destination, revision_id):
2826
 
        """Synchronize last revision and revision history between branches.
2827
 
 
2828
 
        :see: Branch._synchronize_history
2829
 
        """
2830
 
        # XXX: The base Branch has a fast implementation of this method based
2831
 
        # on set_last_revision_info, but BzrBranch/BzrBranch5 have a slower one
2832
 
        # that uses set_revision_history.  This class inherits from BzrBranch5,
2833
 
        # but wants the fast implementation, so it calls
2834
 
        # Branch._synchronize_history directly.
2835
 
        Branch._synchronize_history(self, destination, revision_id)
2836
 
 
2837
2810
    def _check_history_violation(self, revision_id):
2838
2811
        last_revision = _mod_revision.ensure_null(self.last_revision())
2839
2812
        if _mod_revision.is_null(last_revision):
2848
2821
        self._extend_partial_history(stop_index=last_revno-1)
2849
2822
        return list(reversed(self._partial_revision_history_cache))
2850
2823
 
2851
 
    def _write_revision_history(self, history):
2852
 
        """Factored out of set_revision_history.
2853
 
 
2854
 
        This performs the actual writing to disk, with format-specific checks.
2855
 
        It is intended to be called by BzrBranch5.set_revision_history.
2856
 
        """
2857
 
        if len(history) == 0:
2858
 
            last_revision = 'null:'
2859
 
        else:
2860
 
            if history != self._lefthand_history(history[-1]):
2861
 
                raise errors.NotLefthandHistory(history)
2862
 
            last_revision = history[-1]
2863
 
        if self._get_append_revisions_only():
2864
 
            self._check_history_violation(last_revision)
2865
 
        self._write_last_revision_info(len(history), last_revision)
2866
 
 
2867
2824
    @needs_write_lock
2868
2825
    def _set_parent_location(self, url):
2869
2826
        """Set the parent branch"""
2955
2912
 
2956
2913
    def set_bound_location(self, location):
2957
2914
        """See Branch.set_push_location."""
 
2915
        self._master_branch_cache = None
2958
2916
        result = None
2959
2917
        config = self.get_config()
2960
2918
        if location is None:
3000
2958
        return self.get_config(
3001
2959
            ).get_user_option_as_bool('append_revisions_only')
3002
2960
 
3003
 
    @needs_write_lock
3004
 
    def generate_revision_history(self, revision_id, last_rev=None,
3005
 
                                  other_branch=None):
3006
 
        """See BzrBranch5.generate_revision_history"""
3007
 
        history = self._lefthand_history(revision_id, last_rev, other_branch)
3008
 
        revno = len(history)
3009
 
        self.set_last_revision_info(revno, revision_id)
3010
 
 
3011
2961
    @needs_read_lock
3012
2962
    def get_rev_id(self, revno, history=None):
3013
2963
        """Find the revision id of the specified revno."""
3293
3243
        raise NotImplementedError(self.pull)
3294
3244
 
3295
3245
    @needs_write_lock
3296
 
    def update_revisions(self, stop_revision=None, overwrite=False,
3297
 
                         graph=None, fetch_tags=True):
3298
 
        """Pull in new perfect-fit revisions.
3299
 
 
3300
 
        :param stop_revision: Updated until the given revision
3301
 
        :param overwrite: Always set the branch pointer, rather than checking
3302
 
            to see if it is a proper descendant.
3303
 
        :param graph: A Graph object that can be used to query history
3304
 
            information. This can be None.
3305
 
        :param fetch_tags: Flag that specifies if tags from source should be
3306
 
            fetched too.
3307
 
        :return: None
3308
 
        """
3309
 
        raise NotImplementedError(self.update_revisions)
3310
 
 
3311
 
    @needs_write_lock
3312
3246
    def push(self, overwrite=False, stop_revision=None,
3313
3247
             _override_hook_source_branch=None):
3314
3248
        """Mirror the source branch into the target branch.
3326
3260
        """
3327
3261
        raise NotImplementedError(self.copy_content_into)
3328
3262
 
 
3263
    @needs_write_lock
 
3264
    def fetch(self, stop_revision=None):
 
3265
        """Fetch revisions.
 
3266
 
 
3267
        :param stop_revision: Last revision to fetch
 
3268
        """
 
3269
        raise NotImplementedError(self.fetch)
 
3270
 
3329
3271
 
3330
3272
class GenericInterBranch(InterBranch):
3331
3273
    """InterBranch implementation that uses public Branch functions."""
3366
3308
            self.source.tags.merge_to(self.target.tags)
3367
3309
 
3368
3310
    @needs_write_lock
3369
 
    def update_revisions(self, stop_revision=None, overwrite=False,
3370
 
        graph=None, fetch_tags=True):
3371
 
        """See InterBranch.update_revisions()."""
 
3311
    def fetch(self, stop_revision=None):
 
3312
        if self.target.base == self.source.base:
 
3313
            return (0, [])
 
3314
        self.source.lock_read()
 
3315
        try:
 
3316
            fetch_spec_factory = fetch.FetchSpecFactory()
 
3317
            fetch_spec_factory.source_branch = self.source
 
3318
            fetch_spec_factory.source_branch_stop_revision_id = stop_revision
 
3319
            fetch_spec_factory.source_repo = self.source.repository
 
3320
            fetch_spec_factory.target_repo = self.target.repository
 
3321
            fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
 
3322
            fetch_spec = fetch_spec_factory.make_fetch_spec()
 
3323
            return self.target.repository.fetch(self.source.repository,
 
3324
                fetch_spec=fetch_spec)
 
3325
        finally:
 
3326
            self.source.unlock()
 
3327
 
 
3328
    @needs_write_lock
 
3329
    def _update_revisions(self, stop_revision=None, overwrite=False,
 
3330
            graph=None):
3372
3331
        other_revno, other_last_revision = self.source.last_revision_info()
3373
3332
        stop_revno = None # unknown
3374
3333
        if stop_revision is None:
3385
3344
        # case of having something to pull, and so that the check for
3386
3345
        # already merged can operate on the just fetched graph, which will
3387
3346
        # be cached in memory.
3388
 
        if fetch_tags:
3389
 
            fetch_spec_factory = fetch.FetchSpecFactory()
3390
 
            fetch_spec_factory.source_branch = self.source
3391
 
            fetch_spec_factory.source_branch_stop_revision_id = stop_revision
3392
 
            fetch_spec_factory.source_repo = self.source.repository
3393
 
            fetch_spec_factory.target_repo = self.target.repository
3394
 
            fetch_spec_factory.target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
3395
 
            fetch_spec = fetch_spec_factory.make_fetch_spec()
3396
 
        else:
3397
 
            fetch_spec = _mod_graph.NotInOtherForRevs(self.target.repository,
3398
 
                self.source.repository, revision_ids=[stop_revision]).execute()
3399
 
        self.target.fetch(self.source, fetch_spec=fetch_spec)
 
3347
        self.fetch(stop_revision=stop_revision)
3400
3348
        # Check to see if one is an ancestor of the other
3401
3349
        if not overwrite:
3402
3350
            if graph is None:
3471
3419
        finally:
3472
3420
            self.source.unlock()
3473
3421
 
 
3422
    def _basic_push(self, overwrite, stop_revision):
 
3423
        """Basic implementation of push without bound branches or hooks.
 
3424
 
 
3425
        Must be called with source read locked and target write locked.
 
3426
        """
 
3427
        result = BranchPushResult()
 
3428
        result.source_branch = self.source
 
3429
        result.target_branch = self.target
 
3430
        result.old_revno, result.old_revid = self.target.last_revision_info()
 
3431
        self.source.update_references(self.target)
 
3432
        if result.old_revid != stop_revision:
 
3433
            # We assume that during 'push' this repository is closer than
 
3434
            # the target.
 
3435
            graph = self.source.repository.get_graph(self.target.repository)
 
3436
            self._update_revisions(stop_revision, overwrite=overwrite,
 
3437
                    graph=graph)
 
3438
        if self.source._push_should_merge_tags():
 
3439
            result.tag_conflicts = self.source.tags.merge_to(self.target.tags,
 
3440
                overwrite)
 
3441
        result.new_revno, result.new_revid = self.target.last_revision_info()
 
3442
        return result
 
3443
 
3474
3444
    def _push_with_bound_branches(self, overwrite, stop_revision,
3475
3445
            _override_hook_source_branch=None):
3476
3446
        """Push from source into target, and into target's master if any.
3491
3461
            master_branch.lock_write()
3492
3462
            try:
3493
3463
                # push into the master from the source branch.
3494
 
                self.source._basic_push(master_branch, overwrite, stop_revision)
3495
 
                # and push into the target branch from the source. Note that we
3496
 
                # push from the source branch again, because it's considered the
3497
 
                # highest bandwidth repository.
3498
 
                result = self.source._basic_push(self.target, overwrite,
3499
 
                    stop_revision)
 
3464
                master_inter = InterBranch.get(self.source, master_branch)
 
3465
                master_inter._basic_push(overwrite, stop_revision)
 
3466
                # and push into the target branch from the source. Note that
 
3467
                # we push from the source branch again, because it's considered
 
3468
                # the highest bandwidth repository.
 
3469
                result = self._basic_push(overwrite, stop_revision)
3500
3470
                result.master_branch = master_branch
3501
3471
                result.local_branch = self.target
3502
3472
                _run_hooks()
3505
3475
                master_branch.unlock()
3506
3476
        else:
3507
3477
            # no master branch
3508
 
            result = self.source._basic_push(self.target, overwrite,
3509
 
                stop_revision)
 
3478
            result = self._basic_push(overwrite, stop_revision)
3510
3479
            # TODO: Why set master_branch and local_branch if there's no
3511
3480
            # binding?  Maybe cleaner to just leave them unset? -- mbp
3512
3481
            # 20070504
3555
3524
            # -- JRV20090506
3556
3525
            result.old_revno, result.old_revid = \
3557
3526
                self.target.last_revision_info()
3558
 
            self.target.update_revisions(self.source, stop_revision,
3559
 
                overwrite=overwrite, graph=graph)
 
3527
            self._update_revisions(stop_revision, overwrite=overwrite,
 
3528
                graph=graph)
3560
3529
            # TODO: The old revid should be specified when merging tags, 
3561
3530
            # so a tags implementation that versions tags can only 
3562
3531
            # pull in the most recent changes. -- JRV20090506