[MERGE] Re: "update -r REVNO" support
Robert Widhopf-Fenk
hack at robf.de
Fri Aug 10 19:56:55 BST 2007
So here is am update which addresses the issued which
remained unsolved before ...
- A working tree test
- Documentation for the to_revision parameter
- Getting the last revision of a branch just once for status
Robert.
-------------- next part --------------
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: hack at robf.de-20070810185038-npyxf7u76hswoj27
# target_branch: file:///home/fenk/download/bzr.repo/bzr.dev/
# testament_sha1: 48db04c43a8bf6d803e33e2e1faf0ff2b900e73f
# timestamp: 2007-08-10 20:52:52 +0200
# base_revision_id: pqm at pqm.ubuntu.com-20070810111627-h6m8b0ist3ca15ae
#
# Begin patch
=== modified file 'NEWS'
--- NEWS 2007-08-10 10:00:53 +0000
+++ NEWS 2007-08-10 18:50:38 +0000
@@ -112,6 +112,13 @@
* Log errors from the smart server in the trace file, to make debugging
test failures (and live failures!) easier. (Andrew Bennetts)
+
+ * For an out dated working tree, display its revno and number of missing
+ revisions. (Robert Widhopf-Fenk)
+
+ * ``bzr update`` has -r now, i.e. you may update your working tree to
+ other/older revisions than head while retaining your changes. (Robert
+ Widhopf-Fenk)
* The HTML version of the man page has been superceded by a more
comprehensive manual called the Bazaar User Reference. This manual
=== modified file 'bzrlib/branch.py'
--- bzrlib/branch.py 2007-07-27 13:02:00 +0000
+++ bzrlib/branch.py 2007-08-08 02:01:49 +0000
@@ -222,6 +222,15 @@
# modify the return value.
return mapping
+ def revision_id_to_dotted_revno(self, revision_id):
+ """Given a revision id, return its dotted revno"""
+ try:
+ return self.revision_id_to_revno(
+ _mod_revision.ensure_null(revision_id))
+ except errors.NoSuchRevision:
+ dotted_map = self.get_revision_id_to_revno_map()
+ return '.'.join(str(i) for i in dotted_map[revision_id])
+
def _gen_revno_map(self):
"""Create a new mapping from revision ids to dotted revnos.
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2007-08-09 15:19:06 +0000
+++ bzrlib/builtins.py 2007-08-10 18:50:38 +0000
@@ -1005,18 +1005,27 @@
"""Update a tree to have the latest code committed to its branch.
This will perform a merge into the working tree, and may generate
- conflicts. If you have any local changes, you will still
- need to commit them after the update for the update to be complete.
+ conflicts. If you have any local changes, you will still need to
+ commit them after the update for the update to be complete.
If you want to discard your local changes, you can just do a
'bzr revert' instead of 'bzr commit' after the update.
+
+ If you give a --revision parameter, your working tree will be updated
+ to the given revision. Your working tree will be out of date if the
+ given revision is not the latest revision of the branch and thus you
+ cannot commit to the branch anymore.
+
+ Use 'bzr status' to check if the branch is outdated and 'bzr update'
+ to be able to commit again.
"""
_see_also = ['pull', 'working-trees', 'status-flags']
takes_args = ['dir?']
+ takes_options = ['revision']
aliases = ['up']
-
- def run(self, dir='.'):
+
+ def run(self, revision=None, dir='.'):
tree = WorkingTree.open_containing(dir)[0]
master = tree.branch.get_master_branch()
if master is not None:
@@ -1024,21 +1033,39 @@
else:
tree.lock_tree_write()
try:
+ branch_rev = _mod_revision.ensure_null(tree.branch.last_revision())
+ if revision:
+ if len(revision) > 1:
+ raise errors.BzrCommandError(
+ 'bzr update --revision takes exactly 1 revision value')
+ to_rev = _mod_revision.ensure_null(
+ revision[0].in_history(tree.branch)[1])
+ revision = to_rev
+ else:
+ to_rev = branch_rev
existing_pending_merges = tree.get_parent_ids()[1:]
- last_rev = _mod_revision.ensure_null(tree.last_revision())
- if last_rev == _mod_revision.ensure_null(
- tree.branch.last_revision()):
+ last_rev = _mod_revision.ensure_null(tree.last_revision())
+ if last_rev == to_rev:
# may be up to date, check master too.
if master is None or last_rev == _mod_revision.ensure_null(
master.last_revision()):
- revno = tree.branch.revision_id_to_revno(last_rev)
- note("Tree is up to date at revision %d." % (revno,))
+ note("Tree is up to date at revision %s." %
+ (tree.branch.revision_id_to_revno(last_rev),))
return 0
+ # we use "revision" here instead of to_rev as in lightweighted
+ # checkouts the revision may change due to an update of the
+ # related branch.
conflicts = tree.update(delta._ChangeReporter(
- unversioned_filter=tree.is_ignored))
- revno = tree.branch.revision_id_to_revno(
- _mod_revision.ensure_null(tree.last_revision()))
- note('Updated to revision %d.' % (revno,))
+ unversioned_filter=tree.is_ignored),
+ revision)
+ # get the last revision again as it might have changed
+ last_rev = tree.last_revision()
+ if branch_rev == to_rev:
+ note('Updated to revision %s.' %
+ (tree.branch.revision_id_to_dotted_revno(last_rev),))
+ else:
+ warning('Updated to out of date revision %s.' %
+ (tree.branch.revision_id_to_dotted_revno(last_rev),))
if tree.get_parent_ids()[1:] != existing_pending_merges:
note('Your local commits will now show as pending merges with '
"'bzr status', and can be committed with 'bzr commit'.")
=== modified file 'bzrlib/revision.py'
--- bzrlib/revision.py 2007-08-09 03:39:31 +0000
+++ bzrlib/revision.py 2007-08-10 18:50:38 +0000
@@ -490,7 +490,7 @@
def ensure_null(revision_id):
- """Ensure only NULL_REVISION is used to represent the null revisionn"""
+ """Ensure only NULL_REVISION is used to represent the null revision"""
if revision_id is None:
return NULL_REVISION
else:
=== modified file 'bzrlib/status.py'
--- bzrlib/status.py 2007-07-23 14:27:42 +0000
+++ bzrlib/status.py 2007-08-08 02:34:13 +0000
@@ -121,8 +121,15 @@
try:
new_is_working_tree = True
if revision is None:
- if wt.last_revision() != wt.branch.last_revision():
- warning("working tree is out of date, run 'bzr update'")
+ b_rev_id = wt.branch.last_revision()
+ wt_rev_id = wt.last_revision()
+ if wt_rev_id != b_rev_id:
+ revid_to_revno = wt.branch.get_revision_id_to_revno_map()
+ warning("Working tree is out of date.")
+ warning("Working revision: %s" %
+ (wt.branch.revision_id_to_dotted_revno(wt_rev_id),))
+ warning("Branch revision: %s" %
+ (wt.branch.revision_id_to_dotted_revno(b_rev_id),))
new = wt
old = new.basis_tree()
elif len(revision) > 0:
=== modified file 'bzrlib/tests/blackbox/test_update.py'
--- bzrlib/tests/blackbox/test_update.py 2007-07-04 08:46:22 +0000
+++ bzrlib/tests/blackbox/test_update.py 2007-08-10 17:53:09 +0000
@@ -196,7 +196,7 @@
# merges, because they were real merges
out, err = self.run_bzr('update')
self.assertEqual('', out)
- self.assertEndsWith(err, 'All changes applied successfully.\n'
+ self.assertContainsRe(err, 'All changes applied successfully.\n'
'Updated to revision 2.\n')
self.assertContainsRe(err, r'\+N file3')
# The pending merges should still be there
@@ -210,3 +210,49 @@
lightweight=True)
tree.commit('empty commit')
self.run_bzr('update checkout')
+
+ def test_update_r1(self):
+ """Update a checkout from revision 2 to revision 1"""
+ self.make_branch_and_tree('branch')
+ # make a checkout
+ self.run_bzr('checkout --lightweight branch checkout')
+ self.build_tree(['checkout/file1'])
+ self.run_bzr('add checkout/file1')
+ self.run_bzr('commit -m add-file1 checkout')
+ self.build_tree(['checkout/file2'])
+ self.run_bzr('add checkout/file2')
+ self.run_bzr('commit -m add-file2 checkout')
+ out, err = self.run_bzr('update -r 1 checkout')
+ self.assertEqual('', out)
+ self.assertEqual(err, '-D file2\n'
+ 'All changes applied successfully.\n'
+ 'Updated to out of date revision 1.\n')
+ self.failUnlessExists('checkout/file1')
+ self.failIfExists('checkout/file2')
+
+ def test_update_r1_with_modifications(self):
+ """Update a checkout from revision 2 to revision 1 with changes"""
+ self.make_branch_and_tree('branch')
+ # make a checkout
+ self.run_bzr('checkout --lightweight branch checkout')
+ self.build_tree(['checkout/file1'])
+ self.run_bzr('add checkout/file1')
+ self.run_bzr('commit -m add-file1 checkout')
+ self.build_tree(['checkout/file2'])
+ self.run_bzr('add checkout/file2')
+ self.run_bzr('commit -m add-file2 checkout')
+ os.chdir('checkout')
+ a_file = file('file1', 'wt')
+ a_file.write('FooChanges\n')
+ a_file.close()
+ out, err = self.run_bzr('update -r 1')
+ self.assertEqual('', out)
+ self.assertEqual(err, '-D file2\n'
+ 'All changes applied successfully.\n'
+ 'Updated to out of date revision 1.\n')
+ self.failUnlessExists('file1')
+ self.failIfExists('file2')
+ out, err = self.run_bzr('diff', retcode=1)
+ self.assertContainsRe(out, '\n\\+FooChanges\n')
+ self.assertEqual(err, '')
+
=== modified file 'bzrlib/tests/workingtree_implementations/test_workingtree.py'
--- bzrlib/tests/workingtree_implementations/test_workingtree.py 2007-07-20 20:27:07 +0000
+++ bzrlib/tests/workingtree_implementations/test_workingtree.py 2007-08-10 18:48:59 +0000
@@ -471,6 +471,30 @@
self.assertEqual(wt.get_root_id(), checkout.get_root_id())
self.assertNotEqual(None, wt.get_root_id())
+ def test_update_r(self):
+ """Ensure "update -r" works.
+ """
+ wt = self.make_branch_and_tree('tree')
+ main_branch = wt.branch
+ # create an branch with two files and two revisions
+ self.build_tree(['tree/file1'])
+ wt.add('file1')
+ wt.commit('A', rev_id='A')
+ self.build_tree(['tree/file2'])
+ # now commit to 'tree'
+ wt.add('file2')
+ wt.commit('B', rev_id='B')
+ # create an checkout and ensure it is up to date
+ checkout = main_branch.create_checkout('checkout')
+ self.assertEqual('B', checkout.last_revision())
+ self.failUnlessExists('checkout/file1')
+ self.failUnlessExists('checkout/file2')
+ # and update checkout to revision 'A'
+ self.assertEqual(0, checkout.update(to_revision='A'))
+ self.assertEqual('A', checkout.last_revision())
+ self.failUnlessExists('checkout/file1')
+ self.failIfExists('checkout/file2')
+
def test_update_returns_conflict_count(self):
# working tree formats from the meta-dir format and newer support
# setting the last revision on a tree independently of that on the
=== modified file 'bzrlib/workingtree.py'
--- bzrlib/workingtree.py 2007-08-01 18:23:29 +0000
+++ bzrlib/workingtree.py 2007-08-10 18:50:38 +0000
@@ -2004,7 +2004,7 @@
"""
raise NotImplementedError(self.unlock)
- def update(self, change_reporter=None):
+ def update(self, change_reporter=None, to_revision=None):
"""Update a working tree along its branch.
This will update the branch if its bound too, which means we have
@@ -2028,6 +2028,9 @@
- Merge current state -> basis tree of the master w.r.t. the old tree
basis.
- Do a 'normal' merge of the old branch basis if it is relevant.
+
+ :param to_revision: if supplied, the revision id to update the
+ tree to, otherwise update to the head revision of the branch.
"""
if self.branch.get_master_branch() is not None:
self.lock_write()
@@ -2040,16 +2043,19 @@
old_tip = self.branch.update()
else:
old_tip = None
- return self._update_tree(old_tip, change_reporter)
+ return self._update_tree(old_tip, change_reporter, to_revision)
finally:
self.unlock()
@needs_tree_write_lock
- def _update_tree(self, old_tip=None, change_reporter=None):
+ def _update_tree(self, old_tip=None, change_reporter=None,
+ to_revision_id=None):
"""Update a tree to the master branch.
:param old_tip: if supplied, the previous tip revision the branch,
before it was changed to the master branch's tip.
+ :param to_revision_id: if supplied, the revision id to update the
+ tree to, otherwise update to the head revision of the branch.
"""
# here if old_tip is not None, it is the old tip of the branch before
# it was updated from the master branch. This should become a pending
@@ -2066,12 +2072,15 @@
last_rev = self.get_parent_ids()[0]
except IndexError:
last_rev = _mod_revision.NULL_REVISION
- if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
+ to_rev = to_revision_id
+ if to_rev is None:
+ to_rev = self.branch.last_revision()
+ if last_rev != _mod_revision.ensure_null(to_rev):
# merge tree state up to new branch tip.
basis = self.basis_tree()
basis.lock_read()
try:
- to_tree = self.branch.basis_tree()
+ to_tree = self.branch.repository.revision_tree(to_rev)
if basis.inventory.root is None:
self.set_root_id(to_tree.inventory.root.file_id)
self.flush()
@@ -2099,6 +2108,7 @@
parent_trees.append(
(old_tip, self.branch.repository.revision_tree(old_tip)))
self.set_parent_trees(parent_trees)
+ self.set_last_revision(to_rev)
last_rev = parent_trees[0][0]
else:
# the working tree had the same last-revision as the master
# Begin bundle
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
More information about the bazaar
mailing list