~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

MergedĀ fromĀ mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
109
109
        """Open a branch which may be of an old format.
110
110
        
111
111
        Only local branches are supported."""
112
 
        return _Branch(get_transport(base), relax_version_check=True)
 
112
        return BzrBranch(get_transport(base), relax_version_check=True)
113
113
        
114
114
    @staticmethod
115
115
    def open(base):
116
116
        """Open an existing branch, rooted at 'base' (url)"""
117
117
        t = get_transport(base)
118
118
        mutter("trying to open %r with transport %r", base, t)
119
 
        return _Branch(t)
 
119
        return BzrBranch(t)
120
120
 
121
121
    @staticmethod
122
122
    def open_containing(url):
131
131
        t = get_transport(url)
132
132
        while True:
133
133
            try:
134
 
                return _Branch(t), t.relpath(url)
 
134
                return BzrBranch(t), t.relpath(url)
135
135
            except NotBranchError:
136
136
                pass
137
137
            new_t = t.clone('..')
144
144
    def initialize(base):
145
145
        """Create a new branch, rooted at 'base' (url)"""
146
146
        t = get_transport(base)
147
 
        return _Branch(t, init=True)
 
147
        return BzrBranch(t, init=True)
148
148
 
149
149
    def setup_caching(self, cache_root):
150
150
        """Subclasses that care about caching should override this, and set
163
163
 
164
164
    nick = property(_get_nick, _set_nick)
165
165
        
166
 
 
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')
 
169
 
 
170
    def lock_write(self):
 
171
        raise NotImplementedError('lock_write is abstract')
 
172
        
 
173
    def lock_read(self):
 
174
        raise NotImplementedError('lock_read is abstract')
 
175
 
 
176
    def unlock(self):
 
177
        raise NotImplementedError('unlock is abstract')
 
178
 
 
179
    def abspath(self, name):
 
180
        """Return absolute filename for something in the branch
 
181
        
 
182
        XXX: Robert Collins 20051017 what is this used for? why is it a branch
 
183
        method and not a tree method.
 
184
        """
 
185
        raise NotImplementedError('abspath is abstract')
 
186
 
 
187
    def get_root_id(self):
 
188
        """Return the id of this branches root"""
 
189
        raise NotImplementedError('get_root_id is abstract')
 
190
 
 
191
    def set_root_id(self, file_id):
 
192
        raise NotImplementedError('set_root_id is abstract')
 
193
 
 
194
    def add(self, files, ids=None):
 
195
        """Make files versioned.
 
196
 
 
197
        Note that the command line normally calls smart_add instead,
 
198
        which can automatically recurse.
 
199
 
 
200
        This puts the files in the Added state, so that they will be
 
201
        recorded by the next commit.
 
202
 
 
203
        files
 
204
            List of paths to add, relative to the base of the tree.
 
205
 
 
206
        ids
 
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.
 
210
 
 
211
        TODO: Perhaps have an option to add the ids even if the files do
 
212
              not (yet) exist.
 
213
 
 
214
        TODO: Perhaps yield the ids and paths as they're added.
 
215
        """
 
216
        raise NotImplementedError('add is abstract')
 
217
 
 
218
    def print_file(self, file, revno):
 
219
        """Print `file` to stdout."""
 
220
        raise NotImplementedError('print_file is abstract')
 
221
 
 
222
    def unknowns(self):
 
223
        """Return all unknown files.
 
224
 
 
225
        These are files in the working directory that are not versioned or
 
226
        control files or ignored.
 
227
        
 
228
        >>> from bzrlib.workingtree import WorkingTree
 
229
        >>> b = ScratchBranch(files=['foo', 'foo~'])
 
230
        >>> map(str, b.unknowns())
 
231
        ['foo']
 
232
        >>> b.add('foo')
 
233
        >>> list(b.unknowns())
 
234
        []
 
235
        >>> WorkingTree(b.base, b).remove('foo')
 
236
        >>> list(b.unknowns())
 
237
        [u'foo']
 
238
        """
 
239
        raise NotImplementedError('unknowns is abstract')
 
240
 
 
241
    def append_revision(self, *revision_ids):
 
242
        raise NotImplementedError('append_revision is abstract')
 
243
 
 
244
    def set_revision_history(self, rev_history):
 
245
        raise NotImplementedError('set_revision_history is abstract')
 
246
 
 
247
    def get_revision_delta(self, revno):
 
248
        """Return the delta for one revision.
 
