224
226
if last_revision is None:
225
227
pb.update('get source history')
226
from_history = from_branch.revision_history()
228
last_revision = from_history[-1]
230
# no history in the source branch
231
last_revision = _mod_revision.NULL_REVISION
228
last_revision = from_branch.last_revision_info()[1]
232
229
return self.repository.fetch(from_branch.repository,
233
230
revision_id=last_revision,
262
259
if config is None:
263
260
config = self.get_config()
265
return self.repository.get_commit_builder(self, parents, config,
262
return self.repository.get_commit_builder(self, parents, config,
266
263
timestamp, timezone, committer, revprops, revision_id)
268
265
def get_master_branch(self):
322
def last_revision_info(self):
323
"""Return information about the last revision.
325
:return: A tuple (revno, last_revision_id).
327
rh = self.revision_history()
330
return (revno, rh[-1])
332
return (0, _mod_revision.NULL_REVISION)
325
334
def missing_revisions(self, other, stop_revision=None):
326
335
"""Return a list of new revisions that would perfectly fit.
375
384
return history[revno - 1]
377
386
def pull(self, source, overwrite=False, stop_revision=None):
387
"""Mirror source into this branch.
389
This branch is considered to be 'local', having low latency.
378
391
raise NotImplementedError(self.pull)
393
def push(self, target, overwrite=False, stop_revision=None):
394
"""Mirror this branch into target.
396
This branch is considered to be 'local', having low latency.
398
raise NotImplementedError(self.push)
380
400
def basis_tree(self):
381
401
"""Return `Tree` object for last revision."""
382
402
return self.repository.revision_tree(self.last_revision())
716
736
return self.get_format_string().rstrip()
739
class BranchHooks(dict):
740
"""A dictionary mapping hook name to a list of callables for branch hooks.
742
e.g. ['set_rh'] Is the list of items to be called when the
743
set_revision_history function is invoked.
747
"""Create the default hooks.
749
These are all empty initially, because by default nothing should get
753
# Introduced in 0.15:
754
# invoked whenever the revision history has been set
755
# with set_revision_history. The api signature is
756
# (branch, revision_history), and the branch will
759
# invoked after a push operation completes.
760
# the api signature is
761
# (source, local, master, old_revno, old_revid, new_revno, new_revid)
762
# where local is the local branch or None, master is the target
763
# master branch, and the rest should be self explanatory. The source
764
# is read locked and the target branches write locked. Source will
765
# be the local low-latency branch.
766
self['post_push'] = []
767
# invoked after a pull operation completes.
768
# the api signature is
769
# (source, local, master, old_revno, old_revid, new_revno, new_revid)
770
# where local is the local branch or None, master is the target
771
# master branch, and the rest should be self explanatory. The source
772
# is read locked and the target branches write locked. The local
773
# branch is the low-latency branch.
774
self['post_pull'] = []
775
# invoked after a commit operation completes.
776
# the api signature is
777
# (local, master, old_revno, old_revid, new_revno, new_revid)
778
# old_revid is NULL_REVISION for the first commit to a branch.
779
self['post_commit'] = []
780
# invoked after a uncommit operation completes.
781
# the api signature is
782
# (local, master, old_revno, old_revid, new_revno, new_revid) where
783
# local is the local branch or None, master is the target branch,
784
# and an empty branch recieves new_revno of 0, new_revid of None.
785
self['post_uncommit'] = []
787
def install_hook(self, hook_name, a_callable):
788
"""Install a_callable in to the hook hook_name.
790
:param hook_name: A hook name. See the __init__ method of BranchHooks
791
for the complete list of hooks.
792
:param a_callable: The callable to be invoked when the hook triggers.
793
The exact signature will depend on the hook - see the __init__
794
method of BranchHooks for details on each hook.
797
self[hook_name].append(a_callable)
799
raise errors.UnknownHook('branch', hook_name)
802
# install the default hooks into the Branch class.
803
Branch.hooks = BranchHooks()
719
806
class BzrBranchFormat4(BranchFormat):
720
807
"""Bzr branch format 4.
1188
1277
return self.bzrdir.open_workingtree()
1190
1279
@needs_write_lock
1191
def pull(self, source, overwrite=False, stop_revision=None):
1192
"""See Branch.pull."""
1280
def pull(self, source, overwrite=False, stop_revision=None,
1281
_hook_master=None, _run_hooks=True):
1284
:param _hook_master: Private parameter - set the branch to
1285
be supplied as the master to push hooks.
1286
:param _run_hooks: Private parameter - allow disabling of
1287
hooks, used when pushing to a master branch.
1193
1289
source.lock_read()
1195
old_count = len(self.revision_history())
1291
old_count, old_tip = self.last_revision_info()
1197
1293
self.update_revisions(source, stop_revision)
1198
1294
except DivergedBranches:
1202
1298
self.set_revision_history(source.revision_history())
1203
new_count = len(self.revision_history())
1299
new_count, new_tip = self.last_revision_info()
1306
for hook in Branch.hooks['post_pull']:
1307
hook(source, _hook_local, _hook_master, old_count, old_tip,
1204
1309
return new_count - old_count
1206
1311
source.unlock()
1314
def push(self, target, overwrite=False, stop_revision=None,
1315
_hook_master=None, _run_hooks=True):
1318
:param _hook_master: Private parameter - set the branch to
1319
be supplied as the master to push hooks.
1320
:param _run_hooks: Private parameter - allow disabling of
1321
hooks, used when pushing to a master branch.
1325
old_count, old_tip = target.last_revision_info()
1327
target.update_revisions(self, stop_revision)
1328
except DivergedBranches:
1332
target.set_revision_history(self.revision_history())
1333
new_count, new_tip = target.last_revision_info()
1336
_hook_local = target
1338
_hook_master = target
1340
for hook in Branch.hooks['post_push']:
1341
hook(self, _hook_local, _hook_master, old_count, old_tip,
1343
return new_count - old_count
1208
1347
def get_parent(self):
1209
1348
"""See Branch.get_parent."""
1282
1421
_repository=_repository)
1284
1423
@needs_write_lock
1285
def pull(self, source, overwrite=False, stop_revision=None):
1286
"""Updates branch.pull to be bound branch aware."""
1424
def pull(self, source, overwrite=False, stop_revision=None,
1426
"""Extends branch.pull to be bound branch aware.
1428
:param _run_hooks: Private parameter used to force hook running
1429
off during bound branch double-pushing.
1287
1431
bound_location = self.get_bound_location()
1288
if source.base != bound_location:
1432
master_branch = None
1433
if bound_location and source.base != bound_location:
1289
1434
# not pulling from master, so we need to update master.
1290
1435
master_branch = self.get_master_branch()
1292
master_branch.pull(source)
1293
source = master_branch
1294
return super(BzrBranch5, self).pull(source, overwrite, stop_revision)
1436
master_branch.lock_write()
1439
# pull from source into master.
1440
master_branch.pull(source, overwrite, stop_revision,
1442
return super(BzrBranch5, self).pull(source, overwrite,
1443
stop_revision, _hook_master=master_branch,
1444
_run_hooks=_run_hooks)
1447
master_branch.unlock()
1450
def push(self, target, overwrite=False, stop_revision=None):
1451
"""Updates branch.push to be bound branch aware."""
1452
bound_location = target.get_bound_location()
1453
master_branch = None
1454
if bound_location and target.base != bound_location:
1455
# not pushing to master, so we need to update master.
1456
master_branch = target.get_master_branch()
1457
master_branch.lock_write()
1460
# push into the master from this branch.
1461
super(BzrBranch5, self).push(master_branch, overwrite,
1462
stop_revision, _run_hooks=False)
1463
# and push into the target branch from this. Note that we push from
1464
# this branch again, because its considered the highest bandwidth
1466
return super(BzrBranch5, self).push(target, overwrite,
1467
stop_revision, _hook_master=master_branch)
1470
master_branch.unlock()
1296
1472
def get_bound_location(self):