~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to doc/developers/commit.txt

  • Committer: Martin Pool
  • Date: 2007-06-21 04:27:47 UTC
  • mto: This revision was merged to the branch mainline in revision 2551.
  • Revision ID: mbp@sourcefrog.net-20070621042747-e3g0tdn8if750mv5
More commit specs

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
Commit Performance Notes
2
2
========================
3
3
 
4
 
.. contents:: :local:
5
 
 
6
 
Changes to commit
7
 
-----------------
8
 
 
9
 
We want to improve the commit code in two phases.
10
 
 
11
 
Phase one is to have a better separation from the format-specific logic,
12
 
the user interface, and the general process of committing.
13
 
 
14
 
Phase two is to have better interfaces by which a good workingtree format
15
 
can efficiently pass data to a good storage format.  If we get phase one
16
 
right, it will be relatively easy and non-disruptive to bring this in.
17
 
 
18
 
 
19
4
Commit: The Minimum Work Required
20
5
---------------------------------
21
6
 
174
159
     happened several commits back. There are several edge cases to be
175
160
     handled here, like if both branches modified the same file, or if
176
161
     just one branch modified it.
177
 
 
 
162
     
178
163
  b) The trickier case is when a file appears unmodified since last
179
164
     commit, but it was modified versus one of the merged branches. I
180
165
     believe there are a few ways this can happen, like if a merged
291
276
It is desirable to avoid roundtrips to the Repository during commit,
292
277
particularly because it may be remote.  If the WorkingTree can determine
293
278
by itself that a text was in the parent and therefore should be in the
294
 
Repository that avoids one roundtrip per file.
 
279
Repository that avoids one roundtrip per file.  
295
280
 
296
281
There is a possibility here that the parent revision is not stored, or not
297
282
correctly stored, in the repository the tree is being committed into, and
300
285
that if a revision is present, everything to reconstruct it will be
301
286
present too.
302
287
 
303
 
 
304
 
Code structure
305
 
--------------
306
 
 
307
 
Caller starts a commit
308
 
 
309
 
>>> Branch.commit(from_tree, options)
310
 
 
311
 
This creates a CommitBuilder object matched to the Branch, Repository and
312
 
Tree.  It can vary depending on model differences or by knowledge of what
313
 
is efficient with the Repository and Tree.  Model differences might
314
 
include whether no-text-change merges need to be reported, and whether the
315
 
 
316
 
The basic CommitBuilder.commit structure can be
317
 
 
318
 
1. Ask the branch if it is ready to commit (up to date with master if
319
 
   any.)
320
 
 
321
 
2. Ask the tree if it is ready to commit to the branch (up to date with
322
 
   branch?), no conflicts, etc
323
 
 
324
 
3. Commit changed files; prototype implementation:
325
 
 
326
 
   a. Ask the working tree for all committable files; for each it should
327
 
      return the per-file parents, stat information, kind, etc.
328
 
 
329
 
   b. Ask the repository to store the new file text; the repository should
330
 
      return the stored sha1 and new revision id.
331
 
 
332
 
4. Commit changed inventory
333
 
 
334
 
5. Commit revision object
335
 
 
336
 
 
337
 
 
338
 
 
339
 
 
340
 
 
341
 
 
342
 
 
343
 
 
344
288
Complications of commit
345
289
-----------------------
346
290
 
352
296
There are several checks that may cause the commit to be refused, which
353
297
may be activated or deactivated by options.
354
298
 
355
 
* presence of conflicts in the tree
356
 
 
357
 
* presence of unknown files
358
 
 
359
 
* the working tree basis is up to date with the branch tip
360
 
 
361
 
* the local branch is up to date with the master branch, if there
362
 
  is one and --local is not specified
363
 
 
364
 
* an empty commit message is given,
365
 
 
366
 
* a hook flags an error
367
 
 
368
 
* a "pointless" commit, with no inventory changes
 
299
 * presence of conflicts in the tree
 
300
 
 
301
 * presence of unknown files
 
302
 
 
303
 * the working tree basis is up to date with the branch tip
 
304
 
 
305
 * the local branch is up to date with the master branch, if there 
 
306
   is one and --local is not specified
 
307
 
 
308
 * an empty commit message is given, 
 
309
 
 
310
 * a hook flags an error
 
311
 
 
312
 * a "pointless" commit, with no inventory changes
369
313
 
370
314
Most of these require walking the tree and can be easily done while
371
315
recording the tree shape.  This does require that it be possible to abort
375
319
 
376
320
Other complications:
377
321
 
378
 
* when automatically adding new files or deleting missing files during
379
 
  commit, they must be noted during commit and written into the working
380
 
  tree at some point
381
 
 
382
 
* refuse "pointless" commits with no file changes - should be easy by
383
 
  just refusing to do the final step of storing a new overall inventory
384
 
  and revision object
385
 
 
386
 
* heuristic detection of renames between add and delete (out of scope for
387
 
  this change)
388
 
 
389
 
* pushing changes to a master branch if any
390
 
 
391
 
* running hooks, pre and post commit
392
 
 
393
 
* prompting for a commit message if necessary, including a list of the
394
 
  changes that have already been observed
