Merge lp:~abentley/bzr/devnotes into lp:~bzr-core/bzr/devnotes
- devnotes
- Merge into devnotes
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~abentley/bzr/devnotes |
Merge into: | lp:~bzr-core/bzr/devnotes |
Diff against target: | 1369 lines |
To merge this branch: | bzr merge lp:~abentley/bzr/devnotes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Robert Collins (community) | Abstain | ||
Review via email: mp+8766@code.launchpad.net |
Commit message
Description of the change
Aaron Bentley (abentley) wrote : | # |
Martin Pool (mbp) wrote : | # |
This looks like a really nice clear description of the plan. I'm not sure if you're looking to merge it in as an indication it's definitely agreed this is what we'll do, or if you want to merge it as a work-in-progress for the spec.
I still have some doubts about whether recursing downwards is really what people want and/or is the safest strategy for introducing the feature. Maybe once we get this document merged in you can do a specific survey of users on that point. I realize it's been discussed before but the results seem to be mixed.
+seems likely that Bazaar will one day support them file copies, and when it
s/them//
134 +The branches associated with subtrees shall be called "subbranches".
135 +
136 +The branch for the top tree will be in a special format, whose last_revision
137 +file lists all the last_revision info for all of the branches associated with
138 +the nested tree. The .bzr directories of subtrees will have a "branch" that
139 +simply indicates that the top tree's branch should be used.
140 +
141 +In the top tree's last_revision file, the revision id and revno will be
142 +provided, indexed by the tree-reference file-id.
143 +
144 +The repository used by the top-tree's branch must be a shared repository, and
145 +will be used by the sub-branches.
146
I like this better than having separate whole branch control directories.
We'll probably have colocated branches in the same timeframe as this change so we should make sure they will mesh well.
Maybe add sub-branch to the glossary at the top?
But I think we need to back up here and clarify what these branches mean. (Unless you do that later.) I think what you want is:
When you commit in a subtree, it updates the sub-branch pointer. When you run log/etc/
If you're looking at an already-committed version of the containing tree, it'll find the subtrees by looking in the containing tree's inventory.
This seems to imply that the sub-branches are almost just working tree data -- if you're not interested in commits that haven't been wrapped up in a containing tree commit yet, you don't need to see them.
So would it be enough then to just have plain trees with branches in there?
Presumably this adds a constraint on repositories (or clarifies a constraint) that a repository that contains a nested tree revision should hold all the data needed for the subtrees.
202 +Implementation strategies
203 +******
204 +
It's not clear here if you're going to describe several alternative implementation strategies...
230 +The obvious way to prevent slowness when there are no subtrees is to provide a
231 +fast way of determining whether there are subtrees. This could be provided by
232 +additional on-disk indices, or potentially by providing a flag indicating
233 +whether there are subtrees. Such a flag could be updated by Tree.iter_entries,
234 +to avoid re-running Tree.iter_entries. A parallel flag for iter_changes is
235 +also conceivable, but would be more com...
Aaron Bentley (abentley) wrote : | # |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Martin Pool wrote:
> This looks like a really nice clear description of the plan. I'm not sure if you're looking to merge it in as an indication it's definitely agreed this is what we'll do,
Yes.
> I still have some doubts about whether recursing downwards is really what people want and/or is the safest strategy for introducing the feature. Maybe once we get this document merged in you can do a specific survey of users on that point. I realize it's been discussed before but the results seem to be mixed.
You have asked me to reconsider it before. The last time, I took your
advice and asked Andrew Bennets' opinion, doing my best to fairly lay
out the pros and cons of each strategy, and he chose downwards
recursion. Please accept that.
I recognize that you have doubts, but I have doubts about doing it the
other way. We've reviewed it multiple times, and each time the outcome
was downwards recursion.
> +seems likely that Bazaar will one day support them file copies, and when it
>
> s/them//
>
Fixed.
> 134 +The branches associated with subtrees shall be called "subbranches".
> 135 +
> 136 +The branch for the top tree will be in a special format, whose last_revision
> 137 +file lists all the last_revision info for all of the branches associated with
> 138 +the nested tree. The .bzr directories of subtrees will have a "branch" that
> 139 +simply indicates that the top tree's branch should be used.
> 140 +
> 141 +In the top tree's last_revision file, the revision id and revno will be
> 142 +provided, indexed by the tree-reference file-id.
> 143 +
> 144 +The repository used by the top-tree's branch must be a shared repository, and
> 145 +will be used by the sub-branches.
> 146
>
> I like this better than having separate whole branch control directories.
>
> We'll probably have colocated branches in the same timeframe as this change so we should make sure they will mesh well.
>
> Maybe add sub-branch to the glossary at the top?
Done
>
> But I think we need to back up here and clarify what these branches mean. (Unless you do that later.) I think what you want is:
>
> When you commit in a subtree, it updates the sub-branch pointer. When you run log/etc/
>
> If you're looking at an already-committed version of the containing tree, it'll find the subtrees by looking in the containing tree's inventory.
Agreed.
> This seems to imply that the sub-branches are almost just working tree data -- if you're not interested in commits that haven't been wrapped up in a containing tree commit yet, you don't need to see them.
>
> So would it be enough then to just have plain trees with branches in there?
If you mean trees whose branches are in the same .bzr, that is problematic.
- - We want a guarantee that all the branches share a single repository
- - It doesn't provide synchonized control of push/pull/submit locations
- - Bzr will create or delete the branches at will, trashing any user
custo...
- 35. By Aaron Bentley
-
Updates from review
Robert Collins (lifeless) : | # |
Martin Pool (mbp) wrote : | # |
I'll merge this into devnotes; it may need some more thought about foreign branch support but it's worth checkpointing this.
Preview Diff
1 | === modified file 'nested-trees.txt' |
2 | --- nested-trees.txt 2009-05-29 15:50:06 +0000 |
3 | +++ nested-trees.txt 2009-08-25 03:35:20 +0000 |
4 | @@ -2,43 +2,121 @@ |
5 | Nested Trees |
6 | ************ |
7 | |
8 | +.. sectnum:: |
9 | + |
10 | +.. contents:: |
11 | + |
12 | Principles |
13 | ********** |
14 | |
15 | - Never store a location in versioned data. |
16 | |
17 | - Implementation of nested trees shall not make operations observably slower |
18 | - for those not using nested trees. (Using nested trees will impact performance |
19 | - in the initial implementation, but the design will allow a performant |
20 | - implementation.) |
21 | + for those not using nested trees. (Using nested trees will impact |
22 | + performance in the initial implementation, but the design will allow a |
23 | + performant implementation.) |
24 | |
25 | - A repository that holds a revision R should be able to reconstruct the |
26 | whole contents of that revision, including any nested trees. Corolary: |
27 | if I fetch that revision, even into a branch that has no working tree, it |
28 | should bring across any referenced revisions. |
29 | |
30 | -- A project with zero nested trees must pay zero performance cost when |
31 | - using a format supporting them. |
32 | - |
33 | -Design |
34 | -****** |
35 | - |
36 | -(See also <http://bazaar-vcs.org/NestedTreesDesign>) |
37 | - |
38 | -Inventory entries of type 'tree reference' have a file-id and a revision-id. |
39 | - |
40 | -In the working tree, subtrees are represented as a subdirectory. The top |
41 | -containing tree's branch will be in a format that contains: |
42 | - |
43 | - - the last-revision pointers for all the nested branches indexed by the file-id |
44 | - of their tree reference. |
45 | - - the subbranches will use the same repository as the top tree. This |
46 | - repository may be at the top tree, or a shared repository used by the top |
47 | - tree. |
48 | - |
49 | -On disk, the subtrees will simply indicate that their data is stored in a top |
50 | -tree. The top tree for a subtree is located by walking parent dirs until a top |
51 | -tree is found. |
52 | +Core Concepts |
53 | +************* |
54 | + |
55 | +**Subtree** A tree which is inside another tree, which bzr has been asked to |
56 | +treat as part of the outer tree. |
57 | + |
58 | +**Subbranch** The branch associated with a subtree. |
59 | + |
60 | +**Containing tree** A tree which has another tree inside it |
61 | + |
62 | +**Tree reference** A directory in a containing tree which contains a subtree. |
63 | + |
64 | +**Composite tree** A tree which behaves as a single tree, but is actually made |
65 | +up of several trees. |
66 | + |
67 | + |
68 | +Basic design approach |
69 | +********************* |
70 | +(see "Design decisions" for extended rationale) |
71 | +By default, commands in containing trees should behave as though the subtrees |
72 | +were plain directories. By default, commands in subtrees should not affect the |
73 | +containing trees. |
74 | + |
75 | +Downwards recursion |
76 | +~~~~~~~~~~~~~~~~~~~ |
77 | +One of the objectives of nested trees is to provide ways of reproducing |
78 | +historical combinations of different codebases. The dependency chain points |
79 | +downwards, such that trees are affected by the revision of their subtrees, but |
80 | +subtrees are oblivious to their containing trees. Just as bazaar doesn't |
81 | +entice people to commit inconsistent trees, it should not entice people to |
82 | +commit inconsistent combinations of containing tree and subtree. Therefore, |
83 | +commit should recurse downwards by default. |
84 | + |
85 | +Status and diff should reflect what will happen when commit is used, so they |
86 | +should also recurse downward by default. Add almost does this already. With |
87 | +status, diff, commit and add recursing downwards, it would be confusing to |
88 | +users if other operations did not. Therefore, all operations should recurse |
89 | +downwards by default. |
90 | + |
91 | +No upwards recursion by default |
92 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
93 | +One of the reasons for using nested trees is to gain performance by only |
94 | +committing in a subtree. Therefore, operations should not recurse upwards by |
95 | +default. However, some users do want to have upwards recursion, so it should |
96 | +be provided as an option. |
97 | + |
98 | +Modelling nested trees as a composite tree. |
99 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
100 | +The idea that a set of nested trees behaves like a single, larger tree seems |
101 | +relatively easy to grasp. Both for users and for developers, it provides a |
102 | +clear expectation for the behaviour of nested trees. There are no obvious |
103 | +drawbacks in terms of code clarity or performance. Therefore, it seems like a |
104 | +good model to start with. |
105 | + |
106 | +There are cases where users place multiple copies of a source tree inside |
107 | +another tree, and treating a set of nested trees like a single large tree is in |
108 | +conflict with that. It is essentially the same as supporting file copies, and |
109 | +file copies themselves are a big and complicated feature to implement. It |
110 | +seems likely that Bazaar will one day support file copies, and when it does, |
111 | +this conflict will disappear. Implementing limited support for copies via |
112 | +nesting would have similar complexity to implementing general support for file |
113 | +copies, but would have fewer fruits. It would lead to complication when true |
114 | +support for file copies is implemented. It does not seem appropriate for |
115 | +initial nested-tree support. On the other hand, it could be implemented later; |
116 | +none of the data model changes are in conflict with that. |
117 | + |
118 | +Using root file-ids for tree-references |
119 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
120 | +The idea that tree-reference file-ids are the same as the file-ids of the |
121 | +corresponding root directories has a nice symmetry. It is one way of ensuring |
122 | +that "bzr split" is deterministic, and "bzr join" is deterministic. When |
123 | +performing operations involving a tree and a split version of that tree, using |
124 | +the same file-id makes it easy to ensure that operations such as moves and |
125 | +renames are applied appropriately to the tree-reference. Providing mechanisms |
126 | +whereby a tree-reference can be treated as it would if it had its old file-id |
127 | +encroaches on the territory of path tokens or file-id aliases. Having "split" |
128 | +cause file-id changes means that in comparing these revisions, it would be seen |
129 | +as a deleting a directory and creating a new tree-reference with the same name. |
130 | +Handling this correctly in operations such as merge and revert would be more |
131 | +complicated than if it were treated as a kind change, especially when |
132 | +unversioned files are present in the subtree. |
133 | + |
134 | +Sub-branches |
135 | +~~~~~~~~~~~~ |
136 | +The branches associated with subtrees shall be called "subbranches". |
137 | + |
138 | +The branch for the top tree will be in a special format, whose last_revision |
139 | +file lists all the last_revision info for all of the branches associated with |
140 | +the nested tree. The .bzr directories of subtrees will have a "branch" that |
141 | +simply indicates that the top tree's branch should be used. |
142 | + |
143 | +In the top tree's last_revision file, the revision id and revno will be |
144 | +provided, indexed by the tree-reference file-id. |
145 | + |
146 | +The repository used by the top-tree's branch must be a shared repository, and |
147 | +will be used by the sub-branches. |
148 | |
149 | Only the top branch will have a branch.conf. When an operation on a subbranch |
150 | would normally use values from branch.conf it will look them up in the top |
151 | @@ -46,25 +124,871 @@ |
152 | push" in a subtree will push just that subbranch to the corresponding subbranch |
153 | in the configured push location of the top branch. |
154 | |
155 | -Process |
156 | -******* |
157 | - |
158 | -How do we best manage the risk associated with this complex feature? |
159 | - |
160 | -Is it by getting something out there and planning/expecting a few |
161 | -iterations to smooth out issues? Is it by taking more time before |
162 | -coding and landing patches to discuss the design? Or a mix of these? |
163 | - |
164 | -We need to be careful. On the one hand, we don't want to put user |
165 | -data at risk and that's possible if the core data model (not caches) |
166 | -is flawed. On the other, we don't want to get bogged down worrying |
167 | -about obscure edge cases now at the expense of solving the common |
168 | -cases well. This feature will be a classic case of 90% of users |
169 | -only needing 10% of the capability IMNSHO. (igc) |
170 | - |
171 | - |
172 | -Undecided questions |
173 | -******************* |
174 | +Rationale |
175 | +......... |
176 | +If the branches were not local, the local subtrees might not be committable, |
177 | +and commits to the remote branch would make the local subtree out of date. |
178 | +They should not be in a separate location from the containing branch, because |
179 | +they might share history with the tree-reference's branch. However, those |
180 | +local branches should not be at the same location as their tree, because the |
181 | +tree might be deleted or moved. Indeed, they should not be anywhere within a |
182 | +working tree. |
183 | + |
184 | +subtree branches should not be above or beside their containing branch, because |
185 | +it could cause terrible confusion if subtrees from two different trees were |
186 | +updating the same branches with every push, pull, commit and uncommit. |
187 | + |
188 | +Subtree branches could be plain branches stored somewhere in the top tree's |
189 | +branch, but then a lookup mechanism would be needed to translate from file_id |
190 | +to location, and performance with large numbers of subbranches would be poor. |
191 | + |
192 | +Pull and non-initial push |
193 | +~~~~~~~~~~~~~~~~~~~~~~~~~ |
194 | +When a pull involves updates to tree references, pull will always pull into the |
195 | +reference branch. For all new revisions in the upper branch, it will determine |
196 | +the revision values of tree references, and fetch them into the repository. |
197 | + |
198 | +When new tree references are encountered, pull should create a corresponding |
199 | +subbranch in the top branch. |
200 | + |
201 | +Pulls will update the subtrees whose tree-references change, including creating |
202 | +trees for new sub-branches. |
203 | + |
204 | +Implementation strategies |
205 | +************************* |
206 | + |
207 | +Start from the top |
208 | +~~~~~~~~~~~~~~~~~~ |
209 | +In the initial implementation, recursion into subtrees should be implemented at |
210 | +the highest level possible. This will make experimentation easier, reduce the |
211 | +chance for regressions in core code, and reduce the number of public API |
212 | +changes. This will entail some redundant post-operation determination of |
213 | +whether subtrees are present. Speed of operations involving subtrees is not a |
214 | +major concern, but operations that do not use subtrees must not be observably |
215 | +slower. |
216 | + |
217 | +Aaron Bentley believes that recursion at the top level is also easier to |
218 | +understand and debug, but Robert Collins and Vincent Ladeuil disagree. |
219 | + |
220 | +As time goes on and the design is proven, operations can be rewritten as more |
221 | +intrusive changes, in order to provide better performance or better handling of |
222 | +edge cases. It may make sense to implement them on NestedTrees, so that they |
223 | +can take advantage of its subtree caching. |
224 | + |
225 | +However, some low-level operations would be dubious to implement as recursive. |
226 | +For example, a recursive Tree.id2path might open several subtrees in order to |
227 | +determine a single path. It would be better to support a batch operation in |
228 | +NestedTrees. |
229 | + |
230 | +Fast subtree detection |
231 | +~~~~~~~~~~~~~~~~~~~~~~ |
232 | +The obvious way to prevent slowness when there are no subtrees is to provide a |
233 | +fast way of determining whether there are subtrees. This could be provided by |
234 | +additional on-disk indices, or potentially by providing a flag indicating |
235 | +whether there are subtrees. Such a flag could be updated by Tree.iter_entries, |
236 | +to avoid re-running Tree.iter_entries. A parallel flag for iter_changes is |
237 | +also conceivable, but would be more complicated, since iter_changes is relative |
238 | +to another Tree. Further, during ``iter_changes`` it is possible to have |
239 | +subtrees that were not encountered because they were unchanged between the |
240 | +trees (as ``iter_changes`` does not always walk the entire tree). |
241 | + |
242 | +Composite Locking |
243 | +~~~~~~~~~~~~~~~~~ |
244 | +Locking a NestedTrees should lock all subtrees, to reduce the potential for new |
245 | +failure modes. This suggests the need for an on-disk index of subtrees. |
246 | + |
247 | +CompositeTree |
248 | +~~~~~~~~~~~~~ |
249 | +For some operations such as diff, status and export, knowing which directories |
250 | +are tree references is not essential. They can be satisfied by a Tree |
251 | +implementation that papers over tree-references, making the set of nested trees |
252 | +look like a single big tree with directories instead of tree-references. This |
253 | +implementation strategy has a limited scope, and probably a limited shelf life, |
254 | +but provides a fast way of getting coverage of several important commands. |
255 | + |
256 | +Scope |
257 | +***** |
258 | +Ultimately, all commands should support nested trees. Initial work is focused |
259 | +on: |
260 | + |
261 | +- checkout |
262 | +- branch |
263 | +- push |
264 | +- pull |
265 | +- merge |
266 | +- revert |
267 | +- mv |
268 | +- status |
269 | +- diff |
270 | +- commit |
271 | +- export |
272 | + |
273 | + |
274 | +Data storage |
275 | +************ |
276 | + |
277 | +Trees |
278 | +~~~~~ |
279 | +The root-ids of trees must be unique, so that the same file-id can be used in |
280 | +both the containing tree and the subtree, to simplify access within trees. |
281 | +Tree references are an inventory type that is distinct from a directory, and |
282 | +has a revision-id associated with it. |
283 | +All modern working trees support tree references. Indices may be provided to |
284 | +ensure fast access to the list of subtrees. |
285 | + |
286 | +Because of the need to use branches for recursion, it would be desirable to |
287 | +associate RevisionTrees with branches. The alternative is for many operations |
288 | +to accept Tree + Branch as input, and return Tree, Branch pairs. |
289 | + |
290 | +Branches |
291 | +~~~~~~~~ |
292 | +A new branch format, "subbranches", is introduced which provides multiple |
293 | +sub-branches, with their data referenced by file-id. A new branch refrerence |
294 | +format, "subbranch-reference", is introduced which refers to sub-branches in a |
295 | +"subbranches" branch. |
296 | + |
297 | +Repositories |
298 | +~~~~~~~~~~~~ |
299 | +Some repository formats have 'subtree' variants, e.g. pack-0.92-subtree, |
300 | +development-subtree. These are hidden, experimental formats that support |
301 | +storing tree-references in their inventory formats. The most recent format |
302 | +which supports subtrees is RepositoryFormatKnitPack3. |
303 | + |
304 | +Repository indexing might be extended to provide fast access to |
305 | +tree-references. |
306 | + |
307 | +Commands |
308 | +******** |
309 | + |
310 | +The following new commands are introduced: |
311 | + |
312 | +``split`` Convert a single working tree into two trees, one inside the other. |
313 | + |
314 | +``join --nested`` Cause an inner tree to be treated as a subtree. The outer |
315 | +tree's branch must be in the new "subbranches" format. The inner tree's branch |
316 | +will be cloned into the "subbranches" branch, and the local branch will be |
317 | +replaced with a "subbranch-reference". Finally, a tree-reference will be |
318 | +added to the containing tree. |
319 | + |
320 | +API Changes |
321 | +*********** |
322 | + |
323 | +Introduce NestedTrees |
324 | +~~~~~~~~~~~~~~~~~~~~~ |
325 | +New class to provide services for sets of nested trees, including coordinating |
326 | +locking, caching Tree instances, and mapping file-ids and paths to the |
327 | +appropriate Tree and Branch. Includes:: |
328 | + |
329 | + NestedTrees.lock_read |
330 | + |
331 | + NestedTrees.lock_write |
332 | + |
333 | + NestedTrees.unlock |
334 | + |
335 | + NestedTrees.paths_info(self, paths) |
336 | + - return a list of tuples of Tree, relpaths, where relpaths is a list of |
337 | + relative paths, and Tree is the subtree that contains them. |
338 | + |
339 | + NestedTrees.get_tree_and_treepath |
340 | + - return the tree and relative path within that tree of a file-id |
341 | + |
342 | + NestedTrees.apply_inventory_delta |
343 | + - splits an inventory delta into the affected subtrees and applies it to them |
344 | + all |
345 | + |
346 | + NestedTrees.iter_changes |
347 | + - provide iter_changes over a set of nested subtrees. Emits tree-references |
348 | + in preference to tree roots. |
349 | + |
350 | + |
351 | +Introduce NestedTreeTransform |
352 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
353 | +New class to permit smooth recursion of TreeTransform operations like merge and |
354 | +revert even when the subtree boundaries differ. API essentially the same as |
355 | +TreeTransform, except that tree-references can have children, as directories |
356 | +do. |
357 | + |
358 | +Introduce CompositeTree |
359 | +~~~~~~~~~~~~~~~~~~~~~~~ |
360 | +New class to provide easy transition of superficial commands like diff, status, |
361 | +export. API is a subset of Tree API. Additional methods:: |
362 | + |
363 | + CompositeTree.maybe_composite |
364 | + |
365 | + - return a CompositeTree if the input tree has subtrees, otherwise return the |
366 | + input Tree. This restricts the scope of any regressions to Trees that |
367 | + are actually using the features. |
368 | + |
369 | +New Tree methods |
370 | +~~~~~~~~~~~~~~~~ |
371 | + |
372 | + get_nested_tree_and_branch(file_id, branch) |
373 | + |
374 | + - Return a Tree and Branch for the tree-reference with the specified file_id |
375 | + |
376 | +Tree changes |
377 | +~~~~~~~~~~~~ |
378 | + |
379 | + WorkingTree will cache the list of tree-references, to accelerate |
380 | + WorkingTree.iter_references. This may be an in-memory cache, or it may |
381 | + require a new format. |
382 | + |
383 | + WorkingTree.pull recurses downwards by default. Subtrees are pulled from the |
384 | + reference location of the specified branch. |
385 | + |
386 | + MutableTree.commit recurses downwards by default. |
387 | + |
388 | + WorkingTree.revert recurses downwards by default. |
389 | + |
390 | + Merger recurses downwards by default. This is not equivalent to running merge |
391 | + in each of the subtrees-- it uses the tree-reference revision-id to determine |
392 | + which revision to merge into each subtree, recursively. Merger should not |
393 | + care whether subtree boundaries have changed. Like WorkingTree.pull, it |
394 | + fetches from the reference location of the branch associated with the tree. |
395 | + |
396 | +New Branch methods |
397 | +~~~~~~~~~~~~~~~~~~ |
398 | + get_subbranch |
399 | + |
400 | + - Return branch for tree reference |
401 | + |
402 | +Branch changes |
403 | +~~~~~~~~~~~~~~ |
404 | + |
405 | + pull recurses into reference branches, and pulls *from* the source's reference |
406 | + branches. |
407 | + |
408 | +Repository changes |
409 | +~~~~~~~~~~~~~~~~~~ |
410 | + |
411 | + fetch provides a list of tree-reference revision ids/file-id pairs for the |
412 | + revisions that were fetched. Fetch automatically fetches all revisions |
413 | + associted with tree-references that were fetched. |
414 | + |
415 | +Use Cases |
416 | +********* |
417 | + |
418 | +Case 1 |
419 | +~~~~~~ |
420 | +Barry works on a project with three libraries. He wants to keep up to date |
421 | +with the tip of those libraries, but he doesn't want them to be part of his |
422 | +source tree. |
423 | + |
424 | +Example commands:: |
425 | + |
426 | + Set up the tree: |
427 | + $ bzr branch --nested http://library1 project |
428 | + $ bzr branch --nested http://library2 project |
429 | + $ bzr branch --nested http://library3 project |
430 | + $ bzr commit project -m "Added three libraries" |
431 | + |
432 | + Update a library to tip: |
433 | + $ bzr pull -d project/library1 http://library1 |
434 | + |
435 | +Case 2 |
436 | +~~~~~~ |
437 | +Now, Barry wants to add a fourth library. |
438 | + |
439 | +Example commands:: |
440 | + |
441 | + $ bzr branch --nested http://library4 project |
442 | + |
443 | +Case 3 |
444 | +~~~~~~ |
445 | +Barry wants to publish his project. |
446 | + |
447 | +Example commands:: |
448 | + |
449 | + $ bzr push -d project bzr+ssh://project/trunk |
450 | + |
451 | +Case 4 |
452 | +~~~~~~ |
453 | +Barry decides to make part of his project into another library |
454 | + |
455 | +Example commands:: |
456 | + |
457 | + $ bzr split --nested project/newlibrary |
458 | + |
459 | +Case 5 |
460 | +~~~~~~ |
461 | +Curtis wants to hack on Barry's project |
462 | + |
463 | +Example commands:: |
464 | + |
465 | + $ bzr branch http://project/trunk |
466 | + |
467 | +Case 6 |
468 | +~~~~~~ |
469 | +Barry wants to drop one of the libraries he was using |
470 | + |
471 | +Example commands:: |
472 | + |
473 | + $ rm project/library1 |
474 | + $ bzr commit project -m "Removed library1" |
475 | + |
476 | +Case 7 |
477 | +~~~~~~ |
478 | +Curtis has made changes to one of the libraries. Barry wants to merge Curtis' |
479 | +changes into his copy. |
480 | + |
481 | +Example commands:: |
482 | + |
483 | + $ bzr merge -d project http://curtis.org/trunk#library2 |
484 | + |
485 | + Or alternatively: |
486 | + $ bzr merge -d project/library2 http://curtis.org/trunk#library2 |
487 | + |
488 | +Case 8 |
489 | +~~~~~~ |
490 | +Curtis has made changes to Barry's main project. Barry wants to merge Curtis' |
491 | +changes into his copy. |
492 | + |
493 | +Example commands:: |
494 | + |
495 | + $ bzr merge -d project http://curtis.org/trunk |
496 | + |
497 | + |
498 | +Case 9 |
499 | +~~~~~~ |
500 | +Barry makes changes in his project and in a library, and he runs status |
501 | + |
502 | +Example commands:: |
503 | + |
504 | + $ echo bar > project/foo |
505 | + $ echo qux > project/library2/baz |
506 | + $ bzr status project |
507 | + M foo |
508 | + M library2/baz |
509 | + |
510 | +Case 10 |
511 | +~~~~~~~ |
512 | +Barry wants to upgrade the bazaar format of his project |
513 | + |
514 | +Example commands:: |
515 | + |
516 | + $ bzr upgrade project |
517 | + |
518 | +Case 11 |
519 | +~~~~~~~ |
520 | +Curtis wants to apply Barry's latest changes. |
521 | + |
522 | +Example commands:: |
523 | + |
524 | + $ bzr merge -d project http://project/trunk |
525 | + |
526 | +Case 12 |
527 | +~~~~~~~ |
528 | +Danilo wants to start a project with two libraries using nested trees from |
529 | +scratch. |
530 | + |
531 | +Example commands:: |
532 | + |
533 | + $ bzr init project |
534 | + $ bzr branch --nested http://library4 project |
535 | + $ bzr branch --nested http://library5 project |
536 | + $ bzr commit project -m "Created new project." |
537 | + |
538 | +Case 13 |
539 | +~~~~~~~ |
540 | +Edwin has a project that doesn't use nested trees and he wants to start using |
541 | +nested trees. |
542 | + |
543 | +Example commands:: |
544 | + $ bzr split --nested project/subdir |
545 | + |
546 | +Case 14 |
547 | +~~~~~~~ |
548 | +Françis has a project with nested trees where the containing tree uses one |
549 | +Bazaar format and the subtree uses a different Bazaar format. |
550 | + |
551 | +Not supported. |
552 | + |
553 | +Case 15 |
554 | +~~~~~~~ |
555 | +Barry commits some changes to a library and to the main project, and then |
556 | +discovers the changes are not appropriate. He has not yet pushed his changes |
557 | +anywhere. |
558 | + |
559 | +Example commands:: |
560 | + |
561 | + $ bzr merge -d project http://library2 |
562 | + $ bzr commit project -m "Updated library2" |
563 | + $ bzr uncommit project --force |
564 | + |
565 | +Case 16 |
566 | +~~~~~~~ |
567 | +Barry commits some changes to a library and to the main project, publishes his |
568 | +branch, and then discovers the changes are not appropriate. |
569 | + |
570 | +Example commands:: |
571 | + |
572 | + $ bzr merge -d project http://library2 |
573 | + $ bzr commit project -m "Updated library2" |
574 | + $ bzr push -d project |
575 | + $ bzr revert project |
576 | + $ bzr commit project -m "Reverted inappropriate changes." |
577 | + $ bzr push -d project |
578 | + |
579 | +Case 17 |
580 | +~~~~~~~ |
581 | +Gary is writing a project. Henninge wants to split a library out of it. |
582 | + |
583 | +Example commands:: |
584 | + |
585 | + $ bzr branch project |
586 | + $ bzr split project/library6 |
587 | + $ mv project/library6 . |
588 | + $ rm project |
589 | + $ bzr commit -m "split library6 into its own library." |
590 | + |
591 | +Case 18 |
592 | +~~~~~~~ |
593 | +Henning wants to update to receive Gary's latest changes. |
594 | + |
595 | +Example commands:: |
596 | + |
597 | + $ bzr merge -d library6 |
598 | + |
599 | +Case 19 |
600 | +~~~~~~~ |
601 | +Gary wants to update to receive Henninge's changes, including splitting a |
602 | +library out. |
603 | + |
604 | +Example commands:: |
605 | + |
606 | + $ bzr split --nested project/library6 |
607 | + $ bzr commit project -m "Turned library6 into a library" |
608 | + $ bzr merge -d project/library6 http://library6 |
609 | + $ bzr commit project -m "Merge Henninge's changes." |
610 | + |
611 | + |
612 | +Case 20 |
613 | +~~~~~~~ |
614 | +Gary wants to update to receive Henninge's changes, without splitting a library |
615 | +out. |
616 | + |
617 | + $ bzr split --nested project/library6 |
618 | + $ bzr commit project -m "Turned library6 into a library" |
619 | + # i.e. a cherrypick that skips the revision where library6 became a library. |
620 | + $ bzr merge -d project/library6 http://library6 -r 5..-1 |
621 | + $ bzr commit project -m "Merge Henninge's changes." |
622 | + |
623 | +Case 21 |
624 | +~~~~~~~ |
625 | + |
626 | +John works on a project called FooBar, but has decided that it would be better |
627 | +structured as two projects, where Bar is a library that may be of general use |
628 | +outside of Foo. As it happens, bar already has its own subdirectory. |
629 | + |
630 | +He runs: |
631 | +:: |
632 | + |
633 | + # Convert into two trees: foobar and foobar/bar. |
634 | + # In each tree, files will be removed and deleted. In foobar/bar, "bar" |
635 | + # will have been moved to become the tree root. |
636 | + # These changes will be committed later. |
637 | + $ bzr upgrade foobar --format=subbranches |
638 | + $ bzr split foobar/bar |
639 | + |
640 | + # Add a tree-reference from foobar to foobar/bar, change bar's branch |
641 | + # to a reference to subbranch in foobar's branch. |
642 | + $ bzr join --nested foobar/bar |
643 | + |
644 | + # This recurses into foobar/bar and commits the deletion of the containing |
645 | + # tree. In foobar, it commits a kind change for 'bar' from directory to |
646 | + # tree-reference, and the deletion of the contents of bar. |
647 | + $ bzr commit foobar |
648 | + |
649 | +This commits new revisions to foobar and bar, and foobar's tree-reference bar |
650 | +refers to the revision-id of bar. |
651 | + |
652 | +Next, he adds two new files: foobar/baz and foobar/bar/qux:: |
653 | + |
654 | + $ vi foobar/baz |
655 | + $ vi foobar/bar/qux |
656 | + # This adds qux to foobar/bar and adds baz to foobar. |
657 | + $ bzr add foobar |
658 | + |
659 | +Since foobar/bar/qux is in a commitable state and foobar/baz is not, he invokes |
660 | +:: |
661 | + |
662 | + $ bzr commit foobar/bar |
663 | + |
664 | +This commits foobar/bar/baz/qux to the subtree and commits foobar/bar to the |
665 | +containing tree. |
666 | + |
667 | +(Had he wanted to commit to just the subtree, or just the containing tree, he |
668 | +could have specified an option.) |
669 | + |
670 | + |
671 | +Case 21 |
672 | +~~~~~~~ |
673 | + |
674 | +Robert wants to hack on a project, Baz, that is structured as a nested tree, |
675 | +which uses the library "quxlib", from quxlib.org. |
676 | + |
677 | +He runs: |
678 | +:: |
679 | + |
680 | + $ bzr branch http://baz.org/dev baz |
681 | + |
682 | +This creates a "subbranches" branch and working tree for baz, as normal. Since |
683 | +tree-references were encountered, it adds subbranches for them to the baz |
684 | +branch. All data is retrieved from baz.org, not quxlib.org. |
685 | + |
686 | +It creates a working tree for quxlib with a subbranch-reference. It uses the |
687 | +revision-id from the tree-reference in the containing tree, not the head |
688 | +revision at baz.org. This allows Robert to get a known-good nested tree. |
689 | + |
690 | +Later, Robert decides to update the version of quxlib being used to the latest |
691 | +from quxlib.org. He runs:: |
692 | + |
693 | + $ bzr pull -d http://quxlib.org |
694 | + |
695 | +This updates the version of quxlib in the working tree, which mean that baz is |
696 | +now out-of-date with its last-committed tree. Unfortunately, the new rev on |
697 | +quxlib is not completely compatible with the old one, and Robert must tweak a |
698 | +few files before Baz runs properly. Once he has done so, he runs:: |
699 | + |
700 | + $ bzr commit baz |
701 | + |
702 | +Now he has committed a known-good nested tree, and the baz working tree is once |
703 | +again up-to-date. |
704 | + |
705 | + |
706 | +User documentation |
707 | +****************** |
708 | + |
709 | +For many large projects, it is often useful to incorporate libraries |
710 | +maintained elsewhere or to construct them from multiple subprojects. |
711 | +While it is easy for a single user to set up a particular layout of |
712 | +multiple branches by hand, the different branches really need to be |
713 | +linked together if others are to reproduce the desired layout, and |
714 | +if the relationships are going to be managed over time. |
715 | + |
716 | +Bazaar has good support for building and managing external libraries |
717 | +and subprojects via a feature known as *nested trees*. In particular, |
718 | +nearly all of Bazaar's commonly used commands understand nested trees |
719 | +and Do The Right Thing as explained below. The relationship is hierarchical: |
720 | +the containing tree knows about its nested trees, but nested trees are unaware |
721 | +of the tree (or trees) containing them. |
722 | + |
723 | +At the moment, *nested trees* are the only type of nested item |
724 | +supported though *nested files* may be supported in the future. |
725 | +Nested trees may contain other nested trees as required. |
726 | + |
727 | +Note: This feature requires a recent branch format such as ``2.0`` |
728 | +or later. |
729 | + |
730 | + |
731 | +Nesting an external project |
732 | +--------------------------- |
733 | + |
734 | +To link an external project into a branch, use the ``branch`` command |
735 | +with the ``--nested`` option like this:: |
736 | + |
737 | + bzr branch --nested SOURCE-URL TARGET-DIR |
738 | + |
739 | +For example, assuming you already have a ``src/lib`` directory where |
740 | +libraries are kept:: |
741 | + |
742 | + bzr branch --nested http://example.com/xmlsaxlib src/lib/sax |
743 | + |
744 | +This will create a nested branch in the ``src/lib/sax`` directory, |
745 | +join it into the containing branch and save the source location. |
746 | + |
747 | +If you now run ``bzr status``, it will show the nested branch as |
748 | +uncommitted changes like this:: |
749 | + |
750 | + + src/lib/sax |
751 | + + src/lib/sax/README |
752 | + + src/lib/sax/parser.py |
753 | + ... |
754 | + |
755 | +To record this change, use the ``commit`` command as you normally would:: |
756 | + |
757 | + bzr commit -m "added SAX parsing library" |
758 | + |
759 | +Note that Bazaar stores the tip revision of each nested branch. This |
760 | +is an important feature in that it's then easy to reproduce the exact |
761 | +combination of libraries used for historical revisions. It also means |
762 | +that other developers pulling or merging your changes will get nested |
763 | +branches created for them at the right revisions of each. |
764 | + |
765 | + |
766 | +Refreshing a nested branch |
767 | +-------------------------- |
768 | + |
769 | +As bugs are fixed and enhancements are made to nested projects, you |
770 | +will want to update the version being used. To do this, ``pull`` the |
771 | +latest version of the nested branch. For example:: |
772 | + |
773 | + bzr pull -d src/lib/sax |
774 | + |
775 | +If the latest revision is too unstable, you can always use the ``-r`` |
776 | +option on the ``pull`` command to nominate a particular revision or tag. |
777 | + |
778 | +Now that you have the required version of the code, you can make |
779 | +any required adjustments (e.g. API changes), run your automated tests |
780 | +and commit something like this:: |
781 | + |
782 | + view src/lib/sax/README |
783 | + (hack, hack, hack) |
784 | + make test |
785 | + bzr commit -m "upgraded SAX library to version 2.1.3" |
786 | + |
787 | + |
788 | +Changing a nested tree |
789 | +---------------------- |
790 | + |
791 | +As well as keeping track of which revisions of external libraries |
792 | +are used over time, one of the reasons for nesting projects is to |
793 | +make minor changes. You may want to do this in order to fix and |
794 | +track particular bugs you need addressed. In other cases, you may want |
795 | +to make various local enhancements that aren't valuable outside |
796 | +the context of your project. |
797 | + |
798 | +As support for nested branches is integrated into most commonly |
799 | +used commands, this is actually quite easy to do: simply make |
800 | +the change to the required files as you normally would! For example:: |
801 | + |
802 | + edit src/lib/sax/parser.py |
803 | + bzr commit -m "fix bug #42 in sax parser" |
804 | + |
805 | +Note that Bazaar is smart enough to recurse by default into nested |
806 | +branches, commit changes there, and commit the new nested branch tips |
807 | +in the current branch. Both commits get the same commit message. |
808 | + |
809 | +If you want to only commit the change to a nested branch for now, you |
810 | +can change into the nested branch before running commit like this:: |
811 | + |
812 | + cd src/lib/sax |
813 | + bzr commit -m "fix bug #42 in sax parser" |
814 | + |
815 | +Alternatively, you can use a selective commit like this:: |
816 | + |
817 | + bzr commit -m "fix bug #42 in sax parser" src/lib/sax |
818 | + |
819 | + |
820 | +Reviewing nested tree changes |
821 | +----------------------------- |
822 | + |
823 | +Just like ``commit``, the ``status`` and ``diff`` commands implicitly |
824 | +recurse into nested trees. In the case of ``status``, it shows both the |
825 | +nested tree as having a pending change as well as the items within it that have |
826 | +changed. For example:: |
827 | + |
828 | + M src/lib/sax |
829 | + M src/lib/sax/parser.py |
830 | + |
831 | +Once again, if you change into a nested tree though, ``status`` and |
832 | +``diff`` will operate just on that tree and not recurse upwards by |
833 | +default. |
834 | + |
835 | + |
836 | +Browsing nested tree history |
837 | +---------------------------- |
838 | + |
839 | +As the branches of nested trees have their own history, the ``log`` command |
840 | +shows just the history of the containing branch. To see the history for |
841 | +a nested branch, nominate the branch explicitly like this:: |
842 | + |
843 | + bzr log src/lib/sax |
844 | + |
845 | +Note however that ``log -v`` and ``log -p`` on the containing branch |
846 | +will show what files in nested branches were changed in each revision. |
847 | + |
848 | + |
849 | +Splitting out a project |
850 | +----------------------- |
851 | + |
852 | +If you already have a large project and wish to partition it into |
853 | +reusable subprojects, use the ``split`` command. This takes an existing |
854 | +directory and makes it a separate branch. For example, imagine you have |
855 | +a directory holding UI widgets that another project would like to |
856 | +leverage. You can make it a separate branch like this:: |
857 | + |
858 | + bzr split src/uiwidgets |
859 | + |
860 | +To make the new project available to others, push it to a shared location |
861 | +like this:: |
862 | + |
863 | + cd src/uiwidgets |
864 | + bzr push bzr://example.com/uiwidgets |
865 | + |
866 | +You also need to link it back into the original project as a nested branch |
867 | +using the ``join`` command like this (assuming the current directory is |
868 | +``src/uiwidgets``):: |
869 | + |
870 | + bzr join --nested . |
871 | + bzr commit -m "uiwidgets is now a nested project" |
872 | + |
873 | +Similar to ``branch --nested``, ``join --nested`` joins the nominated directory |
874 | +(which must hold a branch) into the containing tree. In order to make sure |
875 | +that all versions of a tree can be reproduced, the branches of nested trees |
876 | +share a repository with their containing tree. |
877 | + |
878 | + |
879 | +Virtual projects |
880 | +---------------- |
881 | + |
882 | +By design, Bazaar is strict about tracking the actual revisions used of |
883 | +nested branches over time. Without this, projects cannot accurately |
884 | +reproduce exactly what was used to make a given build. There are |
885 | +isolated use cases though where is advantageous to say "give me the |
886 | +latest tip of these loosely coupled branches". To do this, create a |
887 | +small 'virtual project' which is just a bunch of *unpegged* nested |
888 | +branches. To mark nested branches as unpegged, use the ``--no-pegged`` |
889 | +option of the ``join`` command like this:: |
890 | + |
891 | + bzr join --nested --no-pegged [DIR] |
892 | + |
893 | +To stop the nested branch tips from floating and to begin recording |
894 | +the tip revisions again, use the ``pegged`` option:: |
895 | + |
896 | + bzr join --nested --pegged [DIR] |
897 | + |
898 | +After changing whether one or more nested branches are pegged or not, you |
899 | +need to ``commit`` the branch to record that metadata. (The pegged state |
900 | +is recorded over time.) |
901 | + |
902 | +For example, you may be managing a company intranet site as a project |
903 | +which is nothing more than a list of unrelated departmental websites |
904 | +bundled together. You can set this up like this:: |
905 | + |
906 | + bzr init intranet-site |
907 | + cd intranet-site |
908 | + bzr branch bzr://ourserver/websites/research |
909 | + bzr branch bzr://ourserver/websites/development |
910 | + bzr branch bzr://ourserver/websites/support |
911 | + bzr branch bzr://ourserver/websites/hr |
912 | + bzr join --nested --no-pegged research |
913 | + bzr join --nested --no-pegged development |
914 | + bzr join --nested --no-pegged support |
915 | + bzr join --nested --no-pegged hr |
916 | + bzr commit -m "initial configuration of intranet-site" |
917 | + |
918 | +Publishing the overall site is then as easy as going to the server |
919 | +hosting your intranet and running something like:: |
920 | + |
921 | + bzr branch http://mymachine//projects/intranet-site |
922 | + |
923 | +Refreshing the overall site is as easy as:: |
924 | + |
925 | + bzr pull |
926 | + |
927 | +Virtual projects are also useful for providing a partial 'view' over |
928 | +a large project containing a large number of subprojects. For example, |
929 | +you may be working on an office suite and have a bunch of developers |
930 | +that only care about the word processor. You can create a virtual |
931 | +project for them like this:: |
932 | + |
933 | + bzr init wp-modules |
934 | + cd wp-modules |
935 | + bzr branch ../common |
936 | + bzr branch ../printing |
937 | + bzr branch ../spellchecker |
938 | + bzr branch ../wordprocessor |
939 | + bzr join --nested --no-pegged common |
940 | + bzr join --nested --no-pegged printing |
941 | + bzr join --nested --no-pegged spellchecker |
942 | + bzr join --nested --no-pegged wordprocessor |
943 | + bzr commit -m "initial configuration of wp-modules" |
944 | + |
945 | +Those developers can then get bootstrapped faster and have *just* the |
946 | +subprojects they care about by branching from ``wp-modules``. |
947 | + |
948 | + |
949 | +Nested branch tips & tricks |
950 | +--------------------------- |
951 | + |
952 | +As explained above, most of Bazaar's commonly used commands recurse |
953 | +downwards into nested branches by default. To prevent this recursion, |
954 | +use the ``--no-recurse-nested`` option on various commands (including |
955 | +``commit``, ``status`` and ``diff``) that support it. |
956 | + |
957 | +Thanks to plugins like bzr-svn and bzr-git, Bazaar has strong support |
958 | +for transparently accessing branches managed by foreign VCS tools. This |
959 | +means that Bazaar can support projects where nested branches are hosted |
960 | +in supported foreign systems. For example, to nest a library maintained |
961 | +in Subversion:: |
962 | + |
963 | + bzr branch --nested svn://example.com/xmlhelpers src/lib/xmlhelpers |
964 | + |
965 | +If you want revisions to be committed both to a remote location and a |
966 | +local location, make the top-level branch a bound branch. (Nested branches |
967 | +have no configuration of their own.) |
968 | + |
969 | +Most likely, you will have some branches that are identical to their upstream |
970 | +version and can be pulled, and some that have local changes and must be merged. |
971 | +You can update all of them at once using ``merge --pull``. This will pull |
972 | +into the trees with no local changes, and merge into the ones with local |
973 | +changes. Afterward, you should commit, which will commit only into the |
974 | +trees that were merged into. |
975 | + |
976 | +As you'd expect, a nested branch can be moved or deleted using the |
977 | +normal commands. For example, after splitting out a subproject, you |
978 | +may want to change its location like this:: |
979 | + |
980 | + bzr mv src/uiwidgets src/lib/uiwidgets |
981 | + bzr commit -m "move uiwidgets into src/lib" |
982 | + |
983 | +Things to be aware of |
984 | +--------------------- |
985 | + |
986 | +Commands like ``commit`` and ``push`` need online access to the locations |
987 | +for nested branches which have updated their tip. In particular, ``commit`` |
988 | +will update any changed nested branches first and only commit to the |
989 | +containing branch if all nested branch commits succeed. If you are working |
990 | +offline, you may want to ensure you have a local mirror location defined |
991 | +for nested branches you are likely to tweak. Alternatively, the |
992 | +``no-recurse-nested`` option to the ``commit`` command might to useful to |
993 | +commit some changes, leaving the nested branch commits until you are back |
994 | +online. |
995 | + |
996 | +A given top level tree cannot contain multiple copies of a nested tree. |
997 | +As a consequence, you cannot nest two projects if they both nest |
998 | +the same project somewhere within them. This limitation may be removed |
999 | +in the future. In the meantime, consider restructuring things so that each |
1000 | +project is only nested once (and leverage symbolic links as appropriate). |
1001 | +In most programming environments, having different parts of the project |
1002 | +using different versions of a library is an integration no-no anyhow, |
1003 | +so enforcing *one* common revision is the right way to prevent this from |
1004 | +happening. |
1005 | + |
1006 | +At the moment, nested trees need to be incorporated as a whole. |
1007 | +Filtered views can to used to restrict the set of files and directories |
1008 | +logically seen. Currently though, filtered views are a lens onto a tree: |
1009 | +they do not delete other files and the exposed files/directories must |
1010 | +have the same paths as they do in the original branch. In the future, |
1011 | +we may add support for nesting and moving selected files from a |
1012 | +(read-only) nested branch something like this:: |
1013 | + |
1014 | + bzr nested DIR --file LICENSE --file doc/README::README |
1015 | + bzr commit -m "change which files are nested from project DIR" |
1016 | + |
1017 | +If you require this feature, please contact us with your needs. |
1018 | + |
1019 | +Design decisions |
1020 | +**************** |
1021 | + |
1022 | +The branches of subtrees shall share a repository with the containing tree. |
1023 | + |
1024 | +The branches of subtrees shall be in a special format that shares a single |
1025 | +last_revision file that is stored in the containing branch. |
1026 | + |
1027 | +The subtree branches shall be referenced in the last_revision file by file-id. |
1028 | + |
1029 | +Subtree branches shall not support individual configuration. |
1030 | + |
1031 | +Fetch shall automatically fetch the revisions mentioned by tree-references, |
1032 | +recursively. |
1033 | + |
1034 | +The reserved revision-id "head:" shall be used in tree-references to refer to |
1035 | +the tip revision of a branch. |
1036 | + |
1037 | +bzr-svn repositories with externals shall behave as though the multiple |
1038 | +repositories were a single Bazaar repository with multiple branches. |
1039 | |
1040 | Shall commands recurse downwards by default? |
1041 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1042 | @@ -76,10 +1000,10 @@ |
1043 | - It is hard to accidentally produce inconsistent trees |
1044 | - Inconsistent trees are hard for remote users to handle |
1045 | - Accidentally committing too many things at once is easy to resolve |
1046 | + - It is hard to accidentally commit too many things at once |
1047 | |
1048 | Cons: |
1049 | |
1050 | - - It is hard to accidentally commit too many things at once |
1051 | - Accidentally committing nuclear launch codes is easier to do |
1052 | - More risk of exposing users to bugs |
1053 | - Makes incompleteness more glaring |
1054 | @@ -98,8 +1022,8 @@ |
1055 | |
1056 | - the "name" of subbranches can change from revision to revision. In fact, |
1057 | subbranches may have no name in a given revision. |
1058 | - - a user may want to get revision X of a subbranch named "foo" in revision Y of |
1059 | - the top branch. |
1060 | + - a user may want to get revision X of a subbranch named "foo" in revision Y |
1061 | + of the top branch. |
1062 | |
1063 | The syntax will be ``BRANCH#SUBBRANCH``, e.g. ``lp:bigproject#subproject``. |
1064 | ``BRANCH`` is a regular URL and ``SUBBRANCH`` is a path within BRANCH's tree |
1065 | @@ -114,8 +1038,9 @@ |
1066 | cross subtree boundaries, e.g. a merge in the top tree can move a file between |
1067 | subtrees. |
1068 | |
1069 | -The downside is that we can't have cheap support for subtrees that are copies of |
1070 | -one another, because we wouldn't know which copy to apply sets of changes to. |
1071 | +The downside is that we can't have cheap support for subtrees that are copies |
1072 | +of one another, because we wouldn't know which copy to apply sets of changes |
1073 | +to. |
1074 | |
1075 | |
1076 | Shall we use root-ids for tree references? |
1077 | @@ -136,8 +1061,8 @@ |
1078 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1079 | |
1080 | Yes. It matches existing behaviour by failing earlier, and the extra cost does |
1081 | -not seem onerous. (To be fully efficient this requires an index of the subtrees, |
1082 | -otherwise we need to scan the fully inventory/dirstate.) |
1083 | +not seem onerous. (To be fully efficient this requires an index of the |
1084 | +subtrees, otherwise we need to scan the fully inventory/dirstate.) |
1085 | |
1086 | (Also, this decision can be changed later with no compatibility concerns.) |
1087 | |
1088 | @@ -149,17 +1074,19 @@ |
1089 | local last revision's revno would change (i.e. is a non-lhs parent in the merge |
1090 | source). This is expected to be the most common way to update nested trees. |
1091 | |
1092 | -The existing "bzr merge --pull" behaviour will be renamed to "bzr merge --pull-renumber". |
1093 | +The existing "bzr merge --pull" behaviour will be renamed to "bzr merge |
1094 | +--pull-renumber". |
1095 | |
1096 | -"bzr merge" (with no "--pull") will do a merge in all trees. "bzr pull" will do |
1097 | -a pull in all trees. |
1098 | +"bzr merge" (with no "--pull") will do a merge in all trees. "bzr pull" will |
1099 | +do a pull in all trees. |
1100 | |
1101 | The rationale is that a very common use-case is that the top tree is a project |
1102 | the user is actively committing to, and the subtrees are mainly libraries that |
1103 | -are being mirrored. So a behaviour that forced every update to be a merge would |
1104 | -be undesirable for the mirrored subtrees, but an update that is a pull wouldn't |
1105 | -suit the changing top tree. And the existing "merge --pull" (that can renumber |
1106 | -revisions) isn't desireable for either the top tree or subtrees in this case. |
1107 | +are being mirrored. So a behaviour that forced every update to be a merge |
1108 | +would be undesirable for the mirrored subtrees, but an update that is a pull |
1109 | +wouldn't suit the changing top tree. And the existing "merge --pull" (that can |
1110 | +renumber revisions) isn't desireable for either the top tree or subtrees in |
1111 | +this case. |
1112 | |
1113 | |
1114 | What should uncommit do? |
1115 | @@ -175,7 +1102,14 @@ |
1116 | $ bzr uncommit |
1117 | |
1118 | will not cause a change in subtrees, since the top-level commit did not affect |
1119 | -them. |
1120 | +them. But on the other hand: |
1121 | + |
1122 | + $ echo foo > subtree/versioned-file-in-subtree.txt |
1123 | + $ bzr ci -m "Change file" |
1124 | + $ bzr uncommit |
1125 | + |
1126 | +will first commit to the subtree, then to the top tree. The uncommit will |
1127 | +restore both trees to their previous state. |
1128 | |
1129 | |
1130 | Shall we use a CompositeTree object as a shim to make existing commands work? |
1131 | @@ -189,13 +1123,10 @@ |
1132 | Some subtrees should have commits and some should not. How? |
1133 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1134 | |
1135 | -We won't do this initially. Flagging some sub-trees as mirror-only or similar |
1136 | -sounds like a nice feature, but we can add this later (and it may only require a |
1137 | -working tree format bump to add). |
1138 | - |
1139 | -It would be nice to have more infrastructure in general to handle mirrors, and |
1140 | -this is not specific to nested trees. |
1141 | - |
1142 | +We will not provide special support for this initially. We might later support |
1143 | +flagging some sub-trees as mirror-only something similar, but this seems like |
1144 | +it could be a general feture not specific to nesting. (and it may only require |
1145 | +a working tree format bump to add). |
1146 | |
1147 | How do we handle files that are moved into subtrees (from another tree in the same top tree)? |
1148 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1149 | @@ -203,128 +1134,97 @@ |
1150 | Add a revision property: |
1151 | "Files-from-other-trees: (rev-id: [f-id, ...]), ..." |
1152 | |
1153 | -(Once we can do cherry-pick merges, we might use those instead?) |
1154 | - |
1155 | - |
1156 | - |
1157 | -Handling svn:externals |
1158 | -~~~~~~~~~~~~~~~~~~~~~~ |
1159 | - |
1160 | -svn externals commonly have references to the tip of some other branch. |
1161 | -Because we want a deterministic representation of the inventory when |
1162 | -pulling from svn, we can't put the specific revision-id into the inventory |
1163 | -at that time. However, we do want to bring down all the relevant data at |
1164 | -the time of fetching, so that we can later branch locally. This seems to |
1165 | - |
1166 | -Decided questions |
1167 | -***************** |
1168 | - |
1169 | -The branches of subtrees shall share a repository with the containing tree. |
1170 | - |
1171 | -The branches of subtrees shall be in a special format that shares a single |
1172 | -last_revision file that is stored in the containing branch. |
1173 | - |
1174 | -The subtree branches shall be referenced in the last_revision file by file-id. |
1175 | - |
1176 | -Subtree branches shall not support individual configuration. |
1177 | - |
1178 | -Fetch shall automatically fetch the revisions mentioned by tree-references, |
1179 | -recursively. |
1180 | - |
1181 | -The reserved revision-id "head:" shall be used in tree-references to refer to |
1182 | -the tip revision of a branch. |
1183 | - |
1184 | -bzr-svn repositories with externals shall behave as though the multiple |
1185 | -repositories were a single Bazaar repository with multiple branches. |
1186 | - |
1187 | - |
1188 | -Use Cases |
1189 | -********* |
1190 | - |
1191 | -Case 1 |
1192 | -~~~~~~ |
1193 | -Barry works on a project with three libraries. He wants to keep up to date |
1194 | -with the tip of those libraries, but he doesn't want them to be part of his |
1195 | -source tree. |
1196 | - |
1197 | -Case 2 |
1198 | -~~~~~~ |
1199 | -Now, Barry wants to add a fourth library. |
1200 | - |
1201 | -Case 3 |
1202 | -~~~~~~ |
1203 | -Barry wants to publish his project. |
1204 | - |
1205 | -Case 4 |
1206 | -~~~~~~ |
1207 | -Barry decides to make part of his project into another library |
1208 | - |
1209 | -Case 5 |
1210 | -~~~~~~ |
1211 | -Curtis wants to hack on Barry's project |
1212 | - |
1213 | -Case 6 |
1214 | -~~~~~~ |
1215 | -Barry wants to drop one of the libraries he was using |
1216 | - |
1217 | -Case 7 |
1218 | -~~~~~~ |
1219 | -Curtis has made changes to one of the libraries. Barry wants to merge Curtis' |
1220 | -changes into his copy. |
1221 | - |
1222 | -Case 8 |
1223 | -~~~~~~ |
1224 | -Curtis has made changes to Barry's main project. Barry wants to merge Curtis' |
1225 | -changes into his copy. |
1226 | - |
1227 | -Case 9 |
1228 | -~~~~~~ |
1229 | -Barry makes changes in his project and in a library, and he runs status |
1230 | - |
1231 | -Case 10 |
1232 | -~~~~~~~ |
1233 | -Barry wants to upgrade the bazaar format of his project |
1234 | - |
1235 | -Case 11 |
1236 | -~~~~~~~ |
1237 | -Curtis wants to apply Barry's latest changes. |
1238 | - |
1239 | -Case 12 |
1240 | -~~~~~~~ |
1241 | -Danilo wants to start a project with two libraries using nested trees from |
1242 | -scratch. |
1243 | - |
1244 | -Case 13 |
1245 | -~~~~~~~ |
1246 | -Edwin has a project that doesn't use nested trees and he wants to start using |
1247 | -nested trees. |
1248 | - |
1249 | -Case 14 |
1250 | -~~~~~~~ |
1251 | -Françis has a project with nested trees where the containing tree uses one |
1252 | -Bazaar format and the subtree uses a different Bazaar format. |
1253 | - |
1254 | -Case 15 |
1255 | -~~~~~~~ |
1256 | -Barry commits some changes to a library and to the main project, and then |
1257 | -discovers the changes are not appropriate. |
1258 | - |
1259 | -Case 16 |
1260 | -~~~~~~~ |
1261 | -Gary is writing a project. Henninge wants to split a library out of it. |
1262 | - |
1263 | -Case 17 |
1264 | -~~~~~~~ |
1265 | -Henning wants to update to receive Gary's latest changes. |
1266 | - |
1267 | -Case 18 |
1268 | -~~~~~~~ |
1269 | -Gary wants to update to receive Henninge's changes, including splitting a |
1270 | -library out. |
1271 | - |
1272 | -Case 19 |
1273 | -~~~~~~~ |
1274 | -Gary wants to update to receive Henninge's changes, without splitting a library |
1275 | -out. |
1276 | +(Once we can record cherry-pick merges, we might use those instead, but it |
1277 | +depends on their history-fetching requirements.) |
1278 | + |
1279 | + |
1280 | + |
1281 | + |
1282 | +Comparison with other systems |
1283 | +***************************** |
1284 | + |
1285 | +Git submodules |
1286 | +~~~~~~~~~~~~~~ |
1287 | + |
1288 | +This allows separate repositories to be used for submodules. At the UI layer, |
1289 | +they are quite different, because submodules does not attempt to integrate |
1290 | +subtree support into the core commands. |
1291 | + |
1292 | +Mercurial Forests |
1293 | +~~~~~~~~~~~~~~~~~ |
1294 | + |
1295 | +The wiki page does not give confidence that this is a well-maintained project. |
1296 | +It seems similar to config-manager-- its 'snapshot' files are like |
1297 | +config-manager's config files, describing what branches to get and where to put |
1298 | +them, optionally specifying a revision. No metadata about nesting is stored in |
1299 | +the tree. Optionally, a 'snapshot.txt' file may be stored in the containing |
1300 | +tree, but it can also be stored somewhere else. |
1301 | + |
1302 | +There is no attempt to integrate subtree support into the core commands. |
1303 | + |
1304 | +Mercurial Nested Repositories |
1305 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1306 | +This design was for an integrated feature, but there are apparently 4 |
1307 | +implementations as extensions. While it does integrate subtree support into |
1308 | +core commands, this may be off by default: "The alternative that I lean towards |
1309 | +is to not recurse unless explicitly instructed to. Most probably, only a few |
1310 | +commands should arguably even be aware of modules." |
1311 | + |
1312 | +Command comparison: |
1313 | + |
1314 | +- hg module add ~= bzr join --nested |
1315 | +- hg module remove ~= bzr remove --keep |
1316 | +- hg module record's functionality is part of nested commits in nested trees. |
1317 | + |
1318 | +Like submodules, this stores location information in versioned data: a |
1319 | +.hgmodules directory. |
1320 | +Like submodules and nested trees, particular revisions are recorded. |
1321 | + |
1322 | +Subversion "svn:externals" |
1323 | +~~~~~~~~~~~~~~~~~~~~~~~~~~ |
1324 | +Like bzr, uses per-file metadata. Like submodules and nested repositories, |
1325 | +locations are versioned data. Like Forests, revisions are optional. Like |
1326 | +nested repositories, there is limited integration into core commands; checkout |
1327 | +and update support externals, and commit may support them in the future. |
1328 | +However, there is no UI specific to creating and updating svn:externals |
1329 | +references. |
1330 | + |
1331 | +Unlike all other alternatives, supports partial checkouts. This is because svn |
1332 | +natively supports partial checkouts. Also, supports checkouts of tags, because |
1333 | +tags are merely a convention in svn. |
1334 | + |
1335 | +Supports pulling in "head" subtrees too, not just specific ("known-good") |
1336 | +revisions. Nested trees supports this in order to provide high-fidelity |
1337 | +imports. |
1338 | + |
1339 | +Some support for single-file svn:externals (see |
1340 | +http://subversion.tigris.org/svn_1.6_releasenotes.html#externals), whereas bzr |
1341 | +subtrees must be directories. |
1342 | + |
1343 | +Has a --ignore-externals option for checking out without pulling in the |
1344 | +svn:externals items (svn checkout is more or less equivalent to bzr branch). |
1345 | +You can also use that option on update (more or less like bzr merge). |
1346 | + |
1347 | + |
1348 | +Comments on differences |
1349 | +~~~~~~~~~~~~~~~~~~~~~~~ |
1350 | +externals support partial checkouts. Nested trees could gain support for this |
1351 | +once Bazaar itself supports partial checkouts. Supporting a single file as a |
1352 | +"subtree" would also depend on native bzr support. On platforms that support |
1353 | +symlinks, using symlinks to portions of a subtree can be an effective |
1354 | +substitute. |
1355 | + |
1356 | + |
1357 | +Future work |
1358 | +*********** |
1359 | +It would be nice to support multiple copies of subtree in a master tree. |
1360 | +Currently, this would lead to having multiple copies of a given file-id in the |
1361 | +(composite) tree, which is forbidden. Allowing this would involve one of: |
1362 | + |
1363 | +- permitting multiple copies of a file-id within a tree |
1364 | +- not treating nested trees as composite trees |
1365 | +- using fake file-ids within the composite tree |
1366 | +- replacing the file-id concept with something else (e.g. path tokens) |
1367 | + |
1368 | |
1369 | .. vim: ft=rst |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi all,
Here's my revised documentation for nested trees. In includes all three nested- trees.txt from the most recent sprint.
documents: NestedTreesDesign from the wiki, Ian's proposed userdoc, and
the devnotes/
I have updated them to provide a coherent view of nested trees,
harmonized with the design decisions made by Andrew Bennetts and me at
the sprint.
There's quite a lot of documentation to go over, so I may have missed
some inconsistencies. Please let me know if so.
Aaron enigmail. mozdev. org
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://
iEYEARECAAYFAkp ctAMACgkQ0F+ nu1YWqI2HMwCeMO EG/7vmjBkUfkgRK yRsXS78 4mSFFsCMc30cA+ ueD
nY4An3c4AprS3bb
=uzRm
-----END PGP SIGNATURE-----