=== removed file 'bzrlib/clone.py'
--- bzrlib/clone.py	
+++ /dev/null	
@@ -1,162 +0,0 @@
-# Copyright (C) 2004, 2005 by Canonical Ltd
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-"""Make a copy of an entire branch and all its history.
-
-This is the underlying function for the branch/get/clone commands."""
-
-# TODO: This could be done *much* more efficiently by just copying
-# all the whole weaves and revisions, rather than getting one
-# revision at a time.
-
-# TODO: Optionally, after copying, discard any irrelevant information from
-# the destination, such as revisions committed after the last one we're interested 
-# in.  This needs to apply a weave prune operation (not written yet) to each
-# weave one by one.
-
-# Copying must be done in a way that supports http transports, where we
-# can't list a directory, and therefore have to rely on information
-# retrieved from top-level objects whose names we do know.
-#
-# In practice this means we first fetch the revision history and ancestry.
-# These give us a list of all the revisions that need to be fetched.  We 
-# also get the inventory weave.  We then just need to get a list of all 
-# file-ids ever referenced by this tree.  (It might be nice to keep a list
-# of them directly.)  This is done by walking over the inventories of all
-# copied revisions and accumulating a list of file ids.
-#
-# For local branches it is possible to optimize this considerably in two
-# ways.  One is to hardlink the files (if possible and requested), rather
-# than copying them.  Another is to simply list the directory rather than
-# walking through the inventories to find out what files are present -- but
-# there it may be better to just be consistent with remote branches.
-
-import os
-import sys
-
-import bzrlib
-from bzrlib.merge import build_working_dir
-from bzrlib.branch import Branch
-from bzrlib.trace import mutter, note
-from bzrlib.store import copy_all
-from bzrlib.errors import InvalidRevisionId
-
-def copy_branch(branch_from, to_location, revision=None, basis_branch=None):
-    """Copy branch_from into the existing directory to_location.
-
-    Returns the newly created branch object.
-
-    revision
-        If not None, only revisions up to this point will be copied.
-        The head of the new branch will be that revision.  Must be a
-        revid or None.
-
-    to_location -- The destination directory; must either exist and be 
-        empty, or not exist, in which case it is created.
-
-    basis_branch
-        A local branch to copy revisions from, related to branch_from. 
-        This is used when branching from a remote (slow) branch, and we have
-        a local branch that might contain some relevant revisions.
-    """
-    assert isinstance(branch_from, Branch)
-    assert isinstance(to_location, basestring)
-    if basis_branch is not None:
-        note("basis_branch is not supported for fast weave copy yet.")
-    branch_from.lock_read()
-    try:
-        if not (branch_from.storage.weave_store.listable()
-                and branch_from.storage.revision_store.listable()):
-            return copy_branch_slower(branch_from, to_location, revision,
-                                      basis_branch)
-        history = _get_truncated_history(branch_from, revision)
-        if not bzrlib.osutils.lexists(to_location):
-            os.mkdir(to_location)
-        branch_to = Branch.initialize(to_location)
-        mutter("copy branch from %s to %s", branch_from, branch_to)
-        branch_to.working_tree().set_root_id(branch_from.get_root_id())
-        branch_to.append_revision(*history)
-        _copy_control_weaves(branch_from, branch_to)
-        _copy_text_weaves(branch_from, branch_to)
-        _copy_revision_store(branch_from, branch_to)
-        build_working_dir(to_location)
-        branch_to.set_parent(branch_from.base)
-        mutter("copied")
-        return branch_to
-    finally:
-        branch_from.unlock()
-
-
-def _get_truncated_history(branch_from, revision_id):
-    history = branch_from.revision_history()
-    if revision_id is None:
-        return history
-    try:
-        idx = history.index(revision_id)
-    except ValueError:
-        raise InvalidRevisionId(revision_id=revision, branch=branch_from)
-    return history[:idx+1]
-
-def _copy_text_weaves(branch_from, branch_to):
-    copy_all(branch_from.storage.weave_store, branch_to.storage.weave_store)
-
-
-def _copy_revision_store(branch_from, branch_to):
-    copy_all(branch_from.storage.revision_store, 
-             branch_to.storage.revision_store)
-
-
-def _copy_control_weaves(branch_from, branch_to):
-    to_control = branch_to.storage.control_weaves
-    from_control = branch_from.storage.control_weaves
-    to_control.copy_multi(from_control, ['inventory'])
-
-    
-def copy_branch_slower(branch_from, to_location, revision=None, basis_branch=None):
-    """Copy branch_from into the existing directory to_location.
-
-    revision
-        If not None, only revisions up to this point will be copied.
-        The head of the new branch will be that revision.  Must be a
-        revid or None.
-
-    to_location -- The destination directory; must either exist and be 
-        empty, or not exist, in which case it is created.
-
-    revno
-        The revision to copy up to
-
-    basis_branch
-        A local branch to copy revisions from, related to branch_from. 
-        This is used when branching from a remote (slow) branch, and we have
-        a local branch that might contain some relevant revisions.
-    """
-    assert isinstance(branch_from, Branch)
-    assert isinstance(to_location, basestring)
-    if not bzrlib.osutils.lexists(to_location):
-        os.mkdir(to_location)
-    br_to = Branch.initialize(to_location)
-    mutter("copy branch from %s to %s", branch_from, br_to)
-    if basis_branch is not None:
-        basis_branch.push_stores(br_to)
-    br_to.working_tree().set_root_id(branch_from.get_root_id())
-    if revision is None:
-        revision = branch_from.last_revision()
-    br_to.update_revisions(branch_from, stop_revision=revision)
-    build_working_dir(to_location)
-    br_to.set_parent(branch_from.base)
-    mutter("copied")
-    return br_to

