[Pkg-bazaar-commits] ./bzr/unstable r628: - merge aaron's updated merge/pull code

Martin Pool mbp at sourcefrog.net
Fri Apr 10 08:20:29 UTC 2009


------------------------------------------------------------
revno: 628
committer: Martin Pool <mbp at sourcefrog.net>
timestamp: Mon 2005-06-06 21:53:29 +1000
message:
  - merge aaron's updated merge/pull code
modified:
  bzrlib/branch.py
  bzrlib/commands.py
  bzrlib/merge.py
  testbzr
-------------- next part --------------
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2005-06-06 04:17:53 +0000
+++ b/bzrlib/branch.py	2005-06-06 11:53:29 +0000
@@ -104,7 +104,11 @@
             raise BzrError('%r is not in a branch' % orig_f)
         f = head
     
-
+class DivergedBranches(Exception):
+    def __init__(self, branch1, branch2):
+        self.branch1 = branch1
+        self.branch2 = branch2
+        Exception.__init__(self, "These branches have diverged.")
 
 ######################################################################
 # branch objects
@@ -650,6 +654,94 @@
             return None
 
 
+    def missing_revisions(self, other):
+        """
+        If self and other have not diverged, return a list of the revisions
+        present in other, but missing from self.
+
+        >>> from bzrlib.commit import commit
+        >>> bzrlib.trace.silent = True
+        >>> br1 = ScratchBranch()
+        >>> br2 = ScratchBranch()
+        >>> br1.missing_revisions(br2)
+        []
+        >>> commit(br2, "lala!", rev_id="REVISION-ID-1")
+        >>> br1.missing_revisions(br2)
+        [u'REVISION-ID-1']
+        >>> br2.missing_revisions(br1)
+        []
+        >>> commit(br1, "lala!", rev_id="REVISION-ID-1")
+        >>> br1.missing_revisions(br2)
+        []
+        >>> commit(br2, "lala!", rev_id="REVISION-ID-2A")
+        >>> br1.missing_revisions(br2)
+        [u'REVISION-ID-2A']
+        >>> commit(br1, "lala!", rev_id="REVISION-ID-2B")
+        >>> br1.missing_revisions(br2)
+        Traceback (most recent call last):
+        DivergedBranches: These branches have diverged.
+        """
+        self_history = self.revision_history()
+        self_len = len(self_history)
+        other_history = other.revision_history()
+        other_len = len(other_history)
+        common_index = min(self_len, other_len) -1
+        if common_index >= 0 and \
+            self_history[common_index] != other_history[common_index]:
+            raise DivergedBranches(self, other)
+        if self_len < other_len:
+            return other_history[self_len:]
+        return []
+
+
+    def update_revisions(self, other):
+        """If self and other have not diverged, ensure self has all the
+        revisions in other
+
+        >>> from bzrlib.commit import commit
+        >>> bzrlib.trace.silent = True
+        >>> br1 = ScratchBranch(files=['foo', 'bar'])
+        >>> br1.add('foo')
+        >>> br1.add('bar')
+        >>> commit(br1, "lala!", rev_id="REVISION-ID-1", verbose=False)
+        >>> br2 = ScratchBranch()
+        >>> br2.update_revisions(br1)
+        Added 2 texts.
+        Added 1 inventories.
+        Added 1 revisions.
+        >>> br2.revision_history()
+        [u'REVISION-ID-1']
+        >>> br2.update_revisions(br1)
+        Added 0 texts.
+        Added 0 inventories.
+        Added 0 revisions.
+        >>> br1.text_store.total_size() == br2.text_store.total_size()
+        True
+        """
+        revision_ids = self.missing_revisions(other)
+        revisions = [other.get_revision(f) for f in revision_ids]
+        needed_texts = sets.Set()
+        for rev in revisions:
+            inv = other.get_inventory(str(rev.inventory_id))
+            for key, entry in inv.iter_entries():
+                if entry.text_id is None:
+                    continue
+                if entry.text_id not in self.text_store:
+                    needed_texts.add(entry.text_id)
+        count = self.text_store.copy_multi(other.text_store, needed_texts)
+        print "Added %d texts." % count 
+        inventory_ids = [ f.inventory_id for f in revisions ]
+        count = self.inventory_store.copy_multi(other.inventory_store, 
+                                                inventory_ids)
+        print "Added %d inventories." % count 
+        revision_ids = [ f.revision_id for f in revisions]
+        count = self.revision_store.copy_multi(other.revision_store, 
+                                               revision_ids)
+        for revision_id in revision_ids:
+            self.append_revision(revision_id)
+        print "Added %d revisions." % count
+                    
+        
     def commit(self, *args, **kw):
         """Deprecated"""
         from bzrlib.commit import commit