395
 
 
396
 
* if there are tree references and recursing into them is enabled, then
397
 
  do so
398
 
 
399
 
Commit needs to protect against duplicated file ids
400
 
 
 
322
 * when automatically adding new files or deleting missing files during
 
323
   commit, they must be noted during commit and written into the working
 
324
   tree at some point
 
325
 
 
326
 * refuse "pointless" commits with no file changes - should be easy by
 
327
   just refusing to do the final step of storing a new overall inventory
 
328
   and revision object
 
329
 
 
330
 * heuristic detection of renames between add and delete (out of scope for
 
331
   this change)
 
332
 
 
333
 * pushing changes to a master branch if any
 
334
 
 
335
 * running hooks, pre and post commit
 
336
 
 
337
 * prompting for a commit message if necessary, including a list of the
 
338
   changes that have already been observed
 
339
 
 
340
 * if there are tree references and recursing into them is enabled, then
 
341
   do so
401
342
 
402
343
Updates that need to be made in the working tree, either on conclusion
403
344
of commit or during the scan, include
404
345
 
405
 
* Changes made to the tree shape, including automatic adds, renames or
406
 
  deletes
407
 
 
408
 
* For trees (eg dirstate) that cache parent inventories, the old parent
409
 
  information must be removed and the new one inserted
410
 
 
411
 
* The tree hashcache information should be updated to reflect the stat
412
 
  value at which the file was the same as the committed version, and the
413
 
  content hash it was observed to have.  This needs to be done carefully to
414
 
  prevent inconsistencies if the file is modified during or shortly after
415
 
  the commit.  Perhaps it would work to read the mtime of the file before we
416
 
  read its text to commit.
 
346
 * Changes made to the tree shape, including automatic adds, renames or
 
347
   deletes
 
348
 
 
349
 * For trees (eg dirstate) that cache parent inventories, the old parent
 
350
   information must be removed and the new one inserted
 
351
 
 
352
 * The tree hashcache information should be updated to reflect the stat
 
353
   value at which the file was the same as the committed version, and the
 
354
   content hash it was observed to have.  This needs to be done carefully to
 
355
   prevent inconsistencies if the file is modified during or shortly after
 
356
   the commit.  Perhaps it would work to read the mtime of the file before we
 
357
   read its text to commit.
417
358
 
418
359
 
419
360
Interface stack
424
365
WorkingTree afterwards.
425
366
 
426
367
The command interface passes:
427
 
 
428
 
* a commit message (from an option, if any),
429
 
* or an indication that it should be read interactively from the ui object;
430
 
* a list of files to commit
431
 
* an option for a dry-run commit
432
 
* verbose option, or callback to indicate
433
 
* timestamp, timezone, committer, chosen revision id
434
 
* config (for what?)
435
 
* option for local-only commit on a bound branch
436
 
* option for strict commits (fail if there are unknown or missing files)
437
 
* option to allow "pointless" commits (with no tree changes)
438
 
 
 
368
 
 
369
 * a commit message (from an option, if any),
 
370
 * or an indication that it should be read interactively from the ui object;
 
371
 * a list of files to commit
 
372
 * an option for a dry-run commit
 
373
 * verbose option, or callback to indicate 
 
374
 * timestamp, timezone, committer, chosen revision id
 
375
 * config (for what?)
 
376
 * option for local-only commit on a bound branch
 
377
 * option for strict commits (fail if there are unknown or missing files)
 
378
 * option to allow "pointless" commits (with no tree changes)
 
379
 
439
380
(This is rather a lot of options to pass individually and just for code tidyness maybe some of them should be combine into objects.)
440
381
 
441
382
>>> Branch.commit(from_tree, message, files_to_commit, ...)
466
407
This needs to collect a list of added/changed/removed files, each of which
467
408
must have its text stored (if any) and containing directory updated.  This
468
409
can be done by calling Tree._iter_changes on the source tree, asking for
469
 
changes
 
410
changes 
470
411
 
471
412
In the 0.17 model the commit operation needs to know the per-file parents
472
 
and per-file last-changed revision.
 
413
and per-file last-changed revision.  
473
414
 