249
 
 
250
        The delta is relative to its mainline predecessor, or the
 
251
        empty tree for revision 1.
 
252
        """
 
253
        assert isinstance(revno, int)
 
254
        rh = self.revision_history()
 
255
        if not (1 <= revno <= len(rh)):
 
256
            raise InvalidRevisionNumber(revno)
 
257
 
 
258
        # revno is 1-based; list is 0-based
 
259
 
 
260
        new_tree = self.revision_tree(rh[revno-1])
 
261
        if revno == 1:
 
262
            old_tree = EmptyTree()
 
263
        else:
 
264
            old_tree = self.revision_tree(rh[revno-2])
 
265
 
 
266
        return compare_trees(old_tree, new_tree)
 
267
 
 
268
    def get_ancestry(self, revision_id):
 
269
        """Return a list of revision-ids integrated by a revision.
 
270
        
 
271
        This currently returns a list, but the ordering is not guaranteed:
 
272
        treat it as a set.
 
273
        """
 
274
        raise NotImplementedError('get_ancestry is abstract')
 
275
 
 
276
    def revision_history(self):
 
277
        """Return sequence of revision hashes on to this branch."""
 
278
        raise NotImplementedError('revision_history is abstract')
 
279
 
 
280
    def revno(self):
 
281
        """Return current revision number for this branch.
 
282
 
 
283
        That is equivalent to the number of revisions committed to
 
284
        this branch.
 
285
        """
 
286
        return len(self.revision_history())
 
287
 
 
288
    def last_revision(self):
 
289
        """Return last patch hash, or None if no history."""
 
290
        ph = self.revision_history()
 
291
        if ph:
 
292
            return ph[-1]
 
293
        else:
 
294
            return None
 
295
 
 
296
    def missing_revisions(self, other, stop_revision=None, diverged_ok=False):
 
297
        """Return a list of new revisions that would perfectly fit.
 
298
        
 
299
        If self and other have not diverged, return a list of the revisions
 
300
        present in other, but missing from self.
 
301
 
 
302
        >>> from bzrlib.commit import commit
 
303
        >>> bzrlib.trace.silent = True
 
304
        >>> br1 = ScratchBranch()
 
305
        >>> br2 = ScratchBranch()
 
306
        >>> br1.missing_revisions(br2)
 
307
        []
 
308
        >>> commit(br2, "lala!", rev_id="REVISION-ID-1")
 
309
        >>> br1.missing_revisions(br2)
 
310
        [u'REVISION-ID-1']
 
311
        >>> br2.missing_revisions(br1)
 
312
        []
 
313
        >>> commit(br1, "lala!", rev_id="REVISION-ID-1")
 
314
        >>> br1.missing_revisions(br2)
 
315
        []
 
316
        >>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
 
317
        >>> br1.missing_revisions(br2)
 
318
        [u'REVISION-ID-2A']
 
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.
 
323
        """
 
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)
 
332
 
 
333
        if stop_revision is None:
 
334
            stop_revision = other_len
 
335
        else:
 
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]
 
340
 
 
341
    
 
342
    def update_revisions(self, other, stop_revision=None):
 
343
        """Pull in new perfect-fit revisions."""
 
344
        raise NotImplementedError('update_revisions is abstract')
 
345
 
 
346
    def pullable_revisions(self, other, stop_revision):
 
347
        raise NotImplementedError('pullable_revisions is abstract')
 
348
        
 
349
    def commit(self, *args, **kw):
 
350
        raise NotImplementedError('commit is abstract')
 
351
    
 
352
    def revision_id_to_revno(self, revision_id):
 
353
        """Given a revision id, return its revno"""
 
354
        if revision_id is None:
 
355
            return 0
 
356
        history = self.revision_history()
 
357
        try:
 
358
            return history.index(revision_id) + 1
 
359
        except ValueError:
 
360
            raise bzrlib.errors.NoSuchRevision(self, revision_id)
 
361
 
 
362
    def get_rev_id(self, revno, history=None):
 
363
        """Find the revision id of the specified revno."""
 
364
        if revno == 0:
 
365
            return None
 
366
        if history is None:
 
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]
 
371
 
 
372
    def working_tree(self):
 
373
        """Return a `Tree` for the working copy."""
 
374
        raise NotImplementedError('working_tree is abstract')
 
375
 
 
376
    def pull(self, source, overwrite=False):
 
377
        raise NotImplementedError('pull is abstract')
 
378
 
 
379
    def basis_tree(self):
 
380
        """Return `Tree` object for last revision.
 