=== modified file 'bzrlib/commands.py'
--- a/bzrlib/commands.py	2005-06-06 04:17:53 +0000
+++ b/bzrlib/commands.py	2005-06-06 11:53:29 +0000
@@ -384,6 +384,111 @@
 
 
 
+
+
+class cmd_pull(Command):
+    """Pull any changes from another branch into the current one.
+
+    If the location is omitted, the last-used location will be used.
+    Both the revision history and the working directory will be
+    updated.
+
+    This command only works on branches that have not diverged.  Branches are
+    considered diverged if both branches have had commits without first
+    pulling from the other.
+
+    If branches have diverged, you can use 'bzr merge' to pull the text changes
+    from one into the other.
+    """
+    takes_args = ['location?']
+
+    def run(self, location=None):
+        from bzrlib.merge import merge
+        import errno
+        
+        br_to = Branch('.')
+        stored_loc = None
+        try:
+            stored_loc = br_to.controlfile("x-pull", "rb").read().rstrip('\n')
+        except IOError, e:
+            if errno == errno.ENOENT:
+                raise
+        if location is None:
+            location = stored_loc
+        if location is None:
+            raise BzrCommandError("No pull location known or specified.")
+        from branch import find_branch, DivergedBranches
+        br_from = find_branch(location)
+        location = pull_loc(br_from)
+        old_revno = br_to.revno()
+        try:
+            br_to.update_revisions(br_from)
+        except DivergedBranches:
+            raise BzrCommandError("These branches have diverged.  Try merge.")
+            
+        merge(('.', -1), ('.', old_revno))
+        if location != stored_loc:
+            br_to.controlfile("x-pull", "wb").write(location + "\n")
+
+
+
+class cmd_branch(Command):
+    """Create a new copy of a branch.
+
+    If the TO_LOCATION is omitted, the last component of the
+    FROM_LOCATION will be used.  In other words,
+    "branch ../foo/bar" will attempt to create ./bar.
+    """
+    takes_args = ['from_location', 'to_location?']
+
+    def run(self, from_location, to_location=None):
+        import errno
+        from bzrlib.merge import merge
+        
+        if to_location is None:
+            to_location = os.path.basename(from_location)
+            # FIXME: If there's a trailing slash, keep removing them
+            # until we find the right bit
+
+        try:
+            os.mkdir(to_location)
+        except OSError, e:
+            if e.errno == errno.EEXIST:
+                raise BzrCommandError('Target directory "%s" already exists.' %
+                                      to_location)
+            if e.errno == errno.ENOENT:
+                raise BzrCommandError('Parent of "%s" does not exist.' %
+                                      to_location)
+            else:
+                raise
+        br_to = Branch(to_location, init=True)
+        from branch import find_branch, DivergedBranches
+        try:
+            br_from = find_branch(from_location)
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                raise BzrCommandError('Source location "%s" does not exist.' %
+                                      to_location)
+            else:
+                raise
+
+        from_location = pull_loc(br_from)
+        br_to.update_revisions(br_from)
+        merge((to_location, -1), (to_location, 0), this_dir=to_location,
+              check_clean=False)
+        br_to.controlfile("x-pull", "wb").write(from_location + "\n")
+
+
+def pull_loc(branch):
+    # TODO: Should perhaps just make attribute be 'base' in
+    # RemoteBranch and Branch?
+    if hasattr(branch, "baseurl"):
+        return branch.baseurl
+    else:
+        return branch.base
+
+
+
 class cmd_renames(Command):
     """Show list of renamed files.
 
@@ -991,6 +1096,8 @@
         parsed = [spec, None]
     return parsed
 
+
+
 class cmd_merge(Command):
     """Perform a three-way merge of trees.
     
