Merge lp:~jelmer/bzr/nested-trees-spec into lp:bzr

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Vincent Ladeuil
Approved revision: no longer in the source branch.
Merged at revision: 6518
Proposed branch: lp:~jelmer/bzr/nested-trees-spec
Merge into: lp:bzr
Diff against target: 1042 lines (+1024/-3)
2 files modified
doc/developers/nested-trees.txt (+1023/-0)
doc/developers/plans.txt (+1/-3)
To merge this branch: bzr merge lp:~jelmer/bzr/nested-trees-spec
Reviewer Review Type Date Requested Status
Marius Kruger Approve
Vincent Ladeuil Approve
Review via email: mp+98067@code.launchpad.net

Commit message

Add a specification for nested trees.

Description of the change

Add the nested tree specification to the tree.

This is the document that Aaron initially committed to lp:~bzr-core/bzr/devnotes. I've updated it to reflect the recent discussions.

To post a comment you must log in.
Revision history for this message
Vincent Ladeuil (vila) wrote :

On top of what we discuss on IRC, I now think we should land this and see it
as a work in progress.

Things I think we should do:

- turn the described scenarios into failing script tests (the syntax used
  should be almost copy'n'pastable) ,

- cleanup the document so that all references to stuff (subbranches format, composite tree) is not yet
  implemented is marked as such, better documented or removed if it's now
  obsolete

- keep working on the text itself to remove all advocacies by reaching a
  consensus for each point,

- better describe the data supporting the implementation (indexes,
  locations, revisions),

- better describe the known bugs/limitations,

- keep an eye on instrumenting *during* the implementation so we can better
  track the performance variations,

Instead of disussing further on this proposal, I'll try to address some of
the above (probably the tests and then some specific points as I run into
them) instead so we can the split the discussions.

review: Approve
Revision history for this message
Marius Kruger (amanica) wrote :

I also read this again now. I'm ecstatic to see any movement on this!

I saw some more trivial things which I proposed here:
https://code.launchpad.net/~amanica/bzr/nested-trees-typos/+merge/100066

2 questions below:

Case 7
+~~~~~~
+Curtis has made changes to one of the libraries. Barry wants to merge Curtis'
+changes into his copy.
+
+Example commands::
+
+ $ bzr merge -d project http://curtis.org/trunk#library2
+
+ Or alternatively:
+ $ bzr merge -d project/library2 http://curtis.org/trunk#library2

Should trunk#library2 not just be trunk/library2 ?
(just wondering, not sure what you guys decided)

+Case 15
+~~~~~~~
+Barry commits some changes to a library and to the main project, and then
+discovers the changes are not appropriate. He has not yet pushed his changes
+anywhere.
+
+Example commands::
+
+ $ bzr merge -d project http://library2

should this be the following?: $ bzr merge -d project/library2 http://library2

review: Approve
Revision history for this message
Jelmer Vernooij (jelmer) wrote :

sent to pqm by email

Preview Diff

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