Merge lp:~mhammond/bzr/update-r into lp:~bzr/bzr/trunk-old

Proposed by Mark Hammond
Status: Superseded
Proposed branch: lp:~mhammond/bzr/update-r
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 336 lines (has conflicts)
Text conflict in NEWS
Text conflict in bzrlib/builtins.py
To merge this branch: bzr merge lp:~mhammond/bzr/update-r

This proposal has been superseded by a proposal from 2009-06-02.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2009-03-24 12:15:01 +0000
+++ NEWS 2009-03-24 21:35:49 +0000
@@ -1,5 +1,6 @@
1====================1====================
2Bazaar Release Notes2Bazaar Release Notes
3<<<<<<< TREE
3====================4====================
45
56
@@ -1944,6 +1945,68 @@
1944* Fix a regression in knit => pack fetching. We had a logic1945* Fix a regression in knit => pack fetching. We had a logic
1945 inversion, causing the fetch to insert fulltexts in random order,1946 inversion, causing the fetch to insert fulltexts in random order,
1946 rather than preserving deltas. (John Arbash Meinel, #256757)1947 rather than preserving deltas. (John Arbash Meinel, #256757)
1948=======
1949--------------------
1950
1951.. contents::
1952
1953IN DEVELOPMENT
1954--------------
1955
1956 CHANGES:
1957
1958 * ``bzr export`` can now export a subdirectory of a project.
1959 (Robert Collins)
1960
1961 * ``bzr rm`` will now scan for files that are missing and remove just
1962 them automatically, much as ``bzr add`` scans for new files that
1963 are not ignored and adds them automatically. (Robert Collins)
1964
1965 IMPROVEMENTS:
1966
1967 * ``bzr init`` and ``bzr init-repo`` will now print out the same as
1968 ``bzr info`` if it completed successfully.
1969 (Marius Kruger)
1970
1971 * ``bzr uncommit`` logs the old tip revision id, and displays how to
1972 restore the branch to that tip using ``bzr pull``. This allows you
1973 to recover if you realize you uncommitted the wrong thing.
1974 (John Arbash Meinel)
1975
1976 * ``bzr update`` now takes a ``--revision`` argument. This lets you
1977 change the revision of the working tree to any revision in the
1978 ancestry of the current or master branch. (Matthieu Moy, #45719)
1979
1980 BUG FIXES:
1981
1982 * ``bzr rm`` is now aliased to ``bzr del`` for the convenience of svn
1983 users. (Robert Collins, #205416)
1984
1985 * ``WorkingTree4`` trees will now correctly report missing-and-new
1986 paths in the output of ``iter_changes``. (Robert Collins)
1987
1988 API CHANGES:
1989
1990 * Exporters now take 4 parameters. (Robert Collins)
1991
1992 * ``Tree.iter_changes`` will now return False for the content change
1993 field when a file is missing in the basis tree and not present in
1994 the target tree. Previously it returned True unconditionally.
1995 (Robert Collins)
1996
1997 TESTING:
1998
1999 * ``addCleanup`` now takes ``*arguments`` and ``**keyword_arguments``
2000 which are then passed to the cleanup callable as it is run. In
2001 addition, addCleanup no longer requires that the callables passed to
2002 it be unique. (Jonathan Lange)
2003
2004 INTERNALS:
2005
2006 * ``bzrlib.diff.DiffTree.show_diff`` now skips changes where the kind
2007 is unknown in both source and target.
2008 (Robert Collins, Aaron Bentley)
2009>>>>>>> MERGE-SOURCE
19472010
19482011
1949bzr 1.6rc3 2008-08-142012bzr 1.6rc3 2008-08-14
19502013
=== modified file 'bzrlib/builtins.py'
--- bzrlib/builtins.py 2009-03-24 12:15:01 +0000
+++ bzrlib/builtins.py 2009-03-24 21:35:49 +0000
@@ -1239,12 +1239,17 @@
12391239
1240 _see_also = ['pull', 'working-trees', 'status-flags']1240 _see_also = ['pull', 'working-trees', 'status-flags']
1241 takes_args = ['dir?']1241 takes_args = ['dir?']
1242 takes_options = ['revision']
1242 aliases = ['up']1243 aliases = ['up']
12431244
1244 def run(self, dir='.'):1245 def run(self, dir='.', revision=None):
1246 if revision is not None and len(revision) != 1:
1247 raise errors.BzrCommandError(
1248 "bzr update --revision takes exactly one revision")
1245 tree = WorkingTree.open_containing(dir)[0]1249 tree = WorkingTree.open_containing(dir)[0]
1250 branch = tree.branch
1246 possible_transports = []1251 possible_transports = []
1247 master = tree.branch.get_master_branch(1252 master = branch.get_master_branch(
1248 possible_transports=possible_transports)1253 possible_transports=possible_transports)
1249 if master is not None:1254 if master is not None:
1250 tree.lock_write()1255 tree.lock_write()
@@ -1252,6 +1257,7 @@
1252 tree.lock_tree_write()1257 tree.lock_tree_write()
1253 try:1258 try:
1254 existing_pending_merges = tree.get_parent_ids()[1:]1259 existing_pending_merges = tree.get_parent_ids()[1:]
1260<<<<<<< TREE
1255 last_rev = _mod_revision.ensure_null(tree.last_revision())1261 last_rev = _mod_revision.ensure_null(tree.last_revision())
1256 if last_rev == _mod_revision.ensure_null(1262 if last_rev == _mod_revision.ensure_null(
1257 tree.branch.last_revision()):1263 tree.branch.last_revision()):
@@ -1267,6 +1273,44 @@
1267 view_info=view_info), possible_transports=possible_transports)1273 view_info=view_info), possible_transports=possible_transports)
1268 revno = tree.branch.revision_id_to_revno(1274 revno = tree.branch.revision_id_to_revno(
1269 _mod_revision.ensure_null(tree.last_revision()))1275 _mod_revision.ensure_null(tree.last_revision()))
1276=======
1277 # potentially get new revisions from the master branch.
1278 # needed for the case where -r N is given, with N not yet
1279 # in the local branch for a heavyweight checkout.
1280 if revision is not None:
1281 try:
1282 rev = revision[0].in_history(branch).rev_id
1283 # no need to run branch.update()
1284 old_tip = None
1285 except (errors.NoSuchRevision, errors.InvalidRevisionSpec):
1286 # revision was not there, but is maybe in the master.
1287 old_tip = branch.update(possible_transports)
1288 rev = revision[0].in_history(branch).rev_id
1289 else:
1290 if master is None:
1291 old_tip = None
1292 else:
1293 old_tip = branch.update(possible_transports)
1294 rev = branch.last_revision()
1295 if rev == _mod_revision.ensure_null(tree.last_revision()):
1296 revno = branch.revision_id_to_revno(rev)
1297 note("Tree is up to date at revision %d." % (revno,))
1298 return 0
1299 try:
1300 conflicts = tree.update(
1301 delta._ChangeReporter(unversioned_filter=tree.is_ignored),
1302 possible_transports=possible_transports,
1303 revision=rev,
1304 old_tip=old_tip)
1305 except errors.NoSuchRevision, e:
1306 raise errors.BzrCommandError(
1307 "branch has no revision %s\n"
1308 "bzr update --revision only works"
1309 " for a revision in the branch history"
1310 % (e.revision))
1311 revno = branch.revision_id_to_revno(
1312 _mod_revision.ensure_null(rev))
1313>>>>>>> MERGE-SOURCE
1270 note('Updated to revision %d.' % (revno,))1314 note('Updated to revision %d.' % (revno,))
1271 if tree.get_parent_ids()[1:] != existing_pending_merges:1315 if tree.get_parent_ids()[1:] != existing_pending_merges:
1272 note('Your local commits will now show as pending merges with '1316 note('Your local commits will now show as pending merges with '
12731317
=== modified file 'bzrlib/tests/blackbox/test_update.py'
--- bzrlib/tests/blackbox/test_update.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/blackbox/test_update.py 2009-03-24 21:35:49 +0000
@@ -209,3 +209,74 @@
209 lightweight=True)209 lightweight=True)
210 tree.commit('empty commit')210 tree.commit('empty commit')
211 self.run_bzr('update checkout')211 self.run_bzr('update checkout')
212
213 def test_update_dash_r(self):
214 # Test that 'bzr update' works correctly when you have
215 # an update in the master tree, and a lightweight checkout
216 # which has merged another branch
217 master = self.make_branch_and_tree('master')
218 os.chdir('master')
219 self.build_tree(['./file1'])
220 master.add(['file1'])
221 master.commit('one', rev_id='m1')
222 self.build_tree(['./file2'])
223 master.add(['file2'])
224 master.commit('two', rev_id='m2')
225
226 out, err = self.run_bzr('update -r 1')
227 self.assertEqual('', out)
228 self.assertEqual('-D file2\nAll changes applied successfully.\n'
229 'Updated to revision 1.\n', err)
230 self.failUnlessExists('./file1')
231 self.failIfExists('./file2')
232 # hrm - the below doesn't look correct for all formats...
233 #self.check_file_contents('.bzr/checkout/last-revision',
234 # 'm1')
235
236 def test_update_dash_r_outside_history(self):
237 # Test that 'bzr update' works correctly when you have
238 # an update in the master tree, and a lightweight checkout
239 # which has merged another branch
240 master = self.make_branch_and_tree('master')
241 self.build_tree(['master/file1'])
242 master.add(['file1'])
243 master.commit('one', rev_id='m1')
244
245 # Create a second branch, with an extra commit
246 other = master.bzrdir.sprout('other').open_workingtree()
247 self.build_tree(['other/file2'])
248 other.add(['file2'])
249 other.commit('other2', rev_id='o2')
250
251 os.chdir('master')
252 self.run_bzr('merge ../other')
253 master.commit('merge', rev_id='merge')
254
255 out, err = self.run_bzr('update -r revid:o2',
256 retcode=3)
257 self.assertEqual('', out)
258 self.assertEqual('bzr: ERROR: branch has no revision o2\n'
259 'bzr update --revision only works'
260 ' for a revision in the branch history\n',
261 err)
262
263 def test_update_dash_r_in_master(self):
264 # Test that 'bzr update' works correctly when you have
265 # an update in the master tree,
266 master = self.make_branch_and_tree('master')
267 self.build_tree(['master/file1'])
268 master.add(['file1'])
269 master.commit('one', rev_id='m1')
270
271 self.run_bzr('checkout master checkout')
272
273 # add a revision in the master.
274 self.build_tree(['master/file2'])
275 master.add(['file2'])
276 master.commit('two', rev_id='m2')
277
278 os.chdir('checkout')
279 out, err = self.run_bzr('update -r revid:m2')
280 self.assertEqual('', out)
281 self.assertEqual('+N file2\nAll changes applied successfully.\n'
282 'Updated to revision 2.\n', err)
212283
=== modified file 'bzrlib/workingtree.py'
--- bzrlib/workingtree.py 2009-03-23 14:59:43 +0000
+++ bzrlib/workingtree.py 2009-03-24 21:35:49 +0000
@@ -2134,7 +2134,10 @@
2134 """2134 """
2135 raise NotImplementedError(self.unlock)2135 raise NotImplementedError(self.unlock)
21362136
2137 def update(self, change_reporter=None, possible_transports=None):2137 _marker = object()
2138
2139 def update(self, change_reporter=None, possible_transports=None,
2140 revision=None, old_tip=_marker):
2138 """Update a working tree along its branch.2141 """Update a working tree along its branch.
21392142
2140 This will update the branch if its bound too, which means we have2143 This will update the branch if its bound too, which means we have
@@ -2158,10 +2161,16 @@
2158 - Merge current state -> basis tree of the master w.r.t. the old tree2161 - Merge current state -> basis tree of the master w.r.t. the old tree
2159 basis.2162 basis.
2160 - Do a 'normal' merge of the old branch basis if it is relevant.2163 - Do a 'normal' merge of the old branch basis if it is relevant.
2164
2165 :param revision: The target revision to update to. Must be in the
2166 revision history.
2167 :param old_tip: If branch.update() has already been run, the value it
2168 returned (old tip of the branch or None). _marker is used
2169 otherwise.
2161 """2170 """
2162 if self.branch.get_bound_location() is not None:2171 if self.branch.get_bound_location() is not None:
2163 self.lock_write()2172 self.lock_write()
2164 update_branch = True2173 update_branch = (old_tip is self._marker)
2165 else:2174 else:
2166 self.lock_tree_write()2175 self.lock_tree_write()
2167 update_branch = False2176 update_branch = False
@@ -2169,13 +2178,14 @@
2169 if update_branch:2178 if update_branch:
2170 old_tip = self.branch.update(possible_transports)2179 old_tip = self.branch.update(possible_transports)
2171 else:2180 else:
2172 old_tip = None2181 if old_tip is self._marker:
2173 return self._update_tree(old_tip, change_reporter)2182 old_tip = None
2183 return self._update_tree(old_tip, change_reporter, revision)
2174 finally:2184 finally:
2175 self.unlock()2185 self.unlock()
21762186
2177 @needs_tree_write_lock2187 @needs_tree_write_lock
2178 def _update_tree(self, old_tip=None, change_reporter=None):2188 def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2179 """Update a tree to the master branch.2189 """Update a tree to the master branch.
21802190
2181 :param old_tip: if supplied, the previous tip revision the branch,2191 :param old_tip: if supplied, the previous tip revision the branch,
@@ -2196,12 +2206,17 @@
2196 last_rev = self.get_parent_ids()[0]2206 last_rev = self.get_parent_ids()[0]
2197 except IndexError:2207 except IndexError:
2198 last_rev = _mod_revision.NULL_REVISION2208 last_rev = _mod_revision.NULL_REVISION
2199 if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):2209 if revision is None:
2200 # merge tree state up to new branch tip.2210 revision = self.branch.last_revision()
2211 else:
2212 if revision not in self.branch.revision_history():
2213 raise errors.NoSuchRevision(self.branch, revision)
2214 if last_rev != _mod_revision.ensure_null(revision):
2215 # merge tree state up to specified revision.
2201 basis = self.basis_tree()2216 basis = self.basis_tree()
2202 basis.lock_read()2217 basis.lock_read()
2203 try:2218 try:
2204 to_tree = self.branch.basis_tree()2219 to_tree = self.branch.repository.revision_tree(revision)
2205 if basis.inventory.root is None:2220 if basis.inventory.root is None:
2206 self.set_root_id(to_tree.get_root_id())2221 self.set_root_id(to_tree.get_root_id())
2207 self.flush()2222 self.flush()
@@ -2211,14 +2226,15 @@
2211 basis,2226 basis,
2212 this_tree=self,2227 this_tree=self,
2213 change_reporter=change_reporter)2228 change_reporter=change_reporter)
2229 self.set_last_revision(revision)
2214 finally:2230 finally:
2215 basis.unlock()2231 basis.unlock()
2216 # TODO - dedup parents list with things merged by pull ?2232 # TODO - dedup parents list with things merged by pull ?
2217 # reuse the tree we've updated to to set the basis:2233 # reuse the tree we've updated to to set the basis:
2218 parent_trees = [(self.branch.last_revision(), to_tree)]2234 parent_trees = [(revision, to_tree)]
2219 merges = self.get_parent_ids()[1:]2235 merges = self.get_parent_ids()[1:]
2220 # Ideally we ask the tree for the trees here, that way the working2236 # Ideally we ask the tree for the trees here, that way the working
2221 # tree can decide whether to give us teh entire tree or give us a2237 # tree can decide whether to give us the entire tree or give us a
2222 # lazy initialised tree. dirstate for instance will have the trees2238 # lazy initialised tree. dirstate for instance will have the trees
2223 # in ram already, whereas a last-revision + basis-inventory tree2239 # in ram already, whereas a last-revision + basis-inventory tree
2224 # will not, but also does not need them when setting parents.2240 # will not, but also does not need them when setting parents.
@@ -2251,8 +2267,7 @@
2251 # should be able to remove this extra flush.2267 # should be able to remove this extra flush.
2252 self.flush()2268 self.flush()
2253 graph = self.branch.repository.get_graph()2269 graph = self.branch.repository.get_graph()
2254 base_rev_id = graph.find_unique_lca(self.branch.last_revision(),2270 base_rev_id = graph.find_unique_lca(revision, old_tip)
2255 old_tip)
2256 base_tree = self.branch.repository.revision_tree(base_rev_id)2271 base_tree = self.branch.repository.revision_tree(base_rev_id)
2257 other_tree = self.branch.repository.revision_tree(old_tip)2272 other_tree = self.branch.repository.revision_tree(old_tip)
2258 result += merge.merge_inner(2273 result += merge.merge_inner(