=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py	
+++ bzrlib/branch.py	
@@ -462,6 +462,45 @@
     def store_revision_signature(self, gpg_strategy, plaintext, revision_id):
         raise NotImplementedError('store_revision_signature is abstract')
 
+    def clone(self, to_location, revision=None, basis_branch=None, to_branch_type=None):
+        """Copy this branch into the existing directory to_location.
+
+        Returns the newly created branch object.
+
+        revision
+            If not None, only revisions up to this point will be copied.
+            The head of the new branch will be that revision.  Must be a
+            revid or None.
+    
+        to_location -- The destination directory; must either exist and be 
+            empty, or not exist, in which case it is created.
+    
+        basis_branch
+            A local branch to copy revisions from, related to this branch. 
+            This is used when branching from a remote (slow) branch, and we have
+            a local branch that might contain some relevant revisions.
+    
+        to_branch_type
+            Branch type of destination branch
+        """
+        assert isinstance(to_location, basestring)
+        if not bzrlib.osutils.lexists(to_location):
+            os.mkdir(to_location)
+        if to_branch_type is None:
+            to_branch_type = BzrBranch
+        br_to = to_branch_type.initialize(to_location)
+        mutter("copy branch from %s to %s", self, br_to)
+        if basis_branch is not None:
+            basis_branch.push_stores(br_to)
+        br_to.working_tree().set_root_id(self.get_root_id())
+        if revision is None:
+            revision = self.last_revision()
+        br_to.update_revisions(self, stop_revision=revision)
+        from bzrlib.merge import build_working_dir
+        build_working_dir(to_location)
+        br_to.set_parent(self.base)
+        mutter("copied")
+        return br_to
 
 class BzrBranch(Branch, LockableFiles):
     """A branch stored in the actual filesystem.
@@ -966,8 +1005,49 @@
         """
         if revno < 1 or revno > self.revno():
             raise InvalidRevisionNumber(revno)
