164
164
nick = property(_get_nick, _set_nick)
167
class _Branch(Branch, ControlFiles):
166
def push_stores(self, branch_to):
167
"""Copy the content of this branches store to branch_to."""
168
raise NotImplementedError('push_stores is abstract')
170
def lock_write(self):
171
raise NotImplementedError('lock_write is abstract')
174
raise NotImplementedError('lock_read is abstract')
177
raise NotImplementedError('unlock is abstract')
179
def abspath(self, name):
180
"""Return absolute filename for something in the branch
182
XXX: Robert Collins 20051017 what is this used for? why is it a branch
183
method and not a tree method.
185
raise NotImplementedError('abspath is abstract')
187
def get_root_id(self):
188
"""Return the id of this branches root"""
189
raise NotImplementedError('get_root_id is abstract')
191
def set_root_id(self, file_id):
192
raise NotImplementedError('set_root_id is abstract')
194
def add(self, files, ids=None):
195
"""Make files versioned.
197
Note that the command line normally calls smart_add instead,
198
which can automatically recurse.
200
This puts the files in the Added state, so that they will be
201
recorded by the next commit.
204
List of paths to add, relative to the base of the tree.
207
If set, use these instead of automatically generated ids.
208
Must be the same length as the list of files, but may
209
contain None for ids that are to be autogenerated.
211
TODO: Perhaps have an option to add the ids even if the files do
214
TODO: Perhaps yield the ids and paths as they're added.
216
raise NotImplementedError('add is abstract')
218
def print_file(self, file, revno):
219
"""Print `file` to stdout."""
220
raise NotImplementedError('print_file is abstract')
223
"""Return all unknown files.
225
These are files in the working directory that are not versioned or
226
control files or ignored.
228
>>> from bzrlib.workingtree import WorkingTree
229
>>> b = ScratchBranch(files=['foo', 'foo~'])
230
>>> map(str, b.unknowns())
233
>>> list(b.unknowns())
235
>>> WorkingTree(b.base, b).remove('foo')
236
>>> list(b.unknowns())
239
raise NotImplementedError('unknowns is abstract')
241
def append_revision(self, *revision_ids):
242
raise NotImplementedError('append_revision is abstract')
244
def set_revision_history(self, rev_history):
245
raise NotImplementedError('set_revision_history is abstract')
247
def get_revision_delta(self, revno):
248
"""Return the delta for one revision.
250
The delta is relative to its mainline predecessor, or the
251
empty tree for revision 1.
253
assert isinstance(revno, int)
254
rh = self.revision_history()
255
if not (1 <= revno <= len(rh)):
256
raise InvalidRevisionNumber(revno)
258
# revno is 1-based; list is 0-based
260
new_tree = self.revision_tree(rh[revno-1])
262
old_tree = EmptyTree()
264
old_tree = self.revision_tree(rh[revno-2])
266
return compare_trees(old_tree, new_tree)
268
def get_ancestry(self, revision_id):
269
"""Return a list of revision-ids integrated by a revision.
271
This currently returns a list, but the ordering is not guaranteed:
274
raise NotImplementedError('get_ancestry is abstract')
276
def revision_history(self):
277
"""Return sequence of revision hashes on to this branch."""
278
raise NotImplementedError('revision_history is abstract')
281
"""Return current revision number for this branch.
283
That is equivalent to the number of revisions committed to
286
return len(self.revision_history())
288
def last_revision(self):
289
"""Return last patch hash, or None if no history."""
290
ph = self.revision_history()
296
def missing_revisions(self, other, stop_revision=None, diverged_ok=False):
297
"""Return a list of new revisions that would perfectly fit.
299
If self and other have not diverged, return a list of the revisions
300
present in other, but missing from self.
302
>>> from bzrlib.commit import commit
303
>>> bzrlib.trace.silent = True
304
>>> br1 = ScratchBranch()
305
>>> br2 = ScratchBranch()
306
>>> br1.missing_revisions(br2)
308
>>> commit(br2, "lala!", rev_id="REVISION-ID-1")
309
>>> br1.missing_revisions(br2)
311
>>> br2.missing_revisions(br1)
313
>>> commit(br1, "lala!", rev_id="REVISION-ID-1")
314
>>> br1.missing_revisions(br2)
316
>>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
317
>>> br1.missing_revisions(br2)
319
>>> commit(br1, "lala!", rev_id="REVISION-ID-2B")
320
>>> br1.missing_revisions(br2)
321
Traceback (most recent call last):
322
DivergedBranches: These branches have diverged.
324
self_history = self.revision_history()
325
self_len = len(self_history)
326
other_history = other.revision_history()
327
other_len = len(other_history)
328
common_index = min(self_len, other_len) -1
329
if common_index >= 0 and \
330
self_history[common_index] != other_history[common_index]:
331
raise DivergedBranches(self, other)
333
if stop_revision is None:
334
stop_revision = other_len
336
assert isinstance(stop_revision, int)
337
if stop_revision > other_len:
338
raise bzrlib.errors.NoSuchRevision(self, stop_revision)
339
return other_history[self_len:stop_revision]
342
def update_revisions(self, other, stop_revision=None):
343
"""Pull in new perfect-fit revisions."""
344
raise NotImplementedError('update_revisions is abstract')
346
def pullable_revisions(self, other, stop_revision):
347
raise NotImplementedError('pullable_revisions is abstract')
349
def commit(self, *args, **kw):
350
raise NotImplementedError('commit is abstract')
352
def revision_id_to_revno(self, revision_id):
353
"""Given a revision id, return its revno"""
354
if revision_id is None:
356
history = self.revision_history()
358
return history.index(revision_id) + 1
360
raise bzrlib.errors.NoSuchRevision(self, revision_id)
362
def get_rev_id(self, revno, history=None):
363
"""Find the revision id of the specified revno."""
367
history = self.revision_history()
368
elif revno <= 0 or revno > len(history):
369
raise bzrlib.errors.NoSuchRevision(self, revno)
370
return history[revno - 1]
372
def working_tree(self):
373
"""Return a `Tree` for the working copy."""
374
raise NotImplementedError('working_tree is abstract')
376
def pull(self, source, overwrite=False):
377
raise NotImplementedError('pull is abstract')
379
def basis_tree(self):
380
"""Return `Tree` object for last revision.
382
If there are no revisions yet, return an `EmptyTree`.
384
return self.storage.revision_tree(self.last_revision())
386
def rename_one(self, from_rel, to_rel):
389
This can change the directory or the filename or both.
391
raise NotImplementedError('rename_one is abstract')
393
def move(self, from_paths, to_name):
396
to_name must exist as a versioned directory.
398
If to_name exists and is a directory, the files are moved into
399
it, keeping their old names. If it is a directory,
401
Note that to_name is only the last component of the new name;
402
this doesn't change the directory.
404
This returns a list of (from_path, to_path) pairs for each
407
raise NotImplementedError('move is abstract')
409
def revert(self, filenames, old_tree=None, backups=True):
410
"""Restore selected files to the versions from a previous tree.
413
If true (default) backups are made of files before
416
raise NotImplementedError('revert is abstract')
418
def pending_merges(self):
419
"""Return a list of pending merges.
421
These are revisions that have been merged into the working
422
directory but not yet committed.
424
raise NotImplementedError('pending_merges is abstract')
426
def add_pending_merge(self, *revision_ids):
427
# TODO: Perhaps should check at this point that the
428
# history of the revision is actually present?
429
raise NotImplementedError('add_pending_merge is abstract')
431
def set_pending_merges(self, rev_list):
432
raise NotImplementedError('set_pending_merges is abstract')
434
def get_parent(self):
435
"""Return the parent location of the branch.
437
This is the default location for push/pull/missing. The usual
438
pattern is that the user can override it by specifying a
441
raise NotImplementedError('get_parent is abstract')
443
def get_push_location(self):
444
"""Return the None or the location to push this branch to."""
445
raise NotImplementedError('get_push_location is abstract')
447
def set_push_location(self, location):
448
"""Set a new push location for this branch."""
449
raise NotImplementedError('set_push_location is abstract')
451
def set_parent(self, url):
452
raise NotImplementedError('set_parent is abstract')
454
def check_revno(self, revno):
456
Check whether a revno corresponds to any revision.
457
Zero (the NULL revision) is considered valid.
460
self.check_real_revno(revno)
462
def check_real_revno(self, revno):
464
Check whether a revno corresponds to a real revision.
465
Zero (the NULL revision) is considered invalid
467
if revno < 1 or revno > self.revno():
468
raise InvalidRevisionNumber(revno)
470
def sign_revision(self, revision_id, gpg_strategy):
471
raise NotImplementedError('sign_revision is abstract')
473
def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
474
raise NotImplementedError('store_revision_signature is abstract')
477
class BzrBranch(Branch, ControlFiles):
168
478
"""A branch stored in the actual filesystem.
170
480
Note that it's "local" in the context of the filesystem; it doesn't
523
793
# transaction.register_clean(history, precious=True)
524
794
return list(history)
527
"""Return current revision number for this branch.
529
That is equivalent to the number of revisions committed to
532
return len(self.revision_history())
534
def last_revision(self):
535
"""Return last patch hash, or None if no history.
537
ph = self.revision_history()
543
def missing_revisions(self, other, stop_revision=None, diverged_ok=False):
544
"""Return a list of new revisions that would perfectly fit.
546
If self and other have not diverged, return a list of the revisions
547
present in other, but missing from self.
549
>>> from bzrlib.commit import commit
550
>>> bzrlib.trace.silent = True
551
>>> br1 = ScratchBranch()
552
>>> br2 = ScratchBranch()
553
>>> br1.missing_revisions(br2)
555
>>> commit(br2, "lala!", rev_id="REVISION-ID-1")
556
>>> br1.missing_revisions(br2)
558
>>> br2.missing_revisions(br1)
560
>>> commit(br1, "lala!", rev_id="REVISION-ID-1")
561
>>> br1.missing_revisions(br2)
563
>>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
564
>>> br1.missing_revisions(br2)
566
>>> commit(br1, "lala!", rev_id="REVISION-ID-2B")
567
>>> br1.missing_revisions(br2)
568
Traceback (most recent call last):
569
DivergedBranches: These branches have diverged.
571
self_history = self.revision_history()
572
self_len = len(self_history)
573
other_history = other.revision_history()
574
other_len = len(other_history)
575
common_index = min(self_len, other_len) -1
576
if common_index >= 0 and \
577
self_history[common_index] != other_history[common_index]:
578
raise DivergedBranches(self, other)
580
if stop_revision is None:
581
stop_revision = other_len
583
assert isinstance(stop_revision, int)
584
if stop_revision > other_len:
585
raise bzrlib.errors.NoSuchRevision(self, stop_revision)
586
return other_history[self_len:stop_revision]
588
796
def update_revisions(self, other, stop_revision=None):
589
"""Pull in new perfect-fit revisions."""
797
"""See Branch.update_revisions."""
590
798
from bzrlib.fetch import greedy_fetch
591
799
if stop_revision is None:
592
800
stop_revision = other.last_revision()