381
 
 
382
        If there are no revisions yet, return an `EmptyTree`.
 
383
        """
 
384
        return self.storage.revision_tree(self.last_revision())
 
385
 
 
386
    def rename_one(self, from_rel, to_rel):
 
387
        """Rename one file.
 
388
 
 
389
        This can change the directory or the filename or both.
 
390
        """
 
391
        raise NotImplementedError('rename_one is abstract')
 
392
 
 
393
    def move(self, from_paths, to_name):
 
394
        """Rename files.
 
395
 
 
396
        to_name must exist as a versioned directory.
 
397
 
 
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, 
 
400
 
 
401
        Note that to_name is only the last component of the new name;
 
402
        this doesn't change the directory.
 
403
 
 
404
        This returns a list of (from_path, to_path) pairs for each
 
405
        entry that is moved.
 
406
        """
 
407
        raise NotImplementedError('move is abstract')
 
408
 
 
409
    def revert(self, filenames, old_tree=None, backups=True):
 
410
        """Restore selected files to the versions from a previous tree.
 
411
 
 
412
        backups
 
413
            If true (default) backups are made of files before
 
414
            they're renamed.
 
415
        """
 
416
        raise NotImplementedError('revert is abstract')
 
417
 
 
418
    def pending_merges(self):
 
419
        """Return a list of pending merges.
 
420
 
 
421
        These are revisions that have been merged into the working
 
422
        directory but not yet committed.
 
423
        """
 
424
        raise NotImplementedError('pending_merges is abstract')
 
425
 
 
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')
 
430
 
 
431
    def set_pending_merges(self, rev_list):
 
432
        raise NotImplementedError('set_pending_merges is abstract')
 
433
 
 
434
    def get_parent(self):
 
435
        """Return the parent location of the branch.
 
436
 
 
437
        This is the default location for push/pull/missing.  The usual
 
438
        pattern is that the user can override it by specifying a
 
439
        location.
 
440
        """
 
441
        raise NotImplementedError('get_parent is abstract')
 
442
 
 
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')
 
446
 
 
447
    def set_push_location(self, location):
 
448
        """Set a new push location for this branch."""
 
449
        raise NotImplementedError('set_push_location is abstract')
 
450
 
 
451
    def set_parent(self, url):
 
452
        raise NotImplementedError('set_parent is abstract')
 
453
 
 
454
    def check_revno(self, revno):
 
455
        """\
 
456
        Check whether a revno corresponds to any revision.
 
457
        Zero (the NULL revision) is considered valid.
 
458
        """
 
459
        if revno != 0:
 
460
            self.check_real_revno(revno)
 
461
            
 
462
    def check_real_revno(self, revno):
 
463
        """\
 
464
        Check whether a revno corresponds to a real revision.
 
465
        Zero (the NULL revision) is considered invalid
 
466
        """
 
467
        if revno < 1 or revno > self.revno():
 
468
            raise InvalidRevisionNumber(revno)
 
469
        
 
470
    def sign_revision(self, revision_id, gpg_strategy):
 
471
        raise NotImplementedError('sign_revision is abstract')
 
472
 
 
473
    def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
 
474
        raise NotImplementedError('store_revision_signature is abstract')
 
475
 
 
476
 
 
477
class BzrBranch(Branch, ControlFiles):
168
478
    """A branch stored in the actual filesystem.
169
479
 
170
480
    Note that it's "local" in the context of the filesystem; it doesn't
184
494
    REVISION_NAMESPACES = {}
185
495
 
186
496
    def push_stores(self, branch_to):
187
 
        """Copy the content of this branches store to branch_to."""
 
497
        """See Branch.push_stores."""
188
498
        if (self._branch_format != branch_to._branch_format
189
499
            or self._branch_format != 4):
190
500
            from bzrlib.fetch import greedy_fetch
256
566
    base = property(_get_base, doc="The URL for the root of this branch.")
257
567
 
258
568
    def abspath(self, name):