-        
-
+
+    def _get_truncated_history(self, revision_id):
+        history = self.revision_history()
+        if revision_id is None:
+            return history
+        try:
+            idx = history.index(revision_id)
+        except ValueError:
+            raise InvalidRevisionId(revision_id=revision, branch=self)
+        return history[:idx+1]
+
+    @needs_read_lock
+    def _clone_weave(self, to_location, revision=None, basis_branch=None):
+        assert isinstance(to_location, basestring)
+        if basis_branch is not None:
+            note("basis_branch is not supported for fast weave copy yet.")
+
+        history = self._get_truncated_history(revision)
+        if not bzrlib.osutils.lexists(to_location):
+            os.mkdir(to_location)
+        branch_to = Branch.initialize(to_location)
+        mutter("copy branch from %s to %s", self, branch_to)
+        branch_to.working_tree().set_root_id(self.get_root_id())
+        branch_to.append_revision(*history)
+
+        self.storage.copy(branch_to.storage)
+        
+        from bzrlib.merge import build_working_dir
+        build_working_dir(to_location)
+        branch_to.set_parent(self.base)
+        mutter("copied")
+        return branch_to
+
+    def clone(self, to_location, revision=None, basis_branch=None, to_branch_type=None):
+        if to_branch_type is None:
+            to_branch_type = BzrBranch
+
+        if to_branch_type == BzrBranch \
+            and self.storage.weave_store.listable() \
+            and self.storage.revision_store.listable():
+            return self._clone_weave(to_location, revision, basis_branch)
+
+        return Branch.clone(self, to_location, revision, basis_branch, to_branch_type)
 
 class ScratchBranch(BzrBranch):
     """Special test class: a branch that cleans up after itself.

=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py	
+++ bzrlib/builtins.py	
@@ -511,7 +511,6 @@
     aliases = ['get', 'clone']
 
     def run(self, from_location, to_location=None, revision=None, basis=None):
-        from bzrlib.clone import copy_branch
         import errno
         from shutil import rmtree
         if revision is None:
@@ -554,7 +553,7 @@
                 else:
                     raise
             try:
-                copy_branch(br_from, to_location, revision_id, basis_branch)
+                br_from.clone(to_location, revision_id, basis_branch)
             except bzrlib.errors.NoSuchRevision:
                 rmtree(to_location)
                 msg = "The branch %s has no revision %s." % (from_location, revision[0])

=== modified file 'bzrlib/repository.py'
--- bzrlib/repository.py	
+++ bzrlib/repository.py	
@@ -18,6 +18,7 @@
 from bzrlib.revision import NULL_REVISION
 from bzrlib.store.weave import WeaveStore
 from bzrlib.store.text import TextStore
+from bzrlib.store import copy_all
 from cStringIO import StringIO
 import bzrlib.xml5
 from bzrlib.tree import RevisionTree
@@ -95,6 +96,12 @@
     def unlock(self):
         self.control_files.unlock()
 
+    def copy(self, destination):
+        destination.control_weaves.copy_multi(self.control_weaves, 
+                ['inventory'])
+        copy_all(self.weave_store, destination.weave_store)
+        copy_all(self.revision_store, destination.revision_store)
+
     def has_revision(self, revision_id):
         """True if this branch has a copy of the revision.
 

=== modified file 'bzrlib/selftest/blackbox.py'
--- bzrlib/selftest/blackbox.py	
+++ bzrlib/selftest/blackbox.py	
@@ -36,7 +36,6 @@
 import sys
 
 from bzrlib.branch import Branch
-from bzrlib.clone import copy_branch
 from bzrlib.errors import BzrCommandError
 from bzrlib.osutils import has_symlinks
 from bzrlib.selftest import TestCaseInTempDir, BzrTestBase
@@ -356,7 +355,7 @@
         branch = Branch.initialize('branch1')
         branch.add(['file'])
         branch.working_tree().commit('add file')
-        copy_branch(branch, 'branch2')
+        branch.clone('branch2')
         print >> open('branch2/file', 'w'), 'new content'
         branch2 = Branch.open('branch2')
         branch2.working_tree().commit('update file')
@@ -1270,7 +1269,7 @@
         url = self.get_remote_url('branch/file')
         output = self.capture('log %s' % url)
         self.assertEqual(8, len(output.split('\n')))
-        copy = copy_branch(branch, 'branch2')
+        copy = branch.clone('branch2')
         branch.working_tree().commit(message='empty commit')
         os.chdir('branch2')
         self.run_bzr('merge', '../branch')

=== modified file 'bzrlib/selftest/test_merge_core.py'
--- bzrlib/selftest/test_merge_core.py	
+++ bzrlib/selftest/test_merge_core.py	
@@ -16,7 +16,6 @@
                                BackupBeforeChange, ExecFlagMerge, WeaveMerge)
 from bzrlib.changeset import Inventory, apply_changeset, invert_dict, \
     get_contents, ReplaceContents, ChangeExecFlag
-from bzrlib.clone import copy_branch
 from bzrlib.merge import merge
 
 