@@ -1009,24 +1116,33 @@
     The OTHER_SPEC parameter is required.  If the BASE_SPEC parameter is
     not supplied, the common ancestor of OTHER_SPEC the current branch is used
     as the BASE.
+
+    merge refuses to run if there are any uncommitted changes, unless
+    --force is given.
     """
     takes_args = ['other_spec', 'base_spec?']
+    takes_options = ['force']
 
-    def run(self, other_spec, base_spec=None):
+    def run(self, other_spec, base_spec=None, force=False):
         from bzrlib.merge import merge
-        merge(parse_spec(other_spec), parse_spec(base_spec))
+        merge(parse_spec(other_spec), parse_spec(base_spec),
+              check_clean=(not force))
 
 
 class cmd_revert(Command):
-    """
-    Reverse all changes since the last commit.  Only versioned files are
-    affected.
+    """Reverse all changes since the last commit.
+
+    Only versioned files are affected.
+
+    TODO: Store backups of any files that will be reverted, so
+          that the revert can be undone.          
     """
     takes_options = ['revision']
 
     def run(self, revision=-1):
-        merge.merge(('.', revision), parse_spec('.'), no_changes=False,
-                    ignore_zero=True)
+        merge(('.', revision), parse_spec('.'),
+              check_clean=False,
+              ignore_zero=True)
 
 
 class cmd_assert_fail(Command):
@@ -1068,6 +1184,7 @@
     'diff-options':           str,
     'help':                   None,
     'file':                   unicode,
+    'force':                  None,
     'forward':                None,
     'message':                unicode,
     'no-recurse':             None,

=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2005-06-06 04:17:53 +0000
+++ b/bzrlib/merge.py	2005-06-06 11:53:29 +0000
@@ -155,11 +155,29 @@
                 self.cached[id] = path
             return self.cached[id]
 
-def merge(other_revision, base_revision, no_changes=True, ignore_zero=False):
+
+
+def merge(other_revision, base_revision,
+          check_clean=True, ignore_zero=False,
+          this_dir=None):
+    """Merge changes into a tree.
+
+    base_revision
+        Base for three-way merge.
+    other_revision
+        Other revision for three-way merge.
+    this_dir
+        Directory to merge changes into; '.' by default.
+    check_clean
+        If true, this_dir must have no uncommitted changes before the
+        merge begins.
+    """
     tempdir = tempfile.mkdtemp(prefix="bzr-")
     try:
-        this_branch = find_branch('.') 
-        if no_changes:
+        if this_dir is None:
+            this_dir = '.'
+        this_branch = find_branch(this_dir)
+        if check_clean:
             changes = compare_trees(this_branch.working_tree(), 
                                     this_branch.basis_tree(), False)
             if changes.has_changed():
@@ -208,7 +226,7 @@
 
 def merge_inner(this_branch, other_tree, base_tree, tempdir, 
                 ignore_zero=False):
-    this_tree = get_tree(('.', None), tempdir, "this")[1]
+    this_tree = get_tree((this_branch.base, None), tempdir, "this")[1]
 
     def get_inventory(tree):
         return tree.inventory

=== modified file 'testbzr'
--- a/testbzr	2005-06-06 05:13:21 +0000
+++ b/testbzr	2005-06-06 11:53:29 +0000
@@ -353,6 +353,28 @@
 
     cd('..')
     cd('..')
+    progress('branch')
+    # Can't create a branch if it already exists
+    runcmd('bzr branch branch1', retcode=1)
+    # Can't create a branch if its parent doesn't exist
+    runcmd('bzr branch /unlikely/to/exist', retcode=1)
+    runcmd('bzr branch branch1 branch2')
+
+    progress("pull")
+    cd('branch1')
+    runcmd('bzr pull', retcode=1)
+    runcmd('bzr pull ../branch2')
+    cd('.bzr')
+    runcmd('bzr pull')
+    runcmd('bzr commit -m empty')
+    runcmd('bzr pull')
+    cd('../../branch2')
+    runcmd('bzr pull')
+    runcmd('bzr commit -m empty')
+    cd('../branch1')
+    runcmd('bzr commit -m empty')
+    runcmd('bzr pull', retcode=1)
+    cd ('..')
 
     progress('status after remove')
     mkdir('status-after-remove')



More information about the Pkg-bazaar-commits mailing list