259
 
        """Return absolute filename for something in the branch
260
 
        
261
 
        XXX: Robert Collins 20051017 what is this used for? why is it a branch
262
 
        method and not a tree method.
263
 
        """
 
569
        """See Branch.abspath."""
264
570
        return self._transport.abspath(name)
265
571
 
266
572
    def _make_control(self):
327
633
                            ' and "bzr init" again'])
328
634
 
329
635
    def get_root_id(self):
330
 
        """Return the id of this branches root"""
 
636
        """See Branch.get_root_id."""
331
637
        inv = self.storage.get_inventory(self.last_revision())
332
638
        return inv.root.file_id
333
639
 
345
651
 
346
652
    @needs_write_lock
347
653
    def set_root_id(self, file_id):
 
654
        """See Branch.set_root_id."""
348
655
        inv = self.working_tree().read_working_inventory()
349
656
        orig_root_id = inv.root.file_id
350
657
        del inv._byid[inv.root.file_id]
374
681
            
375
682
    @needs_write_lock
376
683
    def add(self, files, ids=None):
377
 
        """Make files versioned.
378
 
 
379
 
        Note that the command line normally calls smart_add instead,
380
 
        which can automatically recurse.
381
 
 
382
 
        This puts the files in the Added state, so that they will be
383
 
        recorded by the next commit.
384
 
 
385
 
        files
386
 
            List of paths to add, relative to the base of the tree.
387
 
 
388
 
        ids
389
 
            If set, use these instead of automatically generated ids.
390
 
            Must be the same length as the list of files, but may
391
 
            contain None for ids that are to be autogenerated.
392
 
 
393
 
        TODO: Perhaps have an option to add the ids even if the files do
394
 
              not (yet) exist.
395
 
 
396
 
        TODO: Perhaps yield the ids and paths as they're added.
397
 
        """
 
684
        """See Branch.add."""
398
685
        # TODO: Re-adding a file that is removed in the working copy
399
686
        # should probably put it back with the previous ID.
400
687
        if isinstance(files, basestring):
440
727
 
441
728
    @needs_read_lock
442
729
    def print_file(self, file, revno):
443
 
        """Print `file` to stdout."""
 
730
        """See Branch.print_file."""
444
731
        return self.storage.print_file(file, self.get_rev_id(revno))
445
732
 
446
733
    def unknowns(self):
447
 
        """Return all unknown files.
448
 
 
449
 
        These are files in the working directory that are not versioned or
450
 
        control files or ignored.
451
 
        
452
 
        >>> from bzrlib.workingtree import WorkingTree
453
 
        >>> b = ScratchBranch(files=['foo', 'foo~'])
454
 
        >>> map(str, b.unknowns())
455
 
        ['foo']
456
 
        >>> b.add('foo')
457
 
        >>> list(b.unknowns())
458
 
        []
459
 
        >>> WorkingTree(b.base, b).remove('foo')
460
 
        >>> list(b.unknowns())
461
 
        [u'foo']
462
 
        """
 
734
        """See Branch.unknowns."""
463
735
        return self.working_tree().unknowns()
464
736
 
465
737
    @needs_write_lock
466
738
    def append_revision(self, *revision_ids):
 
739
        """See Branch.append_revision."""
467
740
        for revision_id in revision_ids:
468
741
            mutter("add {%s} to revision-history" % revision_id)
469
742
        rev_history = self.revision_history()
472
745
 
473
746
    @needs_write_lock
474
747
    def set_revision_history(self, rev_history):
 
748
        """See Branch.set_revision_history."""
475
749
        self.put_controlfile('revision-history', '\n'.join(rev_history))
476
750
 
477
751
    def get_revision_delta(self, revno):
496
770
        return compare_trees(old_tree, new_tree)
497
771
 
498
772
    def get_ancestry(self, revision_id):
499
 
        """Return a list of revision-ids integrated by a revision.
500
 
        
501
 
        This currently returns a list, but the ordering is not guaranteed:
502
 
        treat it as a set.
503
 
        """
 
773
        """See Branch.get_ancestry."""
504
774
        if revision_id is None:
505
775
            return [None]
506
776
        w = self.storage.get_inventory_weave()
509
779
 
510
780
    @needs_read_lock
511
781
    def revision_history(self):
512
 
        """Return sequence of revision hashes on to this branch."""
 
