~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to doc/developers/nested-trees.txt

  • Committer: Andrew Bennetts
  • Date: 2009-10-07 08:17:25 UTC
  • mto: This revision was merged to the branch mainline in revision 4734.
  • Revision ID: andrew.bennetts@canonical.com-20091007081725-4t3vkhher69a4k0j
Refactor to reduce duplication.

Show diffs side-by-side

added added

removed removed

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