Merge lp:~mhammond/bzr/update-r into lp:~bzr/bzr/trunk-old
- update-r
- Merge into 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 | ||||
Related bugs: |
|
This proposal has been superseded by a proposal from 2009-06-02.
Commit message
Description of the change
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
1 | === modified file 'NEWS' | |||
2 | --- NEWS 2009-03-24 12:15:01 +0000 | |||
3 | +++ NEWS 2009-03-24 21:35:49 +0000 | |||
4 | @@ -1,5 +1,6 @@ | |||
5 | 1 | ==================== | 1 | ==================== |
6 | 2 | Bazaar Release Notes | 2 | Bazaar Release Notes |
7 | 3 | <<<<<<< TREE | ||
8 | 3 | ==================== | 4 | ==================== |
9 | 4 | 5 | ||
10 | 5 | 6 | ||
11 | @@ -1944,6 +1945,68 @@ | |||
12 | 1944 | * Fix a regression in knit => pack fetching. We had a logic | 1945 | * Fix a regression in knit => pack fetching. We had a logic |
13 | 1945 | inversion, causing the fetch to insert fulltexts in random order, | 1946 | inversion, causing the fetch to insert fulltexts in random order, |
14 | 1946 | rather than preserving deltas. (John Arbash Meinel, #256757) | 1947 | rather than preserving deltas. (John Arbash Meinel, #256757) |
15 | 1948 | ======= | ||
16 | 1949 | -------------------- | ||
17 | 1950 | |||
18 | 1951 | .. contents:: | ||
19 | 1952 | |||
20 | 1953 | IN DEVELOPMENT | ||
21 | 1954 | -------------- | ||
22 | 1955 | |||
23 | 1956 | CHANGES: | ||
24 | 1957 | |||
25 | 1958 | * ``bzr export`` can now export a subdirectory of a project. | ||
26 | 1959 | (Robert Collins) | ||
27 | 1960 | |||
28 | 1961 | * ``bzr rm`` will now scan for files that are missing and remove just | ||
29 | 1962 | them automatically, much as ``bzr add`` scans for new files that | ||
30 | 1963 | are not ignored and adds them automatically. (Robert Collins) | ||
31 | 1964 | |||
32 | 1965 | IMPROVEMENTS: | ||
33 | 1966 | |||
34 | 1967 | * ``bzr init`` and ``bzr init-repo`` will now print out the same as | ||
35 | 1968 | ``bzr info`` if it completed successfully. | ||
36 | 1969 | (Marius Kruger) | ||
37 | 1970 | |||
38 | 1971 | * ``bzr uncommit`` logs the old tip revision id, and displays how to | ||
39 | 1972 | restore the branch to that tip using ``bzr pull``. This allows you | ||
40 | 1973 | to recover if you realize you uncommitted the wrong thing. | ||
41 | 1974 | (John Arbash Meinel) | ||
42 | 1975 | |||
43 | 1976 | * ``bzr update`` now takes a ``--revision`` argument. This lets you | ||
44 | 1977 | change the revision of the working tree to any revision in the | ||
45 | 1978 | ancestry of the current or master branch. (Matthieu Moy, #45719) | ||
46 | 1979 | |||
47 | 1980 | BUG FIXES: | ||
48 | 1981 | |||
49 | 1982 | * ``bzr rm`` is now aliased to ``bzr del`` for the convenience of svn | ||
50 | 1983 | users. (Robert Collins, #205416) | ||
51 | 1984 | |||
52 | 1985 | * ``WorkingTree4`` trees will now correctly report missing-and-new | ||
53 | 1986 | paths in the output of ``iter_changes``. (Robert Collins) | ||
54 | 1987 | |||
55 | 1988 | API CHANGES: | ||
56 | 1989 | |||
57 | 1990 | * Exporters now take 4 parameters. (Robert Collins) | ||
58 | 1991 | |||
59 | 1992 | * ``Tree.iter_changes`` will now return False for the content change | ||
60 | 1993 | field when a file is missing in the basis tree and not present in | ||
61 | 1994 | the target tree. Previously it returned True unconditionally. | ||
62 | 1995 | (Robert Collins) | ||
63 | 1996 | |||
64 | 1997 | TESTING: | ||
65 | 1998 | |||
66 | 1999 | * ``addCleanup`` now takes ``*arguments`` and ``**keyword_arguments`` | ||
67 | 2000 | which are then passed to the cleanup callable as it is run. In | ||
68 | 2001 | addition, addCleanup no longer requires that the callables passed to | ||
69 | 2002 | it be unique. (Jonathan Lange) | ||
70 | 2003 | |||
71 | 2004 | INTERNALS: | ||
72 | 2005 | |||
73 | 2006 | * ``bzrlib.diff.DiffTree.show_diff`` now skips changes where the kind | ||
74 | 2007 | is unknown in both source and target. | ||
75 | 2008 | (Robert Collins, Aaron Bentley) | ||
76 | 2009 | >>>>>>> MERGE-SOURCE | ||
77 | 1947 | 2010 | ||
78 | 1948 | 2011 | ||
79 | 1949 | bzr 1.6rc3 2008-08-14 | 2012 | bzr 1.6rc3 2008-08-14 |
80 | 1950 | 2013 | ||
81 | === modified file 'bzrlib/builtins.py' | |||
82 | --- bzrlib/builtins.py 2009-03-24 12:15:01 +0000 | |||
83 | +++ bzrlib/builtins.py 2009-03-24 21:35:49 +0000 | |||
84 | @@ -1239,12 +1239,17 @@ | |||
85 | 1239 | 1239 | ||
86 | 1240 | _see_also = ['pull', 'working-trees', 'status-flags'] | 1240 | _see_also = ['pull', 'working-trees', 'status-flags'] |
87 | 1241 | takes_args = ['dir?'] | 1241 | takes_args = ['dir?'] |
88 | 1242 | takes_options = ['revision'] | ||
89 | 1242 | aliases = ['up'] | 1243 | aliases = ['up'] |
90 | 1243 | 1244 | ||
92 | 1244 | def run(self, dir='.'): | 1245 | def run(self, dir='.', revision=None): |
93 | 1246 | if revision is not None and len(revision) != 1: | ||
94 | 1247 | raise errors.BzrCommandError( | ||
95 | 1248 | "bzr update --revision takes exactly one revision") | ||
96 | 1245 | tree = WorkingTree.open_containing(dir)[0] | 1249 | tree = WorkingTree.open_containing(dir)[0] |
97 | 1250 | branch = tree.branch | ||
98 | 1246 | possible_transports = [] | 1251 | possible_transports = [] |
100 | 1247 | master = tree.branch.get_master_branch( | 1252 | master = branch.get_master_branch( |
101 | 1248 | possible_transports=possible_transports) | 1253 | possible_transports=possible_transports) |
102 | 1249 | if master is not None: | 1254 | if master is not None: |
103 | 1250 | tree.lock_write() | 1255 | tree.lock_write() |
104 | @@ -1252,6 +1257,7 @@ | |||
105 | 1252 | tree.lock_tree_write() | 1257 | tree.lock_tree_write() |
106 | 1253 | try: | 1258 | try: |
107 | 1254 | existing_pending_merges = tree.get_parent_ids()[1:] | 1259 | existing_pending_merges = tree.get_parent_ids()[1:] |
108 | 1260 | <<<<<<< TREE | ||
109 | 1255 | last_rev = _mod_revision.ensure_null(tree.last_revision()) | 1261 | last_rev = _mod_revision.ensure_null(tree.last_revision()) |
110 | 1256 | if last_rev == _mod_revision.ensure_null( | 1262 | if last_rev == _mod_revision.ensure_null( |
111 | 1257 | tree.branch.last_revision()): | 1263 | tree.branch.last_revision()): |
112 | @@ -1267,6 +1273,44 @@ | |||
113 | 1267 | view_info=view_info), possible_transports=possible_transports) | 1273 | view_info=view_info), possible_transports=possible_transports) |
114 | 1268 | revno = tree.branch.revision_id_to_revno( | 1274 | revno = tree.branch.revision_id_to_revno( |
115 | 1269 | _mod_revision.ensure_null(tree.last_revision())) | 1275 | _mod_revision.ensure_null(tree.last_revision())) |
116 | 1276 | ======= | ||
117 | 1277 | # potentially get new revisions from the master branch. | ||
118 | 1278 | # needed for the case where -r N is given, with N not yet | ||
119 | 1279 | # in the local branch for a heavyweight checkout. | ||
120 | 1280 | if revision is not None: | ||
121 | 1281 | try: | ||
122 | 1282 | rev = revision[0].in_history(branch).rev_id | ||
123 | 1283 | # no need to run branch.update() | ||
124 | 1284 | old_tip = None | ||
125 | 1285 | except (errors.NoSuchRevision, errors.InvalidRevisionSpec): | ||
126 | 1286 | # revision was not there, but is maybe in the master. | ||
127 | 1287 | old_tip = branch.update(possible_transports) | ||
128 | 1288 | rev = revision[0].in_history(branch).rev_id | ||
129 | 1289 | else: | ||
130 | 1290 | if master is None: | ||
131 | 1291 | old_tip = None | ||
132 | 1292 | else: | ||
133 | 1293 | old_tip = branch.update(possible_transports) | ||
134 | 1294 | rev = branch.last_revision() | ||
135 | 1295 | if rev == _mod_revision.ensure_null(tree.last_revision()): | ||
136 | 1296 | revno = branch.revision_id_to_revno(rev) | ||
137 | 1297 | note("Tree is up to date at revision %d." % (revno,)) | ||
138 | 1298 | return 0 | ||
139 | 1299 | try: | ||
140 | 1300 | conflicts = tree.update( | ||
141 | 1301 | delta._ChangeReporter(unversioned_filter=tree.is_ignored), | ||
142 | 1302 | possible_transports=possible_transports, | ||
143 | 1303 | revision=rev, | ||
144 | 1304 | old_tip=old_tip) | ||
145 | 1305 | except errors.NoSuchRevision, e: | ||
146 | 1306 | raise errors.BzrCommandError( | ||
147 | 1307 | "branch has no revision %s\n" | ||
148 | 1308 | "bzr update --revision only works" | ||
149 | 1309 | " for a revision in the branch history" | ||
150 | 1310 | % (e.revision)) | ||
151 | 1311 | revno = branch.revision_id_to_revno( | ||
152 | 1312 | _mod_revision.ensure_null(rev)) | ||
153 | 1313 | >>>>>>> MERGE-SOURCE | ||
154 | 1270 | note('Updated to revision %d.' % (revno,)) | 1314 | note('Updated to revision %d.' % (revno,)) |
155 | 1271 | if tree.get_parent_ids()[1:] != existing_pending_merges: | 1315 | if tree.get_parent_ids()[1:] != existing_pending_merges: |
156 | 1272 | note('Your local commits will now show as pending merges with ' | 1316 | note('Your local commits will now show as pending merges with ' |
157 | 1273 | 1317 | ||
158 | === modified file 'bzrlib/tests/blackbox/test_update.py' | |||
159 | --- bzrlib/tests/blackbox/test_update.py 2009-03-23 14:59:43 +0000 | |||
160 | +++ bzrlib/tests/blackbox/test_update.py 2009-03-24 21:35:49 +0000 | |||
161 | @@ -209,3 +209,74 @@ | |||
162 | 209 | lightweight=True) | 209 | lightweight=True) |
163 | 210 | tree.commit('empty commit') | 210 | tree.commit('empty commit') |
164 | 211 | self.run_bzr('update checkout') | 211 | self.run_bzr('update checkout') |
165 | 212 | |||
166 | 213 | def test_update_dash_r(self): | ||
167 | 214 | # Test that 'bzr update' works correctly when you have | ||
168 | 215 | # an update in the master tree, and a lightweight checkout | ||
169 | 216 | # which has merged another branch | ||
170 | 217 | master = self.make_branch_and_tree('master') | ||
171 | 218 | os.chdir('master') | ||
172 | 219 | self.build_tree(['./file1']) | ||
173 | 220 | master.add(['file1']) | ||
174 | 221 | master.commit('one', rev_id='m1') | ||
175 | 222 | self.build_tree(['./file2']) | ||
176 | 223 | master.add(['file2']) | ||
177 | 224 | master.commit('two', rev_id='m2') | ||
178 | 225 | |||
179 | 226 | out, err = self.run_bzr('update -r 1') | ||
180 | 227 | self.assertEqual('', out) | ||
181 | 228 | self.assertEqual('-D file2\nAll changes applied successfully.\n' | ||
182 | 229 | 'Updated to revision 1.\n', err) | ||
183 | 230 | self.failUnlessExists('./file1') | ||
184 | 231 | self.failIfExists('./file2') | ||
185 | 232 | # hrm - the below doesn't look correct for all formats... | ||
186 | 233 | #self.check_file_contents('.bzr/checkout/last-revision', | ||
187 | 234 | # 'm1') | ||
188 | 235 | |||
189 | 236 | def test_update_dash_r_outside_history(self): | ||
190 | 237 | # Test that 'bzr update' works correctly when you have | ||
191 | 238 | # an update in the master tree, and a lightweight checkout | ||
192 | 239 | # which has merged another branch | ||
193 | 240 | master = self.make_branch_and_tree('master') | ||
194 | 241 | self.build_tree(['master/file1']) | ||
195 | 242 | master.add(['file1']) | ||
196 | 243 | master.commit('one', rev_id='m1') | ||
197 | 244 | |||
198 | 245 | # Create a second branch, with an extra commit | ||
199 | 246 | other = master.bzrdir.sprout('other').open_workingtree() | ||
200 | 247 | self.build_tree(['other/file2']) | ||
201 | 248 | other.add(['file2']) | ||
202 | 249 | other.commit('other2', rev_id='o2') | ||
203 | 250 | |||
204 | 251 | os.chdir('master') | ||
205 | 252 | self.run_bzr('merge ../other') | ||
206 | 253 | master.commit('merge', rev_id='merge') | ||
207 | 254 | |||
208 | 255 | out, err = self.run_bzr('update -r revid:o2', | ||
209 | 256 | retcode=3) | ||
210 | 257 | self.assertEqual('', out) | ||
211 | 258 | self.assertEqual('bzr: ERROR: branch has no revision o2\n' | ||
212 | 259 | 'bzr update --revision only works' | ||
213 | 260 | ' for a revision in the branch history\n', | ||
214 | 261 | err) | ||
215 | 262 | |||
216 | 263 | def test_update_dash_r_in_master(self): | ||
217 | 264 | # Test that 'bzr update' works correctly when you have | ||
218 | 265 | # an update in the master tree, | ||
219 | 266 | master = self.make_branch_and_tree('master') | ||
220 | 267 | self.build_tree(['master/file1']) | ||
221 | 268 | master.add(['file1']) | ||
222 | 269 | master.commit('one', rev_id='m1') | ||
223 | 270 | |||
224 | 271 | self.run_bzr('checkout master checkout') | ||
225 | 272 | |||
226 | 273 | # add a revision in the master. | ||
227 | 274 | self.build_tree(['master/file2']) | ||
228 | 275 | master.add(['file2']) | ||
229 | 276 | master.commit('two', rev_id='m2') | ||
230 | 277 | |||
231 | 278 | os.chdir('checkout') | ||
232 | 279 | out, err = self.run_bzr('update -r revid:m2') | ||
233 | 280 | self.assertEqual('', out) | ||
234 | 281 | self.assertEqual('+N file2\nAll changes applied successfully.\n' | ||
235 | 282 | 'Updated to revision 2.\n', err) | ||
236 | 212 | 283 | ||
237 | === modified file 'bzrlib/workingtree.py' | |||
238 | --- bzrlib/workingtree.py 2009-03-23 14:59:43 +0000 | |||
239 | +++ bzrlib/workingtree.py 2009-03-24 21:35:49 +0000 | |||
240 | @@ -2134,7 +2134,10 @@ | |||
241 | 2134 | """ | 2134 | """ |
242 | 2135 | raise NotImplementedError(self.unlock) | 2135 | raise NotImplementedError(self.unlock) |
243 | 2136 | 2136 | ||
245 | 2137 | def update(self, change_reporter=None, possible_transports=None): | 2137 | _marker = object() |
246 | 2138 | |||
247 | 2139 | def update(self, change_reporter=None, possible_transports=None, | ||
248 | 2140 | revision=None, old_tip=_marker): | ||
249 | 2138 | """Update a working tree along its branch. | 2141 | """Update a working tree along its branch. |
250 | 2139 | 2142 | ||
251 | 2140 | This will update the branch if its bound too, which means we have | 2143 | This will update the branch if its bound too, which means we have |
252 | @@ -2158,10 +2161,16 @@ | |||
253 | 2158 | - Merge current state -> basis tree of the master w.r.t. the old tree | 2161 | - Merge current state -> basis tree of the master w.r.t. the old tree |
254 | 2159 | basis. | 2162 | basis. |
255 | 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. |
256 | 2164 | |||
257 | 2165 | :param revision: The target revision to update to. Must be in the | ||
258 | 2166 | revision history. | ||
259 | 2167 | :param old_tip: If branch.update() has already been run, the value it | ||
260 | 2168 | returned (old tip of the branch or None). _marker is used | ||
261 | 2169 | otherwise. | ||
262 | 2161 | """ | 2170 | """ |
263 | 2162 | if self.branch.get_bound_location() is not None: | 2171 | if self.branch.get_bound_location() is not None: |
264 | 2163 | self.lock_write() | 2172 | self.lock_write() |
266 | 2164 | update_branch = True | 2173 | update_branch = (old_tip is self._marker) |
267 | 2165 | else: | 2174 | else: |
268 | 2166 | self.lock_tree_write() | 2175 | self.lock_tree_write() |
269 | 2167 | update_branch = False | 2176 | update_branch = False |
270 | @@ -2169,13 +2178,14 @@ | |||
271 | 2169 | if update_branch: | 2178 | if update_branch: |
272 | 2170 | old_tip = self.branch.update(possible_transports) | 2179 | old_tip = self.branch.update(possible_transports) |
273 | 2171 | else: | 2180 | else: |
276 | 2172 | old_tip = None | 2181 | if old_tip is self._marker: |
277 | 2173 | return self._update_tree(old_tip, change_reporter) | 2182 | old_tip = None |
278 | 2183 | return self._update_tree(old_tip, change_reporter, revision) | ||
279 | 2174 | finally: | 2184 | finally: |
280 | 2175 | self.unlock() | 2185 | self.unlock() |
281 | 2176 | 2186 | ||
282 | 2177 | @needs_tree_write_lock | 2187 | @needs_tree_write_lock |
284 | 2178 | def _update_tree(self, old_tip=None, change_reporter=None): | 2188 | def _update_tree(self, old_tip=None, change_reporter=None, revision=None): |
285 | 2179 | """Update a tree to the master branch. | 2189 | """Update a tree to the master branch. |
286 | 2180 | 2190 | ||
287 | 2181 | :param old_tip: if supplied, the previous tip revision the branch, | 2191 | :param old_tip: if supplied, the previous tip revision the branch, |
288 | @@ -2196,12 +2206,17 @@ | |||
289 | 2196 | last_rev = self.get_parent_ids()[0] | 2206 | last_rev = self.get_parent_ids()[0] |
290 | 2197 | except IndexError: | 2207 | except IndexError: |
291 | 2198 | last_rev = _mod_revision.NULL_REVISION | 2208 | last_rev = _mod_revision.NULL_REVISION |
294 | 2199 | if last_rev != _mod_revision.ensure_null(self.branch.last_revision()): | 2209 | if revision is None: |
295 | 2200 | # merge tree state up to new branch tip. | 2210 | revision = self.branch.last_revision() |
296 | 2211 | else: | ||
297 | 2212 | if revision not in self.branch.revision_history(): | ||
298 | 2213 | raise errors.NoSuchRevision(self.branch, revision) | ||
299 | 2214 | if last_rev != _mod_revision.ensure_null(revision): | ||
300 | 2215 | # merge tree state up to specified revision. | ||
301 | 2201 | basis = self.basis_tree() | 2216 | basis = self.basis_tree() |
302 | 2202 | basis.lock_read() | 2217 | basis.lock_read() |
303 | 2203 | try: | 2218 | try: |
305 | 2204 | to_tree = self.branch.basis_tree() | 2219 | to_tree = self.branch.repository.revision_tree(revision) |
306 | 2205 | if basis.inventory.root is None: | 2220 | if basis.inventory.root is None: |
307 | 2206 | self.set_root_id(to_tree.get_root_id()) | 2221 | self.set_root_id(to_tree.get_root_id()) |
308 | 2207 | self.flush() | 2222 | self.flush() |
309 | @@ -2211,14 +2226,15 @@ | |||
310 | 2211 | basis, | 2226 | basis, |
311 | 2212 | this_tree=self, | 2227 | this_tree=self, |
312 | 2213 | change_reporter=change_reporter) | 2228 | change_reporter=change_reporter) |
313 | 2229 | self.set_last_revision(revision) | ||
314 | 2214 | finally: | 2230 | finally: |
315 | 2215 | basis.unlock() | 2231 | basis.unlock() |
316 | 2216 | # TODO - dedup parents list with things merged by pull ? | 2232 | # TODO - dedup parents list with things merged by pull ? |
317 | 2217 | # reuse the tree we've updated to to set the basis: | 2233 | # reuse the tree we've updated to to set the basis: |
319 | 2218 | parent_trees = [(self.branch.last_revision(), to_tree)] | 2234 | parent_trees = [(revision, to_tree)] |
320 | 2219 | merges = self.get_parent_ids()[1:] | 2235 | merges = self.get_parent_ids()[1:] |
321 | 2220 | # Ideally we ask the tree for the trees here, that way the working | 2236 | # Ideally we ask the tree for the trees here, that way the working |
323 | 2221 | # tree can decide whether to give us teh entire tree or give us a | 2237 | # tree can decide whether to give us the entire tree or give us a |
324 | 2222 | # lazy initialised tree. dirstate for instance will have the trees | 2238 | # lazy initialised tree. dirstate for instance will have the trees |
325 | 2223 | # in ram already, whereas a last-revision + basis-inventory tree | 2239 | # in ram already, whereas a last-revision + basis-inventory tree |
326 | 2224 | # will not, but also does not need them when setting parents. | 2240 | # will not, but also does not need them when setting parents. |
327 | @@ -2251,8 +2267,7 @@ | |||
328 | 2251 | # should be able to remove this extra flush. | 2267 | # should be able to remove this extra flush. |
329 | 2252 | self.flush() | 2268 | self.flush() |
330 | 2253 | graph = self.branch.repository.get_graph() | 2269 | graph = self.branch.repository.get_graph() |
333 | 2254 | base_rev_id = graph.find_unique_lca(self.branch.last_revision(), | 2270 | base_rev_id = graph.find_unique_lca(revision, old_tip) |
332 | 2255 | old_tip) | ||
334 | 2256 | base_tree = self.branch.repository.revision_tree(base_rev_id) | 2271 | base_tree = self.branch.repository.revision_tree(base_rev_id) |
335 | 2257 | other_tree = self.branch.repository.revision_tree(old_tip) | 2272 | other_tree = self.branch.repository.revision_tree(old_tip) |
336 | 2258 | result += merge.merge_inner( | 2273 | result += merge.merge_inner( |