782
        """See Branch.revision_history."""
513
783
        transaction = self.get_transaction()
514
784
        history = transaction.map.find_revision_history()
515
785
        if history is not None:
523
793
        # transaction.register_clean(history, precious=True)
524
794
        return list(history)
525
795
 
526
 
    def revno(self):
527
 
        """Return current revision number for this branch.
528
 
 
529
 
        That is equivalent to the number of revisions committed to
530
 
        this branch.
531
 
        """
532
 
        return len(self.revision_history())
533
 
 
534
 
    def last_revision(self):
535
 
        """Return last patch hash, or None if no history.
536
 
        """
537
 
        ph = self.revision_history()
538
 
        if ph:
539
 
            return ph[-1]
540
 
        else:
541
 
            return None
542
 
 
543
 
    def missing_revisions(self, other, stop_revision=None, diverged_ok=False):
544
 
        """Return a list of new revisions that would perfectly fit.
545
 
        
546
 
        If self and other have not diverged, return a list of the revisions
547
 
        present in other, but missing from self.
548
 
 
549
 
        >>> from bzrlib.commit import commit
550
 
        >>> bzrlib.trace.silent = True
551
 
        >>> br1 = ScratchBranch()
552
 
        >>> br2 = ScratchBranch()
553
 
        >>> br1.missing_revisions(br2)
554
 
        []
555
 
        >>> commit(br2, "lala!", rev_id="REVISION-ID-1")
556
 
        >>> br1.missing_revisions(br2)
557
 
        [u'REVISION-ID-1']
558
 
        >>> br2.missing_revisions(br1)
559
 
        []
560
 
        >>> commit(br1, "lala!", rev_id="REVISION-ID-1")
561
 
        >>> br1.missing_revisions(br2)
562
 
        []
563
 
        >>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
564
 
        >>> br1.missing_revisions(br2)
565
 
        [u'REVISION-ID-2A']
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.
570
 
        """
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)
579
 
 
580
 
        if stop_revision is None:
581
 
            stop_revision = other_len
582
 
        else:
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]
587
 
 
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()
601
809
            self.append_revision(*pullable_revs)
602
810
 
603
811
    def pullable_revisions(self, other, stop_revision):
 
812
        """See Branch.pullable_revisions."""
604
813
        other_revno = other.revision_id_to_revno(stop_revision)
605
814
        try:
606
815
            return self.missing_revisions(other, other_revno)
618
827
                    raise e
619
828
        
620
829
    def commit(self, *args, **kw):
 
830
        """See Branch.commit."""
621
831
        from bzrlib.commit import Commit
622
832
        Commit().commit(self, *args, **kw)
623
833
    
624
 
    def revision_id_to_revno(self, revision_id):
625
 
        """Given a revision id, return its revno"""
626
 
        if revision_id is None:
627
 
            return 0
628
 
        history = self.revision_history()
629
 
        try:
630
 
            return history.index(revision_id) + 1
631
 
        except ValueError:
632
 
            raise bzrlib.errors.NoSuchRevision(self, revision_id)
633
 
 
634
 
    def get_rev_id(self, revno, history=None):
635
 
        """Find the revision id of the specified revno."""
636
 
        if revno == 0:
637
 
            return None
638
 
        if history is None:
639
 
            history = self.revision_history()
640
 
        elif revno <= 0 or revno > len(history):
641
 
            raise bzrlib.errors.NoSuchRevision(self, revno)
642
 
        return history[revno - 1]
643
 
 
644
834
    def working_tree(self):
645
 
        """Return a `Tree` for the working copy."""
 
835
        """See Branch.working_tree."""
646
836
        from bzrlib.workingtree import WorkingTree
647
837
        # TODO: In the future, perhaps WorkingTree should utilize Transport
648
838
        # RobertCollins 20051003 - I don't think it should - working trees are
655
845
 
656
846
    @needs_write_lock
657
847
    def pull(self, source, overwrite=False):
 
848
        """See Branch.pull."""
658
849
        source.lock_read()
659
850
        try:
660
851
            try:
666
857
        finally:
667
858
            source.unlock()
668
859
 
669
 
    def basis_tree(self):
670
 
        """Return `Tree` object for last revision.
671
 
 
672
 
        If there are no revisions yet, return an `EmptyTree`.
673
 
        """
