6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
1 |
************ |
2 |
Nested Trees |
|
3 |
************ |
|
4 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
5 |
:status: 2012-03-17: Draft spec |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
6 |
|
7 |
.. sectnum:: |
|
8 |
||
9 |
.. contents:: |
|
10 |
||
11 |
Principles |
|
12 |
********** |
|
13 |
||
14 |
- Never store a location in versioned data. |
|
15 |
||
16 |
- Implementation of nested trees shall not make operations observably slower |
|
6445.4.4
by Jelmer Vernooij
More updates. |
17 |
for those not using nested trees. |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
18 |
|
19 |
- A repository that holds a revision R should be able to reconstruct the |
|
20 |
whole contents of that revision, including any nested trees. Corolary: |
|
21 |
if I fetch that revision, even into a branch that has no working tree, it |
|
6445.4.2
by Jelmer Vernooij
Some clarifications. |
22 |
should bring across any referenced revisions, or (implicitly) add fallback |
23 |
repositories. |
|
24 |
||
25 |
- The introduction or possible support for nested trees should not |
|
26 |
have an impact on performance. |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
27 |
|
28 |
Core Concepts |
|
29 |
************* |
|
30 |
||
31 |
**Subtree** A tree which is inside another tree, which bzr has been asked to |
|
32 |
treat as part of the outer tree. |
|
33 |
||
34 |
**Subbranch** The branch associated with a subtree. |
|
35 |
||
36 |
**Containing tree** A tree which has another tree inside it |
|
37 |
||
38 |
**Tree reference** A directory in a containing tree which contains a subtree. |
|
39 |
||
40 |
||
41 |
Basic design approach |
|
42 |
********************* |
|
43 |
(see "Design decisions" for extended rationale) |
|
6445.4.2
by Jelmer Vernooij
Some clarifications. |
44 |
By default, APIs and commands for containing trees should behave as though the |
45 |
subtrees were plain directories. By default, commands in subtrees should not |
|
46 |
affect the containing trees. |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
47 |
|
48 |
Downwards recursion |
|
49 |
~~~~~~~~~~~~~~~~~~~ |
|
50 |
One of the objectives of nested trees is to provide ways of reproducing |
|
51 |
historical combinations of different codebases. The dependency chain points |
|
52 |
downwards, such that trees are affected by the revision of their subtrees, but |
|
53 |
subtrees are oblivious to their containing trees. Just as bazaar doesn't |
|
54 |
entice people to commit inconsistent trees, it should not entice people to |
|
55 |
commit inconsistent combinations of containing tree and subtree. Therefore, |
|
56 |
commit should recurse downwards by default. |
|
57 |
||
58 |
Status and diff should reflect what will happen when commit is used, so they |
|
59 |
should also recurse downward by default. Add almost does this already. With |
|
60 |
status, diff, commit and add recursing downwards, it would be confusing to |
|
61 |
users if other operations did not. Therefore, all operations should recurse |
|
62 |
downwards by default. |
|
63 |
||
64 |
No upwards recursion by default |
|
65 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
66 |
One of the reasons for using nested trees is to gain performance by only |
|
67 |
committing in a subtree. Therefore, operations should not recurse upwards by |
|
68 |
default. However, some users do want to have upwards recursion, so it should |
|
69 |
be provided as an option. |
|
70 |
||
6445.4.2
by Jelmer Vernooij
Some clarifications. |
71 |
Modelling nested trees as a composite tree |
72 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
73 |
The idea that a set of nested trees behaves like a single, larger tree seems |
74 |
relatively easy to grasp. Both for users and for developers, it provides a |
|
75 |
clear expectation for the behaviour of nested trees. There are no obvious |
|
76 |
drawbacks in terms of code clarity or performance. Therefore, it seems like a |
|
77 |
good model to start with. |
|
78 |
||
79 |
Using root file-ids for tree-references |
|
80 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
81 |
The idea that tree-reference file-ids are the same as the file-ids of the |
|
82 |
corresponding root directories has a nice symmetry. It is one way of ensuring |
|
83 |
that "bzr split" is deterministic, and "bzr join" is deterministic. When |
|
84 |
performing operations involving a tree and a split version of that tree, using |
|
85 |
the same file-id makes it easy to ensure that operations such as moves and |
|
86 |
renames are applied appropriately to the tree-reference. Providing mechanisms |
|
87 |
whereby a tree-reference can be treated as it would if it had its old file-id |
|
88 |
encroaches on the territory of path tokens or file-id aliases. Having "split" |
|
89 |
cause file-id changes means that in comparing these revisions, it would be seen |
|
90 |
as a deleting a directory and creating a new tree-reference with the same name. |
|
91 |
Handling this correctly in operations such as merge and revert would be more |
|
92 |
complicated than if it were treated as a kind change, especially when |
|
93 |
unversioned files are present in the subtree. |
|
94 |
||
95 |
Sub-branches |
|
96 |
~~~~~~~~~~~~ |
|
97 |
The branches associated with subtrees shall be called "subbranches". |
|
98 |
||
99 |
The branch for the top tree will be in a special format, whose last_revision |
|
100 |
file lists all the last_revision info for all of the branches associated with |
|
101 |
the nested tree. The .bzr directories of subtrees will have a "branch" that |
|
102 |
simply indicates that the top tree's branch should be used. |
|
103 |
||
104 |
In the top tree's last_revision file, the revision id and revno will be |
|
105 |
provided, indexed by the tree-reference file-id. |
|
106 |
||
107 |
The repository used by the top-tree's branch must be a shared repository, and |
|
108 |
will be used by the sub-branches. |
|
109 |
||
110 |
Only the top branch will have a branch.conf. When an operation on a subbranch |
|
111 |
would normally use values from branch.conf it will look them up in the top |
|
112 |
branch's branch.conf and adjust for the sub-location if appropriate. e.g. "bzr |
|
113 |
push" in a subtree will push just that subbranch to the corresponding subbranch |
|
114 |
in the configured push location of the top branch. |
|
115 |
||
116 |
Rationale |
|
117 |
......... |
|
118 |
If the branches were not local, the local subtrees might not be committable, |
|
119 |
and commits to the remote branch would make the local subtree out of date. |
|
120 |
They should not be in a separate location from the containing branch, because |
|
121 |
they might share history with the tree-reference's branch. However, those |
|
122 |
local branches should not be at the same location as their tree, because the |
|
123 |
tree might be deleted or moved. Indeed, they should not be anywhere within a |
|
124 |
working tree. |
|
125 |
||
126 |
subtree branches should not be above or beside their containing branch, because |
|
127 |
it could cause terrible confusion if subtrees from two different trees were |
|
128 |
updating the same branches with every push, pull, commit and uncommit. |
|
129 |
||
130 |
Subtree branches could be plain branches stored somewhere in the top tree's |
|
131 |
branch, but then a lookup mechanism would be needed to translate from file_id |
|
132 |
to location, and performance with large numbers of subbranches would be poor. |
|
133 |
||
134 |
Pull and non-initial push |
|
135 |
~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
136 |
When a pull involves updates to tree references, pull will always pull into the |
|
137 |
reference branch. For all new revisions in the upper branch, it will determine |
|
138 |
the revision values of tree references, and fetch them into the repository. |
|
139 |
||
140 |
When new tree references are encountered, pull should create a corresponding |
|
141 |
subbranch in the top branch. |
|
142 |
||
143 |
Pulls will update the subtrees whose tree-references change, including creating |
|
144 |
trees for new sub-branches. |
|
145 |
||
146 |
Implementation strategies |
|
147 |
************************* |
|
148 |
||
149 |
Data storage |
|
150 |
************ |
|
151 |
||
152 |
Trees |
|
153 |
~~~~~ |
|
154 |
The root-ids of trees must be unique, so that the same file-id can be used in |
|
155 |
both the containing tree and the subtree, to simplify access within trees. |
|
156 |
Tree references are an inventory type that is distinct from a directory, and |
|
157 |
has a revision-id associated with it. |
|
158 |
All modern working trees support tree references. Indices may be provided to |
|
159 |
ensure fast access to the list of subtrees. |
|
160 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
161 |
The various methods on ``Tree`` need to be updated to handle nested trees. |
162 |
||
163 |
Tree file ids are tuples containing inventory file ids, describing a path |
|
164 |
to the file. This means that if a file is in a nested tree with the root |
|
165 |
fileid ``file_id_a`` and the file itself has the inventory file id ``file_id_b`` |
|
166 |
then the tree file id is (file_id_a, file_id_b). This makes it easy to look up file ids |
|
167 |
without having to load and scan all nested trees for ``file_id_b``. |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
168 |
|
169 |
Branches |
|
170 |
~~~~~~~~ |
|
171 |
A new branch format, "subbranches", is introduced which provides multiple |
|
172 |
sub-branches, with their data referenced by file-id. A new branch refrerence |
|
173 |
format, "subbranch-reference", is introduced which refers to sub-branches in a |
|
174 |
"subbranches" branch. |
|
175 |
||
176 |
Repositories |
|
177 |
~~~~~~~~~~~~ |
|
178 |
Some repository formats have 'subtree' variants, e.g. pack-0.92-subtree, |
|
179 |
development-subtree. These are hidden, experimental formats that support |
|
6445.4.4
by Jelmer Vernooij
More updates. |
180 |
storing tree-references in their inventory formats. |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
181 |
|
182 |
Repository indexing might be extended to provide fast access to |
|
183 |
tree-references. |
|
184 |
||
185 |
Commands |
|
186 |
******** |
|
187 |
||
6445.4.2
by Jelmer Vernooij
Some clarifications. |
188 |
The following new options are introduced: |
189 |
||
190 |
``join --reference`` Cause an inner tree to be treated as a subtree. The outer |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
191 |
tree's branch must be in the new "subbranches" format. The inner tree's branch |
192 |
will be cloned into the "subbranches" branch, and the local branch will be |
|
193 |
replaced with a "subbranch-reference". Finally, a tree-reference will be |
|
194 |
added to the containing tree. |
|
195 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
196 |
(this is already implemented) |
197 |
||
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
198 |
API Changes |
199 |
*********** |
|
200 |
||
6445.4.2
by Jelmer Vernooij
Some clarifications. |
201 |
Tree file ids as tuples |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
202 |
~~~~~~~~~~~~~~~~~~~~~~~ |
6445.4.2
by Jelmer Vernooij
Some clarifications. |
203 |
|
204 |
Implementation Changes |
|
205 |
********************** |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
206 |
|
207 |
Branch changes |
|
208 |
~~~~~~~~~~~~~~ |
|
209 |
||
210 |
pull recurses into reference branches, and pulls *from* the source's reference |
|
211 |
branches. |
|
212 |
||
213 |
Repository changes |
|
214 |
~~~~~~~~~~~~~~~~~~ |
|
215 |
||
216 |
fetch provides a list of tree-reference revision ids/file-id pairs for the |
|
217 |
revisions that were fetched. Fetch automatically fetches all revisions |
|
218 |
associted with tree-references that were fetched. |
|
219 |
||
220 |
Use Cases |
|
221 |
********* |
|
222 |
||
223 |
Case 1 |
|
224 |
~~~~~~ |
|
225 |
Barry works on a project with three libraries. He wants to keep up to date |
|
226 |
with the tip of those libraries, but he doesn't want them to be part of his |
|
227 |
source tree. |
|
228 |
||
229 |
Example commands:: |
|
230 |
||
231 |
Set up the tree: |
|
232 |
$ bzr branch --nested http://library1 project |
|
233 |
$ bzr branch --nested http://library2 project |
|
234 |
$ bzr branch --nested http://library3 project |
|
235 |
$ bzr commit project -m "Added three libraries" |
|
236 |
||
237 |
Update a library to tip: |
|
238 |
$ bzr pull -d project/library1 http://library1 |
|
239 |
||
240 |
Case 2 |
|
241 |
~~~~~~ |
|
242 |
Now, Barry wants to add a fourth library. |
|
243 |
||
244 |
Example commands:: |
|
245 |
||
246 |
$ bzr branch --nested http://library4 project |
|
247 |
||
248 |
Case 3 |
|
249 |
~~~~~~ |
|
250 |
Barry wants to publish his project. |
|
251 |
||
252 |
Example commands:: |
|
253 |
||
254 |
$ bzr push -d project bzr+ssh://project/trunk |
|
255 |
||
256 |
Case 4 |
|
257 |
~~~~~~ |
|
258 |
Barry decides to make part of his project into another library |
|
259 |
||
260 |
Example commands:: |
|
261 |
||
262 |
$ bzr split --nested project/newlibrary |
|
263 |
||
264 |
Case 5 |
|
265 |
~~~~~~ |
|
266 |
Curtis wants to hack on Barry's project |
|
267 |
||
268 |
Example commands:: |
|
269 |
||
270 |
$ bzr branch http://project/trunk |
|
271 |
||
272 |
Case 6 |
|
273 |
~~~~~~ |
|
274 |
Barry wants to drop one of the libraries he was using |
|
275 |
||
276 |
Example commands:: |
|
277 |
||
278 |
$ rm project/library1 |
|
279 |
$ bzr commit project -m "Removed library1" |
|
280 |
||
281 |
Case 7 |
|
282 |
~~~~~~ |
|
283 |
Curtis has made changes to one of the libraries. Barry wants to merge Curtis' |
|
284 |
changes into his copy. |
|
285 |
||
286 |
Example commands:: |
|
287 |
||
6445.4.6
by Jelmer Vernooij
Fix some paths, thanks Marius. |
288 |
$ bzr merge -d project http://curtis.org/trunk/library2 |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
289 |
|
290 |
Or alternatively: |
|
6445.4.6
by Jelmer Vernooij
Fix some paths, thanks Marius. |
291 |
$ bzr merge -d project/library2 http://curtis.org/trunk/library2 |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
292 |
|
293 |
Case 8 |
|
294 |
~~~~~~ |
|
295 |
Curtis has made changes to Barry's main project. Barry wants to merge Curtis' |
|
296 |
changes into his copy. |
|
297 |
||
298 |
Example commands:: |
|
299 |
||
300 |
$ bzr merge -d project http://curtis.org/trunk |
|
301 |
||
302 |
||
303 |
Case 9 |
|
304 |
~~~~~~ |
|
305 |
Barry makes changes in his project and in a library, and he runs status |
|
306 |
||
307 |
Example commands:: |
|
308 |
||
309 |
$ echo bar > project/foo |
|
310 |
$ echo qux > project/library2/baz |
|
311 |
$ bzr status project |
|
312 |
M foo |
|
313 |
M library2/baz |
|
314 |
||
315 |
Case 10 |
|
316 |
~~~~~~~ |
|
317 |
Barry wants to upgrade the bazaar format of his project |
|
318 |
||
319 |
Example commands:: |
|
320 |
||
321 |
$ bzr upgrade project |
|
322 |
||
323 |
Case 11 |
|
324 |
~~~~~~~ |
|
325 |
Curtis wants to apply Barry's latest changes. |
|
326 |
||
327 |
Example commands:: |
|
328 |
||
329 |
$ bzr merge -d project http://project/trunk |
|
330 |
||
331 |
Case 12 |
|
332 |
~~~~~~~ |
|
333 |
Danilo wants to start a project with two libraries using nested trees from |
|
334 |
scratch. |
|
335 |
||
336 |
Example commands:: |
|
337 |
||
338 |
$ bzr init project |
|
339 |
$ bzr branch --nested http://library4 project |
|
340 |
$ bzr branch --nested http://library5 project |
|
341 |
$ bzr commit project -m "Created new project." |
|
342 |
||
343 |
Case 13 |
|
344 |
~~~~~~~ |
|
345 |
Edwin has a project that doesn't use nested trees and he wants to start using |
|
346 |
nested trees. |
|
347 |
||
348 |
Example commands:: |
|
349 |
$ bzr split --nested project/subdir |
|
350 |
||
351 |
Case 14 |
|
352 |
~~~~~~~ |
|
353 |
Françis has a project with nested trees where the containing tree uses one |
|
354 |
Bazaar format and the subtree uses a different Bazaar format. |
|
355 |
||
356 |
Not supported. |
|
357 |
||
358 |
Case 15 |
|
359 |
~~~~~~~ |
|
360 |
Barry commits some changes to a library and to the main project, and then |
|
361 |
discovers the changes are not appropriate. He has not yet pushed his changes |
|
362 |
anywhere. |
|
363 |
||
364 |
Example commands:: |
|
365 |
||
366 |
$ bzr merge -d project http://library2 |
|
367 |
$ bzr commit project -m "Updated library2" |
|
368 |
$ bzr uncommit project --force |
|
369 |
||
370 |
Case 16 |
|
371 |
~~~~~~~ |
|
372 |
Barry commits some changes to a library and to the main project, publishes his |
|
373 |
branch, and then discovers the changes are not appropriate. |
|
374 |
||
375 |
Example commands:: |
|
376 |
||
377 |
$ bzr merge -d project http://library2 |
|
378 |
$ bzr commit project -m "Updated library2" |
|
379 |
$ bzr push -d project |
|
6445.5.1
by Marius Kruger
fix some typos picked up while reading this again |
380 |
$ bzr revert -r-2 project |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
381 |
$ bzr commit project -m "Reverted inappropriate changes." |
382 |
$ bzr push -d project |
|
383 |
||
384 |
Case 17 |
|
385 |
~~~~~~~ |
|
386 |
Gary is writing a project. Henninge wants to split a library out of it. |
|
387 |
||
388 |
Example commands:: |
|
389 |
||
390 |
$ bzr branch project |
|
391 |
$ bzr split project/library6 |
|
392 |
$ mv project/library6 . |
|
393 |
$ rm project |
|
394 |
$ bzr commit -m "split library6 into its own library." |
|
395 |
||
396 |
Case 18 |
|
397 |
~~~~~~~ |
|
398 |
Henning wants to update to receive Gary's latest changes. |
|
399 |
||
400 |
Example commands:: |
|
401 |
||
402 |
$ bzr merge -d library6 |
|
403 |
||
404 |
Case 19 |
|
405 |
~~~~~~~ |
|
406 |
Gary wants to update to receive Henninge's changes, including splitting a |
|
407 |
library out. |
|
408 |
||
409 |
Example commands:: |
|
410 |
||
411 |
$ bzr split --nested project/library6 |
|
412 |
$ bzr commit project -m "Turned library6 into a library" |
|
413 |
$ bzr merge -d project/library6 http://library6 |
|
414 |
$ bzr commit project -m "Merge Henninge's changes." |
|
415 |
||
416 |
||
417 |
Case 20 |
|
418 |
~~~~~~~ |
|
419 |
Gary wants to update to receive Henninge's changes, without splitting a library |
|
420 |
out. |
|
421 |
||
422 |
$ bzr split --nested project/library6 |
|
423 |
$ bzr commit project -m "Turned library6 into a library" |
|
424 |
# i.e. a cherrypick that skips the revision where library6 became a library. |
|
425 |
$ bzr merge -d project/library6 http://library6 -r 5..-1 |
|
426 |
$ bzr commit project -m "Merge Henninge's changes." |
|
427 |
||
428 |
Case 21 |
|
429 |
~~~~~~~ |
|
430 |
||
431 |
John works on a project called FooBar, but has decided that it would be better |
|
432 |
structured as two projects, where Bar is a library that may be of general use |
|
433 |
outside of Foo. As it happens, bar already has its own subdirectory. |
|
434 |
||
435 |
He runs: |
|
436 |
:: |
|
437 |
||
438 |
# Convert into two trees: foobar and foobar/bar. |
|
439 |
# In each tree, files will be removed and deleted. In foobar/bar, "bar" |
|
440 |
# will have been moved to become the tree root. |
|
441 |
# These changes will be committed later. |
|
442 |
$ bzr upgrade foobar --format=subbranches |
|
443 |
$ bzr split foobar/bar |
|
444 |
||
445 |
# Add a tree-reference from foobar to foobar/bar, change bar's branch |
|
446 |
# to a reference to subbranch in foobar's branch. |
|
447 |
$ bzr join --nested foobar/bar |
|
448 |
||
449 |
# This recurses into foobar/bar and commits the deletion of the containing |
|
450 |
# tree. In foobar, it commits a kind change for 'bar' from directory to |
|
451 |
# tree-reference, and the deletion of the contents of bar. |
|
452 |
$ bzr commit foobar |
|
453 |
||
454 |
This commits new revisions to foobar and bar, and foobar's tree-reference bar |
|
455 |
refers to the revision-id of bar. |
|
456 |
||
457 |
Next, he adds two new files: foobar/baz and foobar/bar/qux:: |
|
458 |
||
459 |
$ vi foobar/baz |
|
460 |
$ vi foobar/bar/qux |
|
461 |
# This adds qux to foobar/bar and adds baz to foobar. |
|
462 |
$ bzr add foobar |
|
463 |
||
464 |
Since foobar/bar/qux is in a commitable state and foobar/baz is not, he invokes |
|
465 |
:: |
|
466 |
||
467 |
$ bzr commit foobar/bar |
|
468 |
||
469 |
This commits foobar/bar/baz/qux to the subtree and commits foobar/bar to the |
|
470 |
containing tree. |
|
471 |
||
472 |
(Had he wanted to commit to just the subtree, or just the containing tree, he |
|
473 |
could have specified an option.) |
|
474 |
||
475 |
||
476 |
Case 21 |
|
477 |
~~~~~~~ |
|
478 |
||
479 |
Robert wants to hack on a project, Baz, that is structured as a nested tree, |
|
480 |
which uses the library "quxlib", from quxlib.org. |
|
481 |
||
482 |
He runs: |
|
483 |
:: |
|
484 |
||
485 |
$ bzr branch http://baz.org/dev baz |
|
486 |
||
487 |
This creates a "subbranches" branch and working tree for baz, as normal. Since |
|
488 |
tree-references were encountered, it adds subbranches for them to the baz |
|
489 |
branch. All data is retrieved from baz.org, not quxlib.org. |
|
490 |
||
491 |
It creates a working tree for quxlib with a subbranch-reference. It uses the |
|
492 |
revision-id from the tree-reference in the containing tree, not the head |
|
493 |
revision at baz.org. This allows Robert to get a known-good nested tree. |
|
494 |
||
495 |
Later, Robert decides to update the version of quxlib being used to the latest |
|
496 |
from quxlib.org. He runs:: |
|
497 |
||
498 |
$ bzr pull -d http://quxlib.org |
|
499 |
||
500 |
This updates the version of quxlib in the working tree, which mean that baz is |
|
501 |
now out-of-date with its last-committed tree. Unfortunately, the new rev on |
|
502 |
quxlib is not completely compatible with the old one, and Robert must tweak a |
|
503 |
few files before Baz runs properly. Once he has done so, he runs:: |
|
504 |
||
505 |
$ bzr commit baz |
|
506 |
||
507 |
Now he has committed a known-good nested tree, and the baz working tree is once |
|
508 |
again up-to-date. |
|
509 |
||
510 |
||
511 |
User documentation |
|
512 |
****************** |
|
513 |
||
514 |
For many large projects, it is often useful to incorporate libraries |
|
515 |
maintained elsewhere or to construct them from multiple subprojects. |
|
516 |
While it is easy for a single user to set up a particular layout of |
|
517 |
multiple branches by hand, the different branches really need to be |
|
518 |
linked together if others are to reproduce the desired layout, and |
|
519 |
if the relationships are going to be managed over time. |
|
520 |
||
521 |
Bazaar has good support for building and managing external libraries |
|
522 |
and subprojects via a feature known as *nested trees*. In particular, |
|
523 |
nearly all of Bazaar's commonly used commands understand nested trees |
|
524 |
and Do The Right Thing as explained below. The relationship is hierarchical: |
|
525 |
the containing tree knows about its nested trees, but nested trees are unaware |
|
526 |
of the tree (or trees) containing them. |
|
527 |
||
528 |
At the moment, *nested trees* are the only type of nested item |
|
529 |
supported though *nested files* may be supported in the future. |
|
530 |
Nested trees may contain other nested trees as required. |
|
531 |
||
532 |
Note: This feature requires a recent branch format such as ``2.0`` |
|
533 |
or later. |
|
534 |
||
535 |
||
536 |
Nesting an external project |
|
537 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
538 |
||
539 |
To link an external project into a branch, use the ``branch`` command |
|
540 |
with the ``--nested`` option like this:: |
|
541 |
||
542 |
bzr branch --nested SOURCE-URL TARGET-DIR |
|
543 |
||
544 |
For example, assuming you already have a ``src/lib`` directory where |
|
545 |
libraries are kept:: |
|
546 |
||
547 |
bzr branch --nested http://example.com/xmlsaxlib src/lib/sax |
|
548 |
||
549 |
This will create a nested branch in the ``src/lib/sax`` directory, |
|
550 |
join it into the containing branch and save the source location. |
|
551 |
||
552 |
If you now run ``bzr status``, it will show the nested branch as |
|
553 |
uncommitted changes like this:: |
|
554 |
||
555 |
+ src/lib/sax |
|
556 |
+ src/lib/sax/README |
|
557 |
+ src/lib/sax/parser.py |
|
558 |
... |
|
559 |
||
560 |
To record this change, use the ``commit`` command as you normally would:: |
|
561 |
||
562 |
bzr commit -m "added SAX parsing library" |
|
563 |
||
564 |
Note that Bazaar stores the tip revision of each nested branch. This |
|
565 |
is an important feature in that it's then easy to reproduce the exact |
|
566 |
combination of libraries used for historical revisions. It also means |
|
567 |
that other developers pulling or merging your changes will get nested |
|
568 |
branches created for them at the right revisions of each. |
|
569 |
||
570 |
||
571 |
Refreshing a nested branch |
|
572 |
~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
573 |
||
574 |
As bugs are fixed and enhancements are made to nested projects, you |
|
575 |
will want to update the version being used. To do this, ``pull`` the |
|
576 |
latest version of the nested branch. For example:: |
|
577 |
||
578 |
bzr pull -d src/lib/sax |
|
579 |
||
580 |
If the latest revision is too unstable, you can always use the ``-r`` |
|
581 |
option on the ``pull`` command to nominate a particular revision or tag. |
|
582 |
||
583 |
Now that you have the required version of the code, you can make |
|
584 |
any required adjustments (e.g. API changes), run your automated tests |
|
585 |
and commit something like this:: |
|
586 |
||
587 |
view src/lib/sax/README |
|
588 |
(hack, hack, hack) |
|
589 |
make test |
|
590 |
bzr commit -m "upgraded SAX library to version 2.1.3" |
|
591 |
||
592 |
||
593 |
Changing a nested tree |
|
594 |
~~~~~~~~~~~~~~~~~~~~~~ |
|
595 |
||
596 |
As well as keeping track of which revisions of external libraries |
|
597 |
are used over time, one of the reasons for nesting projects is to |
|
598 |
make minor changes. You may want to do this in order to fix and |
|
599 |
track particular bugs you need addressed. In other cases, you may want |
|
600 |
to make various local enhancements that aren't valuable outside |
|
601 |
the context of your project. |
|
602 |
||
603 |
As support for nested branches is integrated into most commonly |
|
604 |
used commands, this is actually quite easy to do: simply make |
|
605 |
the change to the required files as you normally would! For example:: |
|
606 |
||
607 |
edit src/lib/sax/parser.py |
|
608 |
bzr commit -m "fix bug #42 in sax parser" |
|
609 |
||
610 |
Note that Bazaar is smart enough to recurse by default into nested |
|
611 |
branches, commit changes there, and commit the new nested branch tips |
|
612 |
in the current branch. Both commits get the same commit message. |
|
613 |
||
614 |
If you want to only commit the change to a nested branch for now, you |
|
615 |
can change into the nested branch before running commit like this:: |
|
616 |
||
617 |
cd src/lib/sax |
|
618 |
bzr commit -m "fix bug #42 in sax parser" |
|
619 |
||
620 |
Alternatively, you can use a selective commit like this:: |
|
621 |
||
622 |
bzr commit -m "fix bug #42 in sax parser" src/lib/sax |
|
623 |
||
624 |
||
625 |
Reviewing nested tree changes |
|
626 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
627 |
||
628 |
Just like ``commit``, the ``status`` and ``diff`` commands implicitly |
|
629 |
recurse into nested trees. In the case of ``status``, it shows both the |
|
630 |
nested tree as having a pending change as well as the items within it that have |
|
631 |
changed. For example:: |
|
632 |
||
633 |
M src/lib/sax |
|
634 |
M src/lib/sax/parser.py |
|
635 |
||
636 |
Once again, if you change into a nested tree though, ``status`` and |
|
637 |
``diff`` will operate just on that tree and not recurse upwards by |
|
638 |
default. |
|
639 |
||
640 |
||
641 |
Browsing nested tree history |
|
642 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
643 |
||
644 |
As the branches of nested trees have their own history, the ``log`` command |
|
645 |
shows just the history of the containing branch. To see the history for |
|
646 |
a nested branch, nominate the branch explicitly like this:: |
|
647 |
||
648 |
bzr log src/lib/sax |
|
649 |
||
650 |
Note however that ``log -v`` and ``log -p`` on the containing branch |
|
651 |
will show what files in nested branches were changed in each revision. |
|
652 |
||
653 |
||
654 |
Splitting out a project |
|
655 |
~~~~~~~~~~~~~~~~~~~~~~~ |
|
656 |
||
657 |
If you already have a large project and wish to partition it into |
|
658 |
reusable subprojects, use the ``split`` command. This takes an existing |
|
659 |
directory and makes it a separate branch. For example, imagine you have |
|
660 |
a directory holding UI widgets that another project would like to |
|
661 |
leverage. You can make it a separate branch like this:: |
|
662 |
||
663 |
bzr split src/uiwidgets |
|
664 |
||
665 |
To make the new project available to others, push it to a shared location |
|
666 |
like this:: |
|
667 |
||
668 |
cd src/uiwidgets |
|
669 |
bzr push bzr://example.com/uiwidgets |
|
670 |
||
671 |
You also need to link it back into the original project as a nested branch |
|
672 |
using the ``join`` command like this (assuming the current directory is |
|
673 |
``src/uiwidgets``):: |
|
674 |
||
675 |
bzr join --nested . |
|
676 |
bzr commit -m "uiwidgets is now a nested project" |
|
677 |
||
678 |
Similar to ``branch --nested``, ``join --nested`` joins the nominated directory |
|
679 |
(which must hold a branch) into the containing tree. In order to make sure |
|
680 |
that all versions of a tree can be reproduced, the branches of nested trees |
|
681 |
share a repository with their containing tree. |
|
682 |
||
683 |
||
684 |
Virtual projects |
|
685 |
~~~~~~~~~~~~~~~~ |
|
686 |
||
687 |
By design, Bazaar is strict about tracking the actual revisions used of |
|
688 |
nested branches over time. Without this, projects cannot accurately |
|
689 |
reproduce exactly what was used to make a given build. There are |
|
690 |
isolated use cases though where is advantageous to say "give me the |
|
691 |
latest tip of these loosely coupled branches". To do this, create a |
|
692 |
small 'virtual project' which is just a bunch of *unpegged* nested |
|
693 |
branches. To mark nested branches as unpegged, use the ``--no-pegged`` |
|
694 |
option of the ``join`` command like this:: |
|
695 |
||
696 |
bzr join --nested --no-pegged [DIR] |
|
697 |
||
698 |
To stop the nested branch tips from floating and to begin recording |
|
699 |
the tip revisions again, use the ``pegged`` option:: |
|
700 |
||
701 |
bzr join --nested --pegged [DIR] |
|
702 |
||
703 |
After changing whether one or more nested branches are pegged or not, you |
|
704 |
need to ``commit`` the branch to record that metadata. (The pegged state |
|
705 |
is recorded over time.) |
|
706 |
||
707 |
For example, you may be managing a company intranet site as a project |
|
708 |
which is nothing more than a list of unrelated departmental websites |
|
709 |
bundled together. You can set this up like this:: |
|
710 |
||
711 |
bzr init intranet-site |
|
712 |
cd intranet-site |
|
713 |
bzr branch bzr://ourserver/websites/research |
|
714 |
bzr branch bzr://ourserver/websites/development |
|
715 |
bzr branch bzr://ourserver/websites/support |
|
716 |
bzr branch bzr://ourserver/websites/hr |
|
717 |
bzr join --nested --no-pegged research |
|
718 |
bzr join --nested --no-pegged development |
|
719 |
bzr join --nested --no-pegged support |
|
720 |
bzr join --nested --no-pegged hr |
|
721 |
bzr commit -m "initial configuration of intranet-site" |
|
722 |
||
723 |
Publishing the overall site is then as easy as going to the server |
|
724 |
hosting your intranet and running something like:: |
|
725 |
||
726 |
bzr branch http://mymachine//projects/intranet-site |
|
727 |
||
728 |
Refreshing the overall site is as easy as:: |
|
729 |
||
730 |
bzr pull |
|
731 |
||
732 |
Virtual projects are also useful for providing a partial 'view' over |
|
733 |
a large project containing a large number of subprojects. For example, |
|
734 |
you may be working on an office suite and have a bunch of developers |
|
735 |
that only care about the word processor. You can create a virtual |
|
736 |
project for them like this:: |
|
737 |
||
738 |
bzr init wp-modules |
|
739 |
cd wp-modules |
|
740 |
bzr branch ../common |
|
741 |
bzr branch ../printing |
|
742 |
bzr branch ../spellchecker |
|
743 |
bzr branch ../wordprocessor |
|
744 |
bzr join --nested --no-pegged common |
|
745 |
bzr join --nested --no-pegged printing |
|
746 |
bzr join --nested --no-pegged spellchecker |
|
747 |
bzr join --nested --no-pegged wordprocessor |
|
748 |
bzr commit -m "initial configuration of wp-modules" |
|
749 |
||
750 |
Those developers can then get bootstrapped faster and have *just* the |
|
751 |
subprojects they care about by branching from ``wp-modules``. |
|
752 |
||
753 |
||
754 |
Nested branch tips & tricks |
|
755 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
756 |
||
757 |
As explained above, most of Bazaar's commonly used commands recurse |
|
758 |
downwards into nested branches by default. To prevent this recursion, |
|
759 |
use the ``--no-recurse-nested`` option on various commands (including |
|
760 |
``commit``, ``status`` and ``diff``) that support it. |
|
761 |
||
762 |
Thanks to plugins like bzr-svn and bzr-git, Bazaar has strong support |
|
763 |
for transparently accessing branches managed by foreign VCS tools. This |
|
764 |
means that Bazaar can support projects where nested branches are hosted |
|
765 |
in supported foreign systems. For example, to nest a library maintained |
|
766 |
in Subversion:: |
|
767 |
||
768 |
bzr branch --nested svn://example.com/xmlhelpers src/lib/xmlhelpers |
|
769 |
||
770 |
If you want revisions to be committed both to a remote location and a |
|
771 |
local location, make the top-level branch a bound branch. (Nested branches |
|
772 |
have no configuration of their own.) |
|
773 |
||
774 |
Most likely, you will have some branches that are identical to their upstream |
|
775 |
version and can be pulled, and some that have local changes and must be merged. |
|
776 |
You can update all of them at once using ``merge --pull``. This will pull |
|
777 |
into the trees with no local changes, and merge into the ones with local |
|
778 |
changes. Afterward, you should commit, which will commit only into the |
|
779 |
trees that were merged into. |
|
780 |
||
781 |
As you'd expect, a nested branch can be moved or deleted using the |
|
782 |
normal commands. For example, after splitting out a subproject, you |
|
783 |
may want to change its location like this:: |
|
784 |
||
785 |
bzr mv src/uiwidgets src/lib/uiwidgets |
|
786 |
bzr commit -m "move uiwidgets into src/lib" |
|
787 |
||
788 |
Things to be aware of |
|
789 |
~~~~~~~~~~~~~~~~~~~~~ |
|
790 |
||
791 |
Commands like ``commit`` and ``push`` need online access to the locations |
|
792 |
for nested branches which have updated their tip. In particular, ``commit`` |
|
793 |
will update any changed nested branches first and only commit to the |
|
794 |
containing branch if all nested branch commits succeed. If you are working |
|
795 |
offline, you may want to ensure you have a local mirror location defined |
|
796 |
for nested branches you are likely to tweak. Alternatively, the |
|
797 |
``no-recurse-nested`` option to the ``commit`` command might to useful to |
|
798 |
commit some changes, leaving the nested branch commits until you are back |
|
799 |
online. |
|
800 |
||
801 |
At the moment, nested trees need to be incorporated as a whole. |
|
6445.5.1
by Marius Kruger
fix some typos picked up while reading this again |
802 |
Filtered views can be used to restrict the set of files and directories |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
803 |
logically seen. Currently though, filtered views are a lens onto a tree: |
804 |
they do not delete other files and the exposed files/directories must |
|
805 |
have the same paths as they do in the original branch. In the future, |
|
806 |
we may add support for nesting and moving selected files from a |
|
807 |
(read-only) nested branch something like this:: |
|
808 |
||
809 |
bzr nested DIR --file LICENSE --file doc/README::README |
|
810 |
bzr commit -m "change which files are nested from project DIR" |
|
811 |
||
812 |
If you require this feature, please contact us with your needs. |
|
813 |
||
814 |
Design decisions |
|
815 |
**************** |
|
816 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
817 |
The branches of subtrees shall either share a repository with the containing tree, |
818 |
or the containing tree's repository will be (implicitly) added as a fallback |
|
819 |
repository. |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
820 |
|
821 |
The branches of subtrees shall be in a special format that shares a single |
|
822 |
last_revision file that is stored in the containing branch. |
|
823 |
||
824 |
The subtree branches shall be referenced in the last_revision file by file-id. |
|
825 |
||
826 |
Subtree branches shall not support individual configuration. |
|
827 |
||
828 |
Fetch shall automatically fetch the revisions mentioned by tree-references, |
|
829 |
recursively. |
|
830 |
||
831 |
The reserved revision-id "head:" shall be used in tree-references to refer to |
|
832 |
the tip revision of a branch. |
|
833 |
||
834 |
bzr-svn repositories with externals shall behave as though the multiple |
|
835 |
repositories were a single Bazaar repository with multiple branches. |
|
836 |
||
837 |
Shall commands recurse downwards by default? |
|
838 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
839 |
||
840 |
Yes. |
|
841 |
||
842 |
Pros: |
|
843 |
||
844 |
- It is hard to accidentally produce inconsistent trees |
|
845 |
- Inconsistent trees are hard for remote users to handle |
|
846 |
- Accidentally committing too many things at once is easy to resolve |
|
847 |
- It is hard to accidentally commit too many things at once |
|
848 |
||
849 |
Cons: |
|
850 |
||
851 |
- Accidentally committing nuclear launch codes is easier to do |
|
852 |
- A commit message that makes sense for the top may not make sense lower down. |
|
853 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
854 |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
855 |
Shall commands recurse upwards by default? |
856 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
857 |
||
858 |
No. |
|
859 |
||
860 |
||
861 |
Shall subtree branches be addressable? |
|
862 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
863 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
864 |
Ideally, yes. We might want to use the path segment parameters syntax here too. |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
865 |
|
866 |
||
867 |
Shall we model nested trees as a composite tree? |
|
868 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
869 |
||
870 |
Yes. Users will see recurse-downwards behaviour that allows operations that |
|
871 |
cross subtree boundaries, e.g. a merge in the top tree can move a file between |
|
872 |
subtrees. |
|
873 |
||
874 |
The downside is that we can't have cheap support for subtrees that are copies |
|
875 |
of one another, because we wouldn't know which copy to apply sets of changes |
|
876 |
to. |
|
877 |
||
878 |
||
879 |
Shall we use root-ids for tree references? |
|
880 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
881 |
||
882 |
Yes. This fits well with our current lack of support of file copies. If we do |
|
883 |
support file copies in future it will be possible to change this in a future |
|
884 |
format, and perform deterministic upgrades to that format. |
|
885 |
||
886 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
887 |
What about locking? |
888 |
~~~~~~~~~~~~~~~~~~~ |
|
889 |
||
890 |
We should lock recursively. It matches existing behaviour by failing earlier, |
|
891 |
and the extra cost does not seem onerous. (To be fully efficient this requires |
|
892 |
an index of the subtrees, otherwise we need to scan the fully |
|
893 |
inventory/dirstate.) |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
894 |
|
895 |
(Also, this decision can be changed later with no compatibility concerns.) |
|
896 |
||
897 |
||
898 |
How do we handle merge when the subtree hasn't diverged? |
|
899 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
900 |
||
901 |
"bzr merge --pull" will be changed so that it will merge (not pull) when the |
|
902 |
local last revision's revno would change (i.e. is a non-lhs parent in the merge |
|
903 |
source). This is expected to be the most common way to update nested trees. |
|
904 |
||
905 |
The existing "bzr merge --pull" behaviour will be renamed to "bzr merge |
|
906 |
--pull-renumber". |
|
907 |
||
908 |
"bzr merge" (with no "--pull") will do a merge in all trees. "bzr pull" will |
|
909 |
do a pull in all trees. |
|
910 |
||
911 |
The rationale is that a very common use-case is that the top tree is a project |
|
912 |
the user is actively committing to, and the subtrees are mainly libraries that |
|
913 |
are being mirrored. So a behaviour that forced every update to be a merge |
|
914 |
would be undesirable for the mirrored subtrees, but an update that is a pull |
|
915 |
wouldn't suit the changing top tree. And the existing "merge --pull" (that can |
|
916 |
renumber revisions) isn't desireable for either the top tree or subtrees in |
|
917 |
this case. |
|
918 |
||
919 |
||
920 |
What should uncommit do? |
|
921 |
~~~~~~~~~~~~~~~~~~~~~~~~ |
|
922 |
||
923 |
It will recurse, and subtrees will be uncommitted back to the revision recorded |
|
924 |
by the revision the top tree is uncommitting to. |
|
925 |
||
926 |
This means that operations like:: |
|
927 |
||
928 |
$ echo foo > versioned-file-in-top-tree.txt |
|
929 |
$ bzr ci -m "Change file" |
|
930 |
$ bzr uncommit |
|
931 |
||
932 |
will not cause a change in subtrees, since the top-level commit did not affect |
|
933 |
them. But on the other hand: |
|
934 |
||
935 |
$ echo foo > subtree/versioned-file-in-subtree.txt |
|
936 |
$ bzr ci -m "Change file" |
|
937 |
$ bzr uncommit |
|
938 |
||
6445.5.1
by Marius Kruger
fix some typos picked up while reading this again |
939 |
will first uncommit to the subtree, then to the top tree. The uncommit will |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
940 |
restore both trees to their previous state. |
941 |
||
942 |
||
943 |
Some subtrees should have commits and some should not. How? |
|
944 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
945 |
||
946 |
We will not provide special support for this initially. We might later support |
|
6445.5.1
by Marius Kruger
fix some typos picked up while reading this again |
947 |
flagging some sub-trees as mirror-only or something similar, but this seems like |
948 |
it could be a general feature not specific to nesting. (and it may only require |
|
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
949 |
a working tree format bump to add). |
950 |
||
951 |
Comparison with other systems |
|
952 |
***************************** |
|
953 |
||
954 |
Git submodules |
|
955 |
~~~~~~~~~~~~~~ |
|
956 |
||
6445.4.4
by Jelmer Vernooij
More updates. |
957 |
This allows separate repositories to be used for submodules. |
6445.4.1
by Jelmer Vernooij
Import nested tree doc from devnotes. |
958 |
|
959 |
Mercurial Forests |
|
960 |
~~~~~~~~~~~~~~~~~ |
|
961 |
||
962 |
The wiki page does not give confidence that this is a well-maintained project. |
|
963 |
It seems similar to config-manager-- its 'snapshot' files are like |
|
964 |
config-manager's config files, describing what branches to get and where to put |
|
965 |
them, optionally specifying a revision. No metadata about nesting is stored in |
|
966 |
the tree. Optionally, a 'snapshot.txt' file may be stored in the containing |
|
967 |
tree, but it can also be stored somewhere else. |
|
968 |
||
969 |
There is no attempt to integrate subtree support into the core commands. |
|
970 |
||
971 |
Mercurial Nested Repositories |
|
972 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
973 |
This design was for an integrated feature, but there are apparently 4 |
|
974 |
implementations as extensions. While it does integrate subtree support into |
|
975 |
core commands, this may be off by default: "The alternative that I lean towards |
|
976 |
is to not recurse unless explicitly instructed to. Most probably, only a few |
|
977 |
commands should arguably even be aware of modules." |
|
978 |
||
979 |
Command comparison: |
|
980 |
||
981 |
- hg module add ~= bzr join --nested |
|
982 |
- hg module remove ~= bzr remove --keep |
|
983 |
- hg module record's functionality is part of nested commits in nested trees. |
|
984 |
||
985 |
Like submodules, this stores location information in versioned data: a |
|
986 |
.hgmodules directory. |
|
987 |
Like submodules and nested trees, particular revisions are recorded. |
|
988 |
||
989 |
Subversion "svn:externals" |
|
990 |
~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
991 |
Like bzr, uses per-file metadata. Like submodules and nested repositories, |
|
992 |
locations are versioned data. Like Forests, revisions are optional. Like |
|
993 |
nested repositories, there is limited integration into core commands; checkout |
|
994 |
and update support externals, and commit may support them in the future. |
|
995 |
However, there is no UI specific to creating and updating svn:externals |
|
996 |
references. |
|
997 |
||
998 |
Unlike all other alternatives, supports partial checkouts. This is because svn |
|
999 |
natively supports partial checkouts. Also, supports checkouts of tags, because |
|
1000 |
tags are merely a convention in svn. |
|
1001 |
||
1002 |
Supports pulling in "head" subtrees too, not just specific ("known-good") |
|
1003 |
revisions. Nested trees supports this in order to provide high-fidelity |
|
1004 |
imports. |
|
1005 |
||
1006 |
Some support for single-file svn:externals (see |
|
1007 |
http://subversion.tigris.org/svn_1.6_releasenotes.html#externals), whereas bzr |
|
1008 |
subtrees must be directories. |
|
1009 |
||
1010 |
Has a --ignore-externals option for checking out without pulling in the |
|
1011 |
svn:externals items (svn checkout is more or less equivalent to bzr branch). |
|
1012 |
You can also use that option on update (more or less like bzr merge). |
|
1013 |
||
1014 |
||
1015 |
Comments on differences |
|
1016 |
~~~~~~~~~~~~~~~~~~~~~~~ |
|
1017 |
externals support partial checkouts. Nested trees could gain support for this |
|
1018 |
once Bazaar itself supports partial checkouts. Supporting a single file as a |
|
1019 |
"subtree" would also depend on native bzr support. On platforms that support |
|
1020 |
symlinks, using symlinks to portions of a subtree can be an effective |
|
1021 |
substitute. |
|
1022 |
||
1023 |
.. vim: ft=rst |