@@ -531,7 +530,6 @@
     def test_trivial_star_merge(self):
         """Test that merges in a star shape Just Work.""" 
         from bzrlib.add import smart_add_branch, add_reporter_null
-        from bzrlib.clone import copy_branch
         from bzrlib.merge import merge
         # John starts a branch
         self.build_tree(("original/", "original/file1", "original/file2"))
@@ -540,7 +538,7 @@
         branch.working_tree().commit("start branch.", verbose=False)
         # Mary branches it.
         self.build_tree(("mary/",))
-        copy_branch(branch, "mary")
+        branch.clone("mary")
         # Now John commits a change
         file = open("original/file1", "wt")
         file.write("John\n")
@@ -570,7 +568,7 @@
         file('a/file', 'wb').write('contents\n')
         a.add('file')
         a.working_tree().commit('base revision', allow_pointless=False)
-        b = copy_branch(a, 'b')
+        b = a.clone('b')
         file('a/file', 'wb').write('other contents\n')
         a.working_tree().commit('other revision', allow_pointless=False)
         file('b/file', 'wb').write('this contents contents\n')
@@ -635,7 +633,7 @@
         a.add('file')
         a_wt = a.working_tree()
         a_wt.commit('r0')
-        copy_branch(a, 'b')
+        a.clone('b')
         b = Branch.open('b')
         b_wt = b.working_tree()
         os.chmod('b/file', 0755)

=== modified file 'bzrlib/selftest/test_parent.py'
--- bzrlib/selftest/test_parent.py	
+++ bzrlib/selftest/test_parent.py	
@@ -18,7 +18,6 @@
 import os
 from bzrlib.selftest import TestCaseInTempDir
 from bzrlib.branch import Branch
-from bzrlib.clone import copy_branch
 
 
 """Tests for Branch parent URL"""
@@ -49,7 +48,7 @@
         branch_from.working_tree().commit('initial commit')
         
         os.mkdir('to')
-        copy_branch(branch_from, 'to', None)
+        branch_from.clone('to', None)
 
         branch_to = Branch.open('to')
         abspath = os.path.abspath('from')

=== modified file 'bzrlib/selftest/testannotate.py'
--- bzrlib/selftest/testannotate.py	
+++ bzrlib/selftest/testannotate.py	
@@ -31,7 +31,6 @@
 import os
 
 from bzrlib.branch import Branch
-from bzrlib.clone import copy_branch
 from bzrlib.errors import BzrCommandError
 from bzrlib.osutils import has_symlinks
 from bzrlib.selftest import TestCaseInTempDir, BzrTestBase

=== modified file 'bzrlib/selftest/testbranch.py'
--- bzrlib/selftest/testbranch.py	
+++ bzrlib/selftest/testbranch.py	
@@ -17,7 +17,6 @@
 import os
 
 from bzrlib.branch import Branch, needs_read_lock, needs_write_lock
-from bzrlib.clone import copy_branch
 from bzrlib.commit import commit
 import bzrlib.errors as errors
 from bzrlib.errors import NoSuchRevision, UnlistableBranch, NotBranchError
@@ -104,15 +103,15 @@
                 tree.get_file(file_id).read()
         return br_a, br_b
 
-    def test_copy_branch(self):
+    def test_clone_branch(self):
         """Copy the stores from one branch to another"""
         br_a, br_b = self.get_balanced_branch_pair()
         commit(br_b, "silly commit")
         os.mkdir('c')
-        br_c = copy_branch(br_a, 'c', basis_branch=br_b)
+        br_c = br_a.clone('c', basis_branch=br_b)
         self.assertEqual(br_a.revision_history(), br_c.revision_history())
 
-    def test_copy_partial(self):
+    def test_clone_partial(self):
         """Copy only part of the history of a branch."""
         self.build_tree(['a/', 'a/one'])
         br_a = Branch.initialize('a')
@@ -121,7 +120,7 @@
         self.build_tree(['a/two'])
         br_a.add(['two'])
         br_a.working_tree().commit('commit two', rev_id='u@d-2')
-        br_b = copy_branch(br_a, 'b', revision='u@d-1')
+        br_b = br_a.clone('b', revision='u@d-1')
         self.assertEqual(br_b.last_revision(), 'u@d-1')
         self.assertTrue(os.path.exists('b/one'))
         self.assertFalse(os.path.exists('b/two'))