674
 
        return self.storage.revision_tree(self.last_revision())
675
 
 
676
860
    @needs_write_lock
677
861
    def rename_one(self, from_rel, to_rel):
678
 
        """Rename one file.
679
 
 
680
 
        This can change the directory or the filename or both.
681
 
        """
 
862
        """See Branch.rename_one."""
682
863
        tree = self.working_tree()
683
864
        inv = tree.inventory
684
865
        if not tree.has_filename(from_rel):
720
901
 
721
902
    @needs_write_lock
722
903
    def move(self, from_paths, to_name):
723
 
        """Rename files.
724
 
 
725
 
        to_name must exist as a versioned directory.
726
 
 
727
 
        If to_name exists and is a directory, the files are moved into
728
 
        it, keeping their old names.  If it is a directory, 
729
 
 
730
 
        Note that to_name is only the last component of the new name;
731
 
        this doesn't change the directory.
732
 
 
733
 
        This returns a list of (from_path, to_path) pairs for each
734
 
        entry that is moved.
735
 
        """
 
904
        """See Branch.move."""
736
905
        result = []
737
906
        ## TODO: Option to move IDs only
738
907
        assert not isinstance(from_paths, basestring)
785
954
 
786
955
 
787
956
    def revert(self, filenames, old_tree=None, backups=True):
788
 
        """Restore selected files to the versions from a previous tree.
789
 
 
790
 
        backups
791
 
            If true (default) backups are made of files before
792
 
            they're renamed.
793
 
        """
 
957
        """See Branch.revert."""
794
958
        from bzrlib.atomicfile import AtomicFile
795
959
        from bzrlib.osutils import backup_file
796
960
        
828
992
 
829
993
 
830
994
    def pending_merges(self):
831
 
        """Return a list of pending merges.
832
 
 
833
 
        These are revisions that have been merged into the working
834
 
        directory but not yet committed.
835
 
        """
 
995
        """See Branch.pending_merges."""
836
996
        cfn = self._rel_controlfilename('pending-merges')
837
997
        if not self._transport.has(cfn):
838
998
            return []
843
1003
 
844
1004
 
845
1005
    def add_pending_merge(self, *revision_ids):
 
1006
        """See Branch.add_pending_merge."""
846
1007
        # TODO: Perhaps should check at this point that the
847
1008
        # history of the revision is actually present?
848
1009
        p = self.pending_merges()
857
1018
 
858
1019
    @needs_write_lock
859
1020
    def set_pending_merges(self, rev_list):
 
1021
        """See Branch.set_pending_merges."""
860
1022
        self.put_controlfile('pending-merges', '\n'.join(rev_list))
861
1023
 
862
1024
    def get_parent(self):
863
 
        """Return the parent location of the branch.
864
 
 
865
 
        This is the default location for push/pull/missing.  The usual
866
 
        pattern is that the user can override it by specifying a
867
 
        location.
868
 
        """
 
1025
        """See Branch.get_parent."""
869
1026
        import errno
870
1027
        _locs = ['parent', 'pull', 'x-pull']
871
1028
        for l in _locs:
877
1034
        return None
878
1035
 
879
1036
    def get_push_location(self):
880
 
        """Return the None or the location to push this branch to."""
 
1037
        """See Branch.get_push_location."""
881
1038
        config = bzrlib.config.BranchConfig(self)
882
1039
        push_loc = config.get_user_option('push_location')
883
1040
        return push_loc
884
1041
 
885
1042
    def set_push_location(self, location):
886
 
        """Set a new push location for this branch."""
 
1043
        """See Branch.set_push_location."""
887
1044
        config = bzrlib.config.LocationConfig(self.base)
888
1045
        config.set_user_option('push_location', location)
889
1046
 
890
1047
    @needs_write_lock
891
1048
    def set_parent(self, url):
 
1049
        """See Branch.set_parent."""
892
1050
        # TODO: Maybe delete old location files?
893
1051
        from bzrlib.atomicfile import AtomicFile
894
1052
        f = AtomicFile(self.controlfilename('parent'))
919
1077
        
920
1078
 
921
1079
 
922
 
class ScratchBranch(_Branch):
 
1080
class ScratchBranch(BzrBranch):
923
1081
    """Special test class: a branch that cleans up after itself.
924
1082
 
925
1083
    >>> b = ScratchBranch()