474
415
(In this and other operations we must avoid having multiple layers walk
475
416
over the tree separately.  For example, it is no good to have the Command
492
433
The interface should not return a block for directories that are
493
434
recursively unchanged.
494
435
 
495
 
The tree's idea of what is possibly changed may be more conservative than
496
 
that of the branch.  For example the tree may report on merges of files
497
 
where the text is identical to the parents: this must be recorded for
498
 
Bazaar branches that record per-file ancestry but is not necessary for all
499
 
branches.  If the tree is responsible for determining when directories
500
 
have been recursively modified then it will report on all the parents of
501
 
such files.  There are several implementation options:
502
 
 
503
 
1. Return all files and directories the branch might want to commit, even
504
 
if the branch ends up taking no action on them.
505
 
 
506
 
2. When starting the iteration, the branch can specify what type of change
507
 
is considered interesting.
508
 
 
509
 
Since these types of changes are probably (??) rare compared to files that
510
 
are either completely unmodified or substantially modified, the first may
511
 
be the best and simplest option.
512
 
 
513
 
The branch needs to build an inventory to commit, which must include
514
 
unchanged files within changed directories.  This should be returned from
515
 
the working tree too.  Repositories that store per-directory inventories
516
 
will want to build and store these from the lowest directories up.
517
 
For 0.17 format repositories with an all-in-one inventory it may be
518
 
easiest to accumulate inventory entries in arbitrary order into an
519
 
in-memory Inventory and then serialize it.
520
 
 
521
 
It ought to be possible to commit any Tree into a Branch, without
522
 
requiring a WorkingTree; the commit code should cope if the tree is not
523
 
interested in updating hashcache information or does not have a
524
 
``last_revision``.
525
 
 
526
 
 
527
 
Information from the tree to repository
528
 
---------------------------------------
529
 
 
530
 
The main things the tree needs to tell the Branch about are:
531
 
 
532
 
* A file is modified from its parent revision (in text, permissions,
533
 
  other), and so its text may need to be stored.
534
 
 
535
 
  Files should also be reported if they have more than one unique parent
536
 
  revision, for repositories that store per-file graphs or last-change
537
 
  revisions.  Perhaps this behaviour should be optional.
538
 
 
539
 
  **XXX:** are renames/deletions reported here too?
540
 
 
541
 
* The complete contents of a modified directory, so that its inventory
542
 
  text may be stored.  This should be done after all the contained files
543
 
  and directories have been reported.  If there are unmodified files,
544
 
  or unselected files carried through from
545
 
 
546
 
  XXX: Actually perhaps not grouped by directory, but rather grouped
547
 
  appropriately for the shape of inventory storage in the repository.
548
 
 
549
 
  In a zoomed-in checkout the workingtree may not have all the shape data
550
 
  for the entire tree.
551
 
 
552
 
* A file is missing -- could cause either automatic removal or an aborted
553
 
  commit.
554
 
 
555
 
* Any unknown files -- can cause automatic addition, abortion of a strict
556
 
  commit, or just reporting.
557
 
 
558
 
 
559
 
Information from the repository to the tree
560
 
-------------------------------------------
561
 
 
562
 
After the commit the tree needs to be updated to the new revision.  Some
563
 
information which was accumulated during the commit must be made available
564
 
to the workingtree.  It's probably reasonable to hold it all in memory and
565
 
allow the workingtree to get it in whatever order it wants.
566
 
 
567
 
* A list of modified entries, and for each one:
568
 
 
569
 
  * The stat values observed when the file was first read.
570
 
 
571
 
  * The hash of the committed file text.
572
 
 
573
 
  * The file's last-change revision, if appropriate.
574
 
 
575
 
  This should include any entries automatically added or removed.
576
 
 
577
 
This might be construed as an enhanced version of ``set_parent_trees``.
578
 
We can avoid a stat on each file by using the value that was observed when
579
 
it was first read.
580
 
 
581
 
 
582
 
 
583
 
Selective commit
584
 
----------------
585
 
 
586
 
For a partial commit the directory contents may need to contain a mix of
587
 
entries from the working tree and parent trees.  This code probably
588
 
shouldn't live in a specific tree implementation; maybe there should be a
589
 
general filter that selects paths from one tree into another?
590
 
 
591
 
However, the tree walking code does probably need to know about selected
592
 
paths to avoid examining unselected files or directories.
593
 
 
594
 
We never refuse selective file commits (except of merges).
595
 
 
596
 
 
597
 
 
598
 
Common commit code
599
 
------------------
600
 
 
601
 
What is common to all commit implementations, regardless of workingtree or
602
 
repository format?
603
 
 
604
 
* Prompting for a commit message?
605
 
* Strictness/conflict checks?
606
 
* Auto add/remove?
607
 
 
608
 
How should this be separated?
609
 
 
610
 
 
611
 
 
612
 
Order of traversal
613
 
------------------
614
 
 
615
 
For current and contemplated Bazaar storage formats, we can only finally
616
 
commit a directory after its contained files and directories have been
617
 
committed.
618
 
 
619
 
The dirstate workingtree format naturally iterates by directory in order
620
 
by path, yielding directories before their contents.  This may also be the
621
 
most efficient order in which to stat and read the files.
622
 
 
623
 
One option would be to construe the interface as a visitor which reports
624
 
when files are detected to be changed, and also when directories are
625
 
finished.
 
436
The tree's idea of what is possibly changed may be more conservative than that of the branch.  For example the tree may report on merges of files where the text is identical to the parents: this must be recorded for Bazaar branches that record per-file ancestry but is not necessary for all branches. 
 
437
If the tree is responsible for determining when directories have been recursively modified then it will report on all the parents of such files.
 
438
There are several implementation options:
 
439
 
 
440
1. Return all files and directories the branch might want to commit, even if the branch ends up taking no action on them.
 
441
2. When starting the iteration, the branch can specify what type of change is considered interesting.
 
442
 
 
443
Since these types of changes are probably (??) rare compared to files that are either completely unmodified or substantially modified, the first may be the best and simplest option.
626
444
 
627
445
 
628
446
Open question: per-file graphs