[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