1
1
# Copyright (C) 2005, 2006 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
18
18
# XXX: Can we do any better about making interrupted commits change
19
# nothing? Perhaps the best approach is to integrate commit of
20
# AtomicFiles with releasing the lock on the Branch.
22
21
# TODO: Separate 'prepare' phase where we find a list of potentially
23
22
# committed files. We then can then pause the commit to prompt for a
72
71
from cStringIO import StringIO
74
from bzrlib.atomicfile import AtomicFile
75
73
import bzrlib.config
76
74
import bzrlib.errors as errors
77
75
from bzrlib.errors import (BzrError, PointlessCommit,
86
83
from bzrlib.trace import mutter, note, warning
87
84
from bzrlib.xml5 import serializer_v5
88
85
from bzrlib.inventory import Inventory, ROOT_ID, InventoryEntry
89
from bzrlib.symbol_versioning import *
86
from bzrlib.symbol_versioning import (deprecated_passed,
90
90
from bzrlib.workingtree import WorkingTree
221
221
mutter('preparing to commit')
223
223
if deprecated_passed(branch):
224
warn("Commit.commit (branch, ...): The branch parameter is "
224
warnings.warn("Commit.commit (branch, ...): The branch parameter is "
225
225
"deprecated as of bzr 0.8. Please use working_tree= instead.",
226
226
DeprecationWarning, stacklevel=2)
227
227
self.branch = branch
269
269
raise StrictCommitFailed()
271
271
if self.config is None:
272
self.config = bzrlib.config.BranchConfig(self.branch)
272
self.config = self.branch.get_config()
274
274
if isinstance(message, str):
275
275
message = message.decode(bzrlib.user_encoding)
386
386
self.bound_branch = self.branch
387
387
self.master_branch.lock_write()
388
388
self.master_locked = True
390
#### # Check to see if we have any pending merges. If we do
391
#### # those need to be pushed into the master branch
392
#### pending_merges = self.work_tree.pending_merges()
393
#### if pending_merges:
394
#### for revision_id in pending_merges:
395
#### self.master_branch.repository.fetch(self.bound_branch.repository,
396
#### revision_id=revision_id)
398
390
def _cleanup(self):
399
391
"""Cleanup any open locks, progress bars etc."""
452
444
"""Record the parents of a merge for merge detection."""
453
445
# TODO: Make sure that this list doesn't contain duplicate
454
446
# entries and the order is preserved when doing this.
455
pending_merges = self.work_tree.pending_merges()
447
self.parents = self.work_tree.get_parent_ids()
457
448
self.parent_invs = []
458
precursor_id = self.branch.last_revision()
460
self.parents.append(precursor_id)
461
self.parents += pending_merges
462
449
for revision in self.parents:
463
450
if self.branch.repository.has_revision(revision):
464
451
inventory = self.branch.repository.get_inventory(revision)
470
457
if not self.branch.repository.has_revision(parent_id):
471
458
if parent_id == self.branch.last_revision():
472
459
warning("parent is missing %r", parent_id)
473
raise HistoryMissing(self.branch, 'revision', parent_id)
475
mutter("commit will ghost revision %r", parent_id)
460
raise BzrCheckError("branch %s is missing revision {%s}"
461
% (self.branch, parent_id))
477
463
def _remove_deleted(self):
478
464
"""Remove deleted files from the working inventories.
509
495
None; inventory entries that are carried over untouched have their
510
496
revision set to their prior value.
498
# ESEPARATIONOFCONCERNS: this function is diffing and using the diff
499
# results to create a new inventory at the same time, which results
500
# in bugs like #46635. Any reason not to use/enhance Tree.changes_from?
512
502
mutter("Selecting files for commit with filter %s", self.specific_files)
513
# iter_entries does not visit the ROOT_ID node so we need to call
514
# self._emit_progress_update once by hand.
503
# at this point we dont copy the root entry:
504
entries = self.work_inv.iter_entries()
515
506
self._emit_progress_update()
516
for path, new_ie in self.work_inv.iter_entries():
507
for path, new_ie in entries:
517
508
self._emit_progress_update()
518
509
file_id = new_ie.file_id
519
mutter('check %s {%s}', path, file_id)
510
# mutter('check %s {%s}', path, file_id)
520
511
if (not self.specific_files or
521
512
is_inside_or_parent_of_any(self.specific_files, path)):
522
mutter('%s selected for commit', path)
513
# mutter('%s selected for commit', path)
523
514
ie = new_ie.copy()
524
515
ie.revision = None
526
mutter('%s not selected for commit', path)
517
# mutter('%s not selected for commit', path)
527
518
if self.basis_inv.has_id(file_id):
528
519
ie = self.basis_inv[file_id].copy()
547
538
self.reporter.snapshot_change(change, path)
540
if not self.specific_files:
543
# ignore removals that don't match filespec
544
for path, new_ie in self.basis_inv.iter_entries():
545
if new_ie.file_id in self.work_inv:
547
if is_inside_any(self.specific_files, path):
551
self.builder.record_entry_contents(ie, self.parent_invs, path,
549
554
def _emit_progress_update(self):
550
555
"""Emit an update to the progress bar."""
551
556
self.pb.update("Committing", self.pb_count, self.pb_total)