313
236
self.strict = strict
314
237
self.verbose = verbose
239
if reporter is None and self.reporter is None:
240
self.reporter = NullCommitReporter()
241
elif reporter is not None:
242
self.reporter = reporter
316
244
self.work_tree.lock_write()
317
operation.add_cleanup(self.work_tree.unlock)
318
self.parents = self.work_tree.get_parent_ids()
319
# We can use record_iter_changes IFF iter_changes is compatible with
320
# the command line parameters, and the repository has fast delta
321
# generation. See bug 347649.
322
self.use_record_iter_changes = (
324
not self.branch.repository._format.supports_tree_reference and
325
(self.branch.repository._format.fast_deltas or
326
len(self.parents) < 2))
327
245
self.pb = bzrlib.ui.ui_factory.nested_progress_bar()
328
operation.add_cleanup(self.pb.finished)
329
self.basis_revid = self.work_tree.last_revision()
330
246
self.basis_tree = self.work_tree.basis_tree()
331
247
self.basis_tree.lock_read()
332
operation.add_cleanup(self.basis_tree.unlock)
333
# Cannot commit with conflicts present.
334
if len(self.work_tree.conflicts()) > 0:
335
raise ConflictsInTree
337
# Setup the bound branch variables as needed.
338
self._check_bound_branch(operation, possible_master_transports)
340
# Check that the working tree is up to date
341
old_revno, new_revno = self._check_out_of_date_tree()
343
# Complete configuration setup
344
if reporter is not None:
345
self.reporter = reporter
346
elif self.reporter is None:
347
self.reporter = self._select_reporter()
348
if self.config is None:
349
self.config = self.branch.get_config()
351
self._set_specific_file_ids()
353
# Setup the progress bar. As the number of files that need to be
354
# committed in unknown, progress is reported as stages.
355
# We keep track of entries separately though and include that
356
# information in the progress bar during the relevant stages.
357
self.pb_stage_name = ""
358
self.pb_stage_count = 0
359
self.pb_stage_total = 5
360
if self.bound_branch:
361
self.pb_stage_total += 1
362
self.pb.show_pct = False
363
self.pb.show_spinner = False
364
self.pb.show_eta = False
365
self.pb.show_count = True
366
self.pb.show_bar = True
368
self._gather_parents()
369
# After a merge, a selected file commit is not supported.
370
# See 'bzr help merge' for an explanation as to why.
371
if len(self.parents) > 1 and self.specific_files is not None:
372
raise errors.CannotCommitSelectedFileMerge(self.specific_files)
373
# Excludes are a form of selected file commit.
374
if len(self.parents) > 1 and self.exclude:
375
raise errors.CannotCommitSelectedFileMerge(self.exclude)
377
# Collect the changes
378
self._set_progress_stage("Collecting changes", counter=True)
379
self.builder = self.branch.get_commit_builder(self.parents,
380
self.config, timestamp, timezone, committer, self.revprops, rev_id)
383
self.builder.will_record_deletes()
384
# find the location being committed to
385
if self.bound_branch:
386
master_location = self.master_branch.base
388
master_location = self.branch.base
390
# report the start of the commit
391
self.reporter.started(new_revno, self.rev_id, master_location)
393
self._update_builder_with_changes()
394
self._check_pointless()
396
# TODO: Now the new inventory is known, check for conflicts.
397
# ADHB 2006-08-08: If this is done, populate_new_inv should not add
398
# weave lines, because nothing should be recorded until it is known
399
# that commit will succeed.
400
self._set_progress_stage("Saving data locally")
401
self.builder.finish_inventory()
403
# Prompt the user for a commit message if none provided
404
message = message_callback(self)
405
self.message = message
407
# Add revision data to the local branch
408
self.rev_id = self.builder.commit(self.message)
411
mutter("aborting commit write group because of exception:")
412
trace.log_exception_quietly()
413
note("aborting commit write group: %r" % (e,))
417
self._process_pre_hooks(old_revno, new_revno)
419
# Upload revision data to the master.
420
# this will propagate merged revisions too if needed.
421
if self.bound_branch:
422
self._set_progress_stage("Uploading data to master branch")
423
# 'commit' to the master first so a timeout here causes the
424
# local branch to be out of date
425
self.master_branch.import_last_revision_info(
426
self.branch.repository, new_revno, self.rev_id)
428
# and now do the commit locally.
429
self.branch.set_last_revision_info(new_revno, self.rev_id)
431
# Make the working tree be up to date with the branch. This
432
# includes automatic changes scheduled to be made to the tree, such
433
# as updating its basis and unversioning paths that were missing.
434
self.work_tree.unversion(self.deleted_ids)
435
self._set_progress_stage("Updating the working tree")
436
self.work_tree.update_basis_by_delta(self.rev_id,
437
self.builder.get_basis_delta())
438
self.reporter.completed(new_revno, self.rev_id)
439
self._process_post_hooks(old_revno, new_revno)
249
# Cannot commit with conflicts present.
250
if len(self.work_tree.conflicts()) > 0:
251
raise ConflictsInTree
253
# Setup the bound branch variables as needed.
254
self._check_bound_branch()
256
# Check that the working tree is up to date
257
old_revno,new_revno = self._check_out_of_date_tree()
259
if self.config is None:
260
self.config = self.branch.get_config()
262
# If provided, ensure the specified files are versioned
263
if specific_files is not None:
264
# Note: We don't actually need the IDs here. This routine
265
# is being called because it raises PathNotVerisonedError
266
# as a side effect of finding the IDs.
267
# XXX: Dont we have filter_unversioned to do this more
269
tree.find_ids_across_trees(specific_files,
270
[self.basis_tree, self.work_tree])
272
# Setup the progress bar. As the number of files that need to be
273
# committed in unknown, progress is reported as stages.
274
# We keep track of entries separately though and include that
275
# information in the progress bar during the relevant stages.
276
self.pb_stage_name = ""
277
self.pb_stage_count = 0
278
self.pb_stage_total = 4
279
if self.bound_branch:
280
self.pb_stage_total += 1
281
self.pb.show_pct = False
282
self.pb.show_spinner = False
283
self.pb.show_eta = False
284
self.pb.show_count = True
285
self.pb.show_bar = True
287
# After a merge, a selected file commit is not supported.
288
# See 'bzr help merge' for an explanation as to why.
289
self.basis_inv = self.basis_tree.inventory
290
self._gather_parents()
291
if len(self.parents) > 1 and self.specific_files:
292
raise errors.CannotCommitSelectedFileMerge(self.specific_files)
294
# Collect the changes
295
self._set_progress_stage("Collecting changes",
296
entries_title="Directory")
297
self.builder = self.branch.get_commit_builder(self.parents,
298
self.config, timestamp, timezone, committer, revprops, rev_id)
300
self._update_builder_with_changes()
301
self._check_pointless()
303
# TODO: Now the new inventory is known, check for conflicts.
304
# ADHB 2006-08-08: If this is done, populate_new_inv should not add
305
# weave lines, because nothing should be recorded until it is known
306
# that commit will succeed.
307
self._set_progress_stage("Saving data locally")
308
self.builder.finish_inventory()
310
# Prompt the user for a commit message if none provided
311
message = message_callback(self)
312
assert isinstance(message, unicode), type(message)
313
self.message = message
314
self._escape_commit_message()
316
# Add revision data to the local branch
317
self.rev_id = self.builder.commit(self.message)
322
# Upload revision data to the master.
323
# this will propagate merged revisions too if needed.
324
if self.bound_branch:
325
self._set_progress_stage("Uploading data to master branch")
326
self.master_branch.repository.fetch(self.branch.repository,
327
revision_id=self.rev_id)
328
# now the master has the revision data
329
# 'commit' to the master first so a timeout here causes the
330
# local branch to be out of date
331
self.master_branch.set_last_revision_info(new_revno,
334
# and now do the commit locally.
335
self.branch.set_last_revision_info(new_revno, self.rev_id)
337
# Make the working tree up to date with the branch
338
self._set_progress_stage("Updating the working tree")
339
rev_tree = self.builder.revision_tree()
340
self.work_tree.set_parent_trees([(self.rev_id, rev_tree)])
341
self.reporter.completed(new_revno, self.rev_id)
342
self._process_hooks(old_revno, new_revno)
440
345
return self.rev_id
442
def _select_reporter(self):
443
"""Select the CommitReporter to use."""
445
return NullCommitReporter()
446
return ReportCommitToLog()
347
def _any_real_changes(self):
348
"""Are there real changes between new_inventory and basis?
350
For trees without rich roots, inv.root.revision changes every commit.
351
But if that is the only change, we want to treat it as though there
354
new_entries = self.builder.new_inventory.iter_entries()
355
basis_entries = self.basis_inv.iter_entries()
356
new_path, new_root_ie = new_entries.next()
357
basis_path, basis_root_ie = basis_entries.next()
359
# This is a copy of InventoryEntry.__eq__ only leaving out .revision
360
def ie_equal_no_revision(this, other):
361
return ((this.file_id == other.file_id)
362
and (this.name == other.name)
363
and (this.symlink_target == other.symlink_target)
364
and (this.text_sha1 == other.text_sha1)
365
and (this.text_size == other.text_size)
366
and (this.text_id == other.text_id)
367
and (this.parent_id == other.parent_id)
368
and (this.kind == other.kind)
369
and (this.executable == other.executable)
370
and (this.reference_revision == other.reference_revision)
372
if not ie_equal_no_revision(new_root_ie, basis_root_ie):
375
for new_ie, basis_ie in zip(new_entries, basis_entries):
376
if new_ie != basis_ie:
379
# No actual changes present
448
382
def _check_pointless(self):
449
383
if self.allow_pointless:
571
493
old_revid = self.parents[0]
573
495
old_revid = bzrlib.revision.NULL_REVISION
575
if hook_name == "pre_commit":
576
future_tree = self.builder.revision_tree()
577
tree_delta = future_tree.changes_from(self.basis_tree,
580
for hook in Branch.hooks[hook_name]:
496
for hook in Branch.hooks['post_commit']:
581
497
# show the running hook in the progress bar. As hooks may
582
498
# end up doing nothing (e.g. because they are not configured by
583
499
# the user) this is still showing progress, not showing overall
584
500
# actions - its up to each plugin to show a UI if it want's to
585
501
# (such as 'Emailing diff to foo@example.com').
586
self.pb_stage_name = "Running %s hooks [%s]" % \
587
(hook_name, Branch.hooks.get_hook_name(hook))
502
self.pb_stage_name = "Running post commit hooks [%s]" % \
503
Branch.hooks.get_hook_name(hook)
588
504
self._emit_progress()
589
505
if 'hooks' in debug.debug_flags:
590
506
mutter("Invoking commit hook: %r", hook)
591
if hook_name == "post_commit":
592
hook(hook_local, hook_master, old_revno, old_revid, new_revno,
594
elif hook_name == "pre_commit":
595
hook(hook_local, hook_master,
596
old_revno, old_revid, new_revno, self.rev_id,
597
tree_delta, future_tree)
507
hook(hook_local, hook_master, old_revno, old_revid, new_revno,
511
"""Cleanup any open locks, progress bars etc."""
512
cleanups = [self._cleanup_bound_branch,
513
self.basis_tree.unlock,
514
self.work_tree.unlock,
516
found_exception = None
517
for cleanup in cleanups:
520
# we want every cleanup to run no matter what.
521
# so we have a catchall here, but we will raise the
522
# last encountered exception up the stack: and
523
# typically this will be useful enough.
526
if found_exception is not None:
527
# don't do a plan raise, because the last exception may have been
528
# trashed, e is our sure-to-work exception even though it loses the
529
# full traceback. XXX: RBC 20060421 perhaps we could check the
530
# exc_info and if its the same one do a plain raise otherwise
531
# 'raise e' as we do now.
534
def _cleanup_bound_branch(self):
535
"""Executed at the end of a try/finally to cleanup a bound branch.
537
If the branch wasn't bound, this is a no-op.
538
If it was, it resents self.branch to the local branch, instead
541
if not self.bound_branch:
543
if self.master_locked:
544
self.master_branch.unlock()
546
def _escape_commit_message(self):
547
"""Replace xml-incompatible control characters."""
548
# FIXME: RBC 20060419 this should be done by the revision
549
# serialiser not by commit. Then we can also add an unescaper
550
# in the deserializer and start roundtripping revision messages
551
# precisely. See repository_implementations/test_repository.py
553
# Python strings can include characters that can't be
554
# represented in well-formed XML; escape characters that
555
# aren't listed in the XML specification
556
# (http://www.w3.org/TR/REC-xml/#NT-Char).
557
self.message, escape_count = re.subn(
558
u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
559
lambda match: match.group(0).encode('unicode_escape'),
562
self.reporter.escaped(escape_count, self.message)
599
564
def _gather_parents(self):
600
565
"""Record the parents of a merge for merge detection."""
601
# TODO: Make sure that this list doesn't contain duplicate
566
# TODO: Make sure that this list doesn't contain duplicate
602
567
# entries and the order is preserved when doing this.
603
if self.use_record_iter_changes:
605
self.basis_inv = self.basis_tree.inventory
568
self.parents = self.work_tree.get_parent_ids()
606
569
self.parent_invs = [self.basis_inv]
607
570
for revision in self.parents[1:]:
608
571
if self.branch.repository.has_revision(revision):
615
578
def _update_builder_with_changes(self):
616
579
"""Update the commit builder with the data about what has changed.
618
exclude = self.exclude
581
# Build the revision inventory.
583
# This starts by creating a new empty inventory. Depending on
584
# which files are selected for commit, and what is present in the
585
# current tree, the new inventory is populated. inventory entries
586
# which are candidates for modification have their revision set to
587
# None; inventory entries that are carried over untouched have their
588
# revision set to their prior value.
590
# ESEPARATIONOFCONCERNS: this function is diffing and using the diff
591
# results to create a new inventory at the same time, which results
592
# in bugs like #46635. Any reason not to use/enhance Tree.changes_from?
619
595
specific_files = self.specific_files
620
596
mutter("Selecting files for commit with filter %s", specific_files)
623
if self.use_record_iter_changes:
624
iter_changes = self.work_tree.iter_changes(self.basis_tree,
625
specific_files=specific_files)
626
iter_changes = self._filter_iter_changes(iter_changes)
627
for file_id, path, fs_hash in self.builder.record_iter_changes(
628
self.work_tree, self.basis_revid, iter_changes):
629
self.work_tree._observed_sha1(file_id, path, fs_hash)
631
# Build the new inventory
632
self._populate_from_inventory()
633
self._record_unselected()
634
self._report_and_accumulate_deletes()
636
def _filter_iter_changes(self, iter_changes):
637
"""Process iter_changes.
639
This method reports on the changes in iter_changes to the user, and
640
converts 'missing' entries in the iter_changes iterator to 'deleted'
641
entries. 'missing' entries have their
643
:param iter_changes: An iter_changes to process.
644
:return: A generator of changes.
646
reporter = self.reporter
647
report_changes = reporter.is_verbose()
649
for change in iter_changes:
651
old_path = change[1][0]
652
new_path = change[1][1]
653
versioned = change[3][1]
655
versioned = change[3][1]
656
if kind is None and versioned:
659
reporter.missing(new_path)
660
deleted_ids.append(change[0])
661
# Reset the new path (None) and new versioned flag (False)
662
change = (change[0], (change[1][0], None), change[2],
663
(change[3][0], False)) + change[4:]
664
elif kind == 'tree-reference':
665
if self.recursive == 'down':
666
self._commit_nested_tree(change[0], change[1][1])
667
if change[3][0] or change[3][1]:
671
reporter.deleted(old_path)
672
elif old_path is None:
673
reporter.snapshot_change('added', new_path)
674
elif old_path != new_path:
675
reporter.renamed('renamed', old_path, new_path)
678
self.work_tree.branch.repository._format.rich_root_data):
679
# Don't report on changes to '' in non rich root
681
reporter.snapshot_change('modified', new_path)
682
self._next_progress_entry()
683
# Unversion IDs that were found to be deleted
684
self.deleted_ids = deleted_ids
686
def _record_unselected(self):
598
# Check and warn about old CommitBuilders
599
if not self.builder.record_root_entry:
600
symbol_versioning.warn('CommitBuilders should support recording'
601
' the root entry as of bzr 0.10.', DeprecationWarning,
603
self.builder.new_inventory.add(self.basis_inv.root.copy())
605
# Build the new inventory
606
self._populate_from_inventory(specific_files)
687
608
# If specific files are selected, then all un-selected files must be
688
609
# recorded in their previous state. For more details, see
689
610
# https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
690
if self.specific_files or self.exclude:
691
specific_files = self.specific_files or []
692
for path, old_ie in self.basis_inv.iter_entries():
693
if old_ie.file_id in self.builder.new_inventory:
694
# already added - skip.
696
if (is_inside_any(specific_files, path)
697
and not is_inside_any(self.exclude, path)):
698
# was inside the selected path, and not excluded - if not
699
# present it has been deleted so skip.
701
# From here down it was either not selected, or was excluded:
702
# We preserve the entry unaltered.
704
# Note: specific file commits after a merge are currently
705
# prohibited. This test is for sanity/safety in case it's
706
# required after that changes.
707
if len(self.parents) > 1:
612
for path, new_ie in self.basis_inv.iter_entries():
613
if new_ie.file_id in self.builder.new_inventory:
615
if is_inside_any(specific_files, path):
709
619
self.builder.record_entry_contents(ie, self.parent_invs, path,
710
self.basis_tree, None)
712
def _report_and_accumulate_deletes(self):
713
if (isinstance(self.basis_inv, Inventory)
714
and isinstance(self.builder.new_inventory, Inventory)):
715
# the older Inventory classes provide a _byid dict, and building a
716
# set from the keys of this dict is substantially faster than even
717
# getting a set of ids from the inventory
719
# <lifeless> set(dict) is roughly the same speed as
720
# set(iter(dict)) and both are significantly slower than
722
deleted_ids = set(self.basis_inv._byid.keys()) - \
723
set(self.builder.new_inventory._byid.keys())
725
deleted_ids = set(self.basis_inv) - set(self.builder.new_inventory)
727
self.any_entries_deleted = True
728
deleted = [(self.basis_tree.id2path(file_id), file_id)
729
for file_id in deleted_ids]
731
# XXX: this is not quite directory-order sorting
732
for path, file_id in deleted:
733
self.builder.record_delete(path, file_id)
622
# Report what was deleted. We could skip this when no deletes are
623
# detected to gain a performance win, but it arguably serves as a
624
# 'safety check' by informing the user whenever anything disappears.
625
for path, ie in self.basis_inv.iter_entries():
626
if ie.file_id not in self.builder.new_inventory:
734
627
self.reporter.deleted(path)
736
def _check_strict(self):
737
# XXX: when we use iter_changes this would likely be faster if
738
# iter_changes would check for us (even in the presence of
629
def _populate_from_inventory(self, specific_files):
630
"""Populate the CommitBuilder by walking the working tree inventory."""
741
632
# raise an exception as soon as we find a single unknown.
742
633
for unknown in self.work_tree.unknowns():
743
634
raise StrictCommitFailed()
745
def _populate_from_inventory(self):
746
"""Populate the CommitBuilder by walking the working tree inventory."""
747
# Build the revision inventory.
749
# This starts by creating a new empty inventory. Depending on
750
# which files are selected for commit, and what is present in the
751
# current tree, the new inventory is populated. inventory entries
752
# which are candidates for modification have their revision set to
753
# None; inventory entries that are carried over untouched have their
754
# revision set to their prior value.
756
# ESEPARATIONOFCONCERNS: this function is diffing and using the diff
757
# results to create a new inventory at the same time, which results
758
# in bugs like #46635. Any reason not to use/enhance Tree.changes_from?
761
specific_files = self.specific_files
762
exclude = self.exclude
763
report_changes = self.reporter.is_verbose()
765
# A tree of paths that have been deleted. E.g. if foo/bar has been
766
# deleted, then we have {'foo':{'bar':{}}}
768
# XXX: Note that entries may have the wrong kind because the entry does
769
# not reflect the status on disk.
637
deleted_paths = set()
770
638
work_inv = self.work_tree.inventory
771
# NB: entries will include entries within the excluded ids/paths
772
# because iter_entries_by_dir has no 'exclude' facility today.
773
entries = work_inv.iter_entries_by_dir(
774
specific_file_ids=self.specific_file_ids, yield_parents=True)
639
assert work_inv.root is not None
640
entries = work_inv.iter_entries()
641
if not self.builder.record_root_entry:
775
643
for path, existing_ie in entries:
776
644
file_id = existing_ie.file_id
777
645
name = existing_ie.name
778
646
parent_id = existing_ie.parent_id
779
647
kind = existing_ie.kind
648
if kind == 'directory':
649
self._next_progress_entry()
780
651
# Skip files that have been deleted from the working tree.
781
# The deleted path ids are also recorded so they can be explicitly
784
path_segments = splitpath(path)
785
deleted_dict = deleted_paths
786
for segment in path_segments:
787
deleted_dict = deleted_dict.get(segment, None)
789
# We either took a path not present in the dict
790
# (deleted_dict was None), or we've reached an empty
791
# child dir in the dict, so are now a sub-path.
795
if deleted_dict is not None:
796
# the path has a deleted parent, do not add it.
798
if exclude and is_inside_any(exclude, path):
799
# Skip excluded paths. Excluded paths are processed by
800
# _update_builder_with_changes.
652
# The deleted files/directories are also recorded so they
653
# can be explicitly unversioned later. Note that when a
654
# filter of specific files is given, we must only skip/record
655
# deleted files matching that filter.
656
if is_inside_any(deleted_paths, path):
802
content_summary = self.work_tree.path_content_summary(path)
803
kind = content_summary[0]
804
# Note that when a filter of specific files is given, we must only
805
# skip/record deleted files matching that filter.
806
658
if not specific_files or is_inside_any(specific_files, path):
807
if kind == 'missing':
808
if not deleted_paths:
809
# path won't have been split yet.
810
path_segments = splitpath(path)
811
deleted_dict = deleted_paths
812
for segment in path_segments:
813
deleted_dict = deleted_dict.setdefault(segment, {})
659
if not self.work_tree.has_filename(path):
660
deleted_paths.add(path)
814
661
self.reporter.missing(path)
815
self._next_progress_entry()
816
662
deleted_ids.append(file_id)
818
# TODO: have the builder do the nested commit just-in-time IF and
820
if kind == 'tree-reference':
821
# enforce repository nested tree policy.
822
if (not self.work_tree.supports_tree_reference() or
823
# repository does not support it either.
824
not self.branch.repository._format.supports_tree_reference):
826
content_summary = (kind, None, None, None)
827
elif self.recursive == 'down':
828
nested_revision_id = self._commit_nested_tree(
830
content_summary = (kind, None, None, nested_revision_id)
832
nested_revision_id = self.work_tree.get_reference_revision(file_id)
833
content_summary = (kind, None, None, nested_revision_id)
665
kind = self.work_tree.kind(file_id)
666
# TODO: specific_files filtering before nested tree processing
667
if kind == 'tree-reference' and self.recursive == 'down':
668
self._commit_nested_tree(file_id, path)
669
except errors.NoSuchFile:
835
672
# Record an entry for this item
836
673
# Note: I don't particularly want to have the existing_ie
837
674
# parameter but the test suite currently (28-Jun-07) breaks
838
675
# without it thanks to a unicode normalisation issue. :-(
839
definitely_changed = kind != existing_ie.kind
676
definitely_changed = kind != existing_ie.kind
840
677
self._record_entry(path, file_id, specific_files, kind, name,
841
parent_id, definitely_changed, existing_ie, report_changes,
678
parent_id, definitely_changed, existing_ie)
844
680
# Unversion IDs that were found to be deleted
845
self.deleted_ids = deleted_ids
681
self.work_tree.unversion(deleted_ids)
847
683
def _commit_nested_tree(self, file_id, path):
848
684
"Commit a nested tree."
867
703
strict=self.strict, verbose=self.verbose,
868
704
local=self.local, reporter=self.reporter)
869
705
except errors.PointlessCommit:
870
return self.work_tree.get_reference_revision(file_id)
872
708
def _record_entry(self, path, file_id, specific_files, kind, name,
873
parent_id, definitely_changed, existing_ie, report_changes,
709
parent_id, definitely_changed, existing_ie=None):
875
710
"Record the new inventory entry for a path if any."
876
711
# mutter('check %s {%s}', path, file_id)
877
# mutter('%s selected for commit', path)
878
if definitely_changed or existing_ie is None:
879
ie = make_entry(kind, name, parent_id, file_id)
712
if (not specific_files or
713
is_inside_or_parent_of_any(specific_files, path)):
714
# mutter('%s selected for commit', path)
715
if definitely_changed or existing_ie is None:
716
ie = inventory.make_entry(kind, name, parent_id, file_id)
718
ie = existing_ie.copy()
881
ie = existing_ie.copy()
883
# For carried over entries we don't care about the fs hash - the repo
884
# isn't generating a sha, so we're not saving computation time.
885
_, _, fs_hash = self.builder.record_entry_contents(
886
ie, self.parent_invs, path, self.work_tree, content_summary)
721
# mutter('%s not selected for commit', path)
722
if self.basis_inv.has_id(file_id):
723
ie = self.basis_inv[file_id].copy()
725
# this entry is new and not being committed
728
self.builder.record_entry_contents(ie, self.parent_invs,
729
path, self.work_tree)
888
730
self._report_change(ie, path)
890
self.work_tree._observed_sha1(ie.file_id, path, fs_hash)
893
733
def _report_change(self, ie, path):