~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/commit.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-08-05 01:14:07 UTC
  • mfrom: (3602.1.5 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080805011407-wmq7130znc0e6c4x
(robertc) Implement a --exclude option for commit which allows the
        exclusion of paths from the commit change detection logic.
        (Robert Collins, \#3117)

Show diffs side-by-side

added added

removed removed

Lines of Context:
204
204
               reporter=None,
205
205
               config=None,
206
206
               message_callback=None,
207
 
               recursive='down'):
 
207
               recursive='down',
 
208
               exclude=None):
208
209
        """Commit working copy as a new revision.
209
210
 
210
211
        :param message: the commit message (it or message_callback is required)
232
233
        :param verbose: if True and the reporter is not None, report everything
233
234
        :param recursive: If set to 'down', commit in any subtrees that have
234
235
            pending changes of any sort during this commit.
 
236
        :param exclude: None or a list of relative paths to exclude from the
 
237
            commit. Pending changes to excluded files will be ignored by the
 
238
            commit. 
235
239
        """
236
240
        mutter('preparing to commit')
237
241
 
255
259
        self.bound_branch = None
256
260
        self.any_entries_changed = False
257
261
        self.any_entries_deleted = False
 
262
        if exclude is not None:
 
263
            self.exclude = sorted(
 
264
                minimum_path_selection(exclude))
 
265
        else:
 
266
            self.exclude = []
258
267
        self.local = local
259
268
        self.master_branch = None
260
269
        self.master_locked = False
329
338
            self.pb.show_count = True
330
339
            self.pb.show_bar = True
331
340
 
 
341
            self.basis_inv = self.basis_tree.inventory
 
342
            self._gather_parents()
332
343
            # After a merge, a selected file commit is not supported.
333
344
            # See 'bzr help merge' for an explanation as to why.
334
 
            self.basis_inv = self.basis_tree.inventory
335
 
            self._gather_parents()
336
345
            if len(self.parents) > 1 and self.specific_files:
337
346
                raise errors.CannotCommitSelectedFileMerge(self.specific_files)
 
347
            # Excludes are a form of selected file commit.
 
348
            if len(self.parents) > 1 and self.exclude:
 
349
                raise errors.CannotCommitSelectedFileMerge(self.exclude)
338
350
 
339
351
            # Collect the changes
340
352
            self._set_progress_stage("Collecting changes",
648
660
        # in bugs like #46635.  Any reason not to use/enhance Tree.changes_from?
649
661
        # ADHB 11-07-2006
650
662
 
651
 
        specific_files = self.specific_files
 
663
        exclude = self.exclude
 
664
        specific_files = self.specific_files or []
652
665
        mutter("Selecting files for commit with filter %s", specific_files)
653
666
 
654
667
        # Build the new inventory
655
 
        self._populate_from_inventory(specific_files)
 
668
        self._populate_from_inventory()
656
669
 
657
670
        # If specific files are selected, then all un-selected files must be
658
671
        # recorded in their previous state. For more details, see
659
672
        # https://lists.ubuntu.com/archives/bazaar/2007q3/028476.html.
660
 
        if specific_files:
 
673
        if specific_files or exclude:
661
674
            for path, old_ie in self.basis_inv.iter_entries():
662
675
                if old_ie.file_id in self.builder.new_inventory:
663
676
                    # already added - skip.
664
677
                    continue
665
 
                if is_inside_any(specific_files, path):
666
 
                    # was inside the selected path, if not present it has been
667
 
                    # deleted so skip.
 
678
                if (is_inside_any(specific_files, path)
 
679
                    and not is_inside_any(exclude, path)):
 
680
                    # was inside the selected path, and not excluded - if not
 
681
                    # present it has been deleted so skip.
668
682
                    continue
 
683
                # From here down it was either not selected, or was excluded:
669
684
                if old_ie.kind == 'directory':
670
685
                    self._next_progress_entry()
671
 
                # not in final inv yet, was not in the selected files, so is an
672
 
                # entry to be preserved unaltered.
 
686
                # We preserve the entry unaltered.
673
687
                ie = old_ie.copy()
674
688
                # Note: specific file commits after a merge are currently
675
689
                # prohibited. This test is for sanity/safety in case it's
697
711
                self._basis_delta.append((path, None, file_id, None))
698
712
                self.reporter.deleted(path)
699
713
 
700
 
    def _populate_from_inventory(self, specific_files):
 
714
    def _populate_from_inventory(self):
701
715
        """Populate the CommitBuilder by walking the working tree inventory."""
702
716
        if self.strict:
703
717
            # raise an exception as soon as we find a single unknown.
704
718
            for unknown in self.work_tree.unknowns():
705
719
                raise StrictCommitFailed()
706
 
               
 
720
        
 
721
        specific_files = self.specific_files
 
722
        exclude = self.exclude
707
723
        report_changes = self.reporter.is_verbose()
708
724
        deleted_ids = []
709
725
        # A tree of paths that have been deleted. E.g. if foo/bar has been
712
728
        # XXX: Note that entries may have the wrong kind because the entry does
713
729
        # not reflect the status on disk.
714
730
        work_inv = self.work_tree.inventory
 
731
        # NB: entries will include entries within the excluded ids/paths
 
732
        # because iter_entries_by_dir has no 'exclude' facility today.
715
733
        entries = work_inv.iter_entries_by_dir(
716
734
            specific_file_ids=self.specific_file_ids, yield_parents=True)
717
735
        for path, existing_ie in entries:
739
757
                if deleted_dict is not None:
740
758
                    # the path has a deleted parent, do not add it.
741
759
                    continue
 
760
            if exclude and is_inside_any(exclude, path):
 
761
                # Skip - it is to be considered by the final copy-from-basis
 
762
                # step.
 
763
                continue
742
764
            content_summary = self.work_tree.path_content_summary(path)
743
765
            # Note that when a filter of specific files is given, we must only
744
766
            # skip/record deleted files matching that filter.