"update -r REVNO" support
Robert Widhopf-Fenk
hack at robf.de
Sat Aug 4 03:16:39 BST 2007
Hi,
"revert -r" was not enough for me, so I tried to implement
"update -r" and better "bzr st" for outdated working trees.
;-)
Robert.
-------------- next part --------------
# Bazaar merge directive format 2 (Bazaar 0.19)
# revision_id: hack at robf.de-20070804020549-fqaszg0ddxizsqm7
# target_branch: file:///home/fenk/download/bzr.repo/bzr.dev/
# testament_sha1: a25381b23592bbcff486c0cdb00a13422253e109
# timestamp: 2007-08-04 04:09:14 +0200
# base_revision_id: pqm at pqm.ubuntu.com-20070803043116-l7u1uypblmx1uxnr
#
# Begin patch
=== modified file 'NEWS'
--- NEWS 2007-08-02 07:22:05 +0000
+++ NEWS 2007-08-04 00:41:50 +0000
@@ -109,7 +109,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)
LIBRARY API BREAKS:
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2007-07-31 20:02:47 +0000
+++ bzrlib/builtins.py 2007-08-04 02:05:49 +0000
@@ -1013,9 +1013,10 @@
_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:
@@ -1023,10 +1024,18 @@
else:
tree.lock_tree_write()
try:
+ if revision:
+ if len(revision) > 1:
+ raise errors.BzrCommandError(
+ 'bzr update --revision takes exactly 1 revision value')
+ branch_location = osutils.getcwd()
+ source = Branch.open(branch_location)
+ to_rev = _mod_revision.ensure_null(revision[0].in_history(source)[1])
+ else:
+ to_rev = _mod_revision.ensure_null(tree.branch.last_revision())
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()):
@@ -1034,7 +1043,8 @@
note("Tree is up to date at revision %d." % (revno,))
return 0
conflicts = tree.update(delta._ChangeReporter(
- unversioned_filter=tree.is_ignored))
+ unversioned_filter=tree.is_ignored),
+ revision and to_rev or None)
revno = tree.branch.revision_id_to_revno(
_mod_revision.ensure_null(tree.last_revision()))
note('Updated to revision %d.' % (revno,))
=== modified file 'bzrlib/status.py'
--- bzrlib/status.py 2007-07-23 14:27:42 +0000
+++ bzrlib/status.py 2007-08-04 00:14:16 +0000
@@ -122,7 +122,12 @@
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_revno = wt.branch.last_revision_info()[0]
+ wt_revno = wt.branch.revision_id_to_revno(wt.last_revision())
+ missing = b_revno - wt_revno
+ warning("Working tree is at revno %d missing %d revision%s!" %
+ (wt_revno, missing,
+ (missing > 1) and "s" or ""))
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-04 01:53:59 +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')
+ os.chdir('checkout')
+ out, err = self.run_bzr('update -r 1')
+ self.assertEqual('', out)
+ self.assertEqual(err, '-D file2\n'
+ 'All changes applied successfully.\n'
+ 'Updated to revision 1.\n')
+ self.failUnlessExists('file1')
+ self.failIfExists('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 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/workingtree.py'
--- bzrlib/workingtree.py 2007-07-25 21:25:00 +0000
+++ bzrlib/workingtree.py 2007-08-04 02:05:49 +0000
@@ -2001,7 +2001,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
@@ -2037,12 +2037,12 @@
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=None):
"""Update a tree to the master branch.
:param old_tip: if supplied, the previous tip revision the branch,
@@ -2063,12 +2063,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
+ if to_rev is None:
+ to_rev = _mod_revision.ensure_null(self.branch.last_revision())
+ if last_rev != 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()
@@ -2096,6 +2099,8 @@
parent_trees.append(
(old_tip, self.branch.repository.revision_tree(old_tip)))
self.set_parent_trees(parent_trees)
+ if to_revision is not None:
+ self.set_parent_ids([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