204
204
"""Commit working copy as a new revision.
206
206
:param message: the commit message (it or message_callback is required)
207
:param message_callback: A callback: message = message_callback(cmt_obj)
208
209
:param timestamp: if not None, seconds-since-epoch for a
209
210
postdated/predated commit.
211
:param specific_files: If true, commit only those files.
212
:param specific_files: If not None, commit only those files. An empty
213
list means 'commit no files'.
213
215
:param rev_id: If set, use this as the new revision id.
214
216
Useful for test or import commands that need to tightly
263
265
self.master_locked = False
264
266
self.recursive = recursive
265
267
self.rev_id = None
268
# self.specific_files is None to indicate no filter, or any iterable to
269
# indicate a filter - [] means no files at all, as per iter_changes.
266
270
if specific_files is not None:
267
271
self.specific_files = sorted(
268
272
minimum_path_selection(specific_files))
284
288
# the command line parameters, and the repository has fast delta
285
289
# generation. See bug 347649.
286
290
self.use_record_iter_changes = (
287
not self.specific_files and
288
291
not self.exclude and
289
292
not self.branch.repository._format.supports_tree_reference and
290
293
(self.branch.repository._format.fast_deltas or
332
335
self._gather_parents()
333
336
# After a merge, a selected file commit is not supported.
334
337
# See 'bzr help merge' for an explanation as to why.
335
if len(self.parents) > 1 and self.specific_files:
338
if len(self.parents) > 1 and self.specific_files is not None:
336
339
raise errors.CannotCommitSelectedFileMerge(self.specific_files)
337
340
# Excludes are a form of selected file commit.
338
341
if len(self.parents) > 1 and self.exclude:
392
395
# and now do the commit locally.
393
396
self.branch.set_last_revision_info(new_revno, self.rev_id)
395
# Make the working tree up to date with the branch
398
# Make the working tree be up to date with the branch. This
399
# includes automatic changes scheduled to be made to the tree, such
400
# as updating its basis and unversioning paths that were missing.
401
self.work_tree.unversion(self.deleted_ids)
396
402
self._set_progress_stage("Updating the working tree")
397
403
self.work_tree.update_basis_by_delta(self.rev_id,
398
404
self.builder.get_basis_delta())
615
621
"""Update the commit builder with the data about what has changed.
617
623
exclude = self.exclude
618
specific_files = self.specific_files or []
624
specific_files = self.specific_files
619
625
mutter("Selecting files for commit with filter %s", specific_files)
621
627
self._check_strict()
622
628
if self.use_record_iter_changes:
623
iter_changes = self.work_tree.iter_changes(self.basis_tree)
629
iter_changes = self.work_tree.iter_changes(self.basis_tree,
630
specific_files=specific_files)
624
631
iter_changes = self._filter_iter_changes(iter_changes)
625
632
for file_id, path, fs_hash in self.builder.record_iter_changes(
626
633
self.work_tree, self.basis_revid, iter_changes):
679
686
reporter.snapshot_change('modified', new_path)
680
687
self._next_progress_entry()
681
688
# Unversion IDs that were found to be deleted
682
self.work_tree.unversion(deleted_ids)
689
self.deleted_ids = deleted_ids
684
691
def _record_unselected(self):
685
692
# If specific files are selected, then all un-selected files must be
798
805
# _update_builder_with_changes.
800
807
content_summary = self.work_tree.path_content_summary(path)
808
kind = content_summary[0]
801
809
# Note that when a filter of specific files is given, we must only
802
810
# skip/record deleted files matching that filter.
803
811
if not specific_files or is_inside_any(specific_files, path):
804
if content_summary[0] == 'missing':
812
if kind == 'missing':
805
813
if not deleted_paths:
806
814
# path won't have been split yet.
807
815
path_segments = splitpath(path)
815
823
# TODO: have the builder do the nested commit just-in-time IF and
816
824
# only if needed.
817
if content_summary[0] == 'tree-reference':
825
if kind == 'tree-reference':
818
826
# enforce repository nested tree policy.
819
827
if (not self.work_tree.supports_tree_reference() or
820
828
# repository does not support it either.
821
829
not self.branch.repository._format.supports_tree_reference):
822
content_summary = ('directory',) + content_summary[1:]
823
kind = content_summary[0]
824
# TODO: specific_files filtering before nested tree processing
825
if kind == 'tree-reference':
826
if self.recursive == 'down':
831
content_summary = (kind, None, None, None)
832
elif self.recursive == 'down':
827
833
nested_revision_id = self._commit_nested_tree(
829
content_summary = content_summary[:3] + (
835
content_summary = (kind, None, None, nested_revision_id)
832
content_summary = content_summary[:3] + (
833
self.work_tree.get_reference_revision(file_id),)
837
nested_revision_id = self.work_tree.get_reference_revision(file_id)
838
content_summary = (kind, None, None, nested_revision_id)
835
840
# Record an entry for this item
836
841
# Note: I don't particularly want to have the existing_ie
844
849
# Unversion IDs that were found to be deleted
845
self.work_tree.unversion(deleted_ids)
850
self.deleted_ids = deleted_ids
847
852
def _commit_nested_tree(self, file_id, path):
848
853
"Commit a nested tree."