=== modified file 'bzrlib/selftest/testfetch.py'
--- bzrlib/selftest/testfetch.py	
+++ bzrlib/selftest/testfetch.py	
@@ -23,7 +23,6 @@
 from bzrlib.branch import Branch
 from bzrlib.fetch import greedy_fetch
 from bzrlib.merge import merge
-from bzrlib.clone import copy_branch
 
 from bzrlib.selftest import TestCaseInTempDir
 from bzrlib.selftest.HTTPTestUtil import TestCaseWithWebserver
@@ -128,7 +127,7 @@
         os.mkdir('br1')
         br1 = Branch.initialize('br1')
         br1.working_tree().commit(message='rev 1-1', rev_id='1-1')
-        copy_branch(br1, 'br2')
+        br1.clone('br2')
         br2 = Branch.open('br2')
         br1.working_tree().commit(message='rev 1-2', rev_id='1-2')
         br2.working_tree().commit(message='rev 2-1', rev_id='2-1')
@@ -153,7 +152,7 @@
         self.build_tree_contents([('br1/file', 'original contents\n')])
         br1.add(['file'], ['this-file-id'])
         br1.working_tree().commit(message='rev 1-1', rev_id='1-1')
-        copy_branch(br1, 'br2')
+        br1.clone('br2')
         br2 = Branch.open('br2')
         self.build_tree_contents([('br1/file', 'original from 1\n')])
         br1.working_tree().commit(message='rev 1-2', rev_id='1-2')

=== modified file 'bzrlib/selftest/testinv.py'
--- bzrlib/selftest/testinv.py	
+++ bzrlib/selftest/testinv.py	
@@ -18,7 +18,6 @@
 import os
 
 from bzrlib.branch import Branch
-from bzrlib.clone import copy_branch
 import bzrlib.errors as errors
 from bzrlib.diff import internal_diff
 from bzrlib.inventory import Inventory, ROOT_ID

=== modified file 'bzrlib/selftest/testrevisionnamespaces.py'
--- bzrlib/selftest/testrevisionnamespaces.py	
+++ bzrlib/selftest/testrevisionnamespaces.py	
@@ -21,7 +21,6 @@
 from bzrlib.selftest import TestCaseInTempDir
 from bzrlib.errors import NoCommonAncestor, NoCommits
 from bzrlib.errors import NoSuchRevision
-from bzrlib.clone import copy_branch
 from bzrlib.merge import merge
 from bzrlib.revisionspec import RevisionSpec
 
@@ -69,7 +68,7 @@
         self.assertRaises(NoCommits, RevisionSpec('ancestor:.').in_history, b2)
 
         os.mkdir('copy')
-        b3 = copy_branch(b, 'copy')
+        b3 = b.clone('copy')
         b3.working_tree().commit('Commit four', rev_id='b@r-0-4')
         self.assertEquals(RevisionSpec('ancestor:.').in_history(b3).rev_id,
                           'a@r-0-3')
@@ -86,7 +85,7 @@
         branch = Branch.initialize('branch1')
         branch.add(['file'])
         branch.working_tree().commit('add file')
-        copy_branch(branch, 'branch2')
+        branch.clone('branch2')
         print >> open('branch2/file', 'w'), 'new content'
         branch2 = Branch.open('branch2')
         branch2.working_tree().commit('update file', rev_id='A')

=== modified file 'bzrlib/selftest/teststatus.py'
--- bzrlib/selftest/teststatus.py	
+++ bzrlib/selftest/teststatus.py	
@@ -28,7 +28,6 @@
 from bzrlib.status import show_status
 from bzrlib.branch import Branch
 from os import mkdir
-from bzrlib.clone import copy_branch
 
 class BranchStatus(TestCaseInTempDir):
     
@@ -107,7 +106,7 @@
         mkdir("./branch")
         b = Branch.initialize('./branch')
         b.working_tree().commit("Empty commit 1")
-        b_2 = copy_branch(b, './copy')
+        b_2 = b.clone('./copy')
         b.working_tree().commit("Empty commit 2")
         merge(["./branch", -1], [None, None], this_dir = './copy')
         message = self.status_string(b_2)

