245
250
self._check_bound_branch()
247
252
# check for out of date working trees
248
# if we are bound, then self.branch is the master branch and this
249
# test is thus all we need.
254
first_tree_parent = self.work_tree.get_parent_ids()[0]
256
# if there are no parents, treat our parent as 'None'
257
# this is so that we still consier the master branch
258
# - in a checkout scenario the tree may have no
259
# parents but the branch may do.
260
first_tree_parent = None
250
261
master_last = self.master_branch.last_revision()
251
if (master_last is not None and
252
master_last != self.work_tree.last_revision()):
262
if (master_last is not None and
263
master_last != first_tree_parent):
253
264
raise errors.OutOfDateTree(self.work_tree)
269
280
self.work_inv = self.work_tree.inventory
270
281
self.basis_tree = self.work_tree.basis_tree()
271
282
self.basis_inv = self.basis_tree.inventory
283
if specific_files is not None:
284
# Ensure specified files are versioned
285
# (We don't actually need the ids here)
286
tree.find_ids_across_trees(specific_files,
287
[self.basis_tree, self.work_tree])
272
288
# one to finish, one for rev and inventory, and one for each
273
289
# inventory entry, and the same for the new inventory.
274
290
# note that this estimate is too long when we do a partial tree
289
305
self._populate_new_inv()
290
306
self._report_deletes()
292
if not (self.allow_pointless
293
or len(self.parents) > 1
294
or self.builder.new_inventory != self.basis_inv):
295
raise PointlessCommit()
308
self._check_pointless()
297
310
self._emit_progress_update()
298
311
# TODO: Now the new inventory is known, check for conflicts and
319
332
# and now do the commit locally.
320
333
self.branch.append_revision(self.rev_id)
322
# if the builder gave us the revisiontree it created back, we
323
# could use it straight away here.
324
# TODO: implement this.
325
self.work_tree.set_parent_trees([(self.rev_id,
326
self.branch.repository.revision_tree(self.rev_id))])
335
rev_tree = self.builder.revision_tree()
336
self.work_tree.set_parent_trees([(self.rev_id, rev_tree)])
327
337
# now the work tree is up to date with the branch
329
339
self.reporter.completed(self.branch.revno(), self.rev_id)
341
351
return self.rev_id
353
def _any_real_changes(self):
354
"""Are there real changes between new_inventory and basis?
356
For trees without rich roots, inv.root.revision changes every commit.
357
But if that is the only change, we want to treat it as though there
360
new_entries = self.builder.new_inventory.iter_entries()
361
basis_entries = self.basis_inv.iter_entries()
362
new_path, new_root_ie = new_entries.next()
363
basis_path, basis_root_ie = basis_entries.next()
365
# This is a copy of InventoryEntry.__eq__ only leaving out .revision
366
def ie_equal_no_revision(this, other):
367
return ((this.file_id == other.file_id)
368
and (this.name == other.name)
369
and (this.symlink_target == other.symlink_target)
370
and (this.text_sha1 == other.text_sha1)
371
and (this.text_size == other.text_size)
372
and (this.text_id == other.text_id)
373
and (this.parent_id == other.parent_id)
374
and (this.kind == other.kind)
375
and (this.executable == other.executable)
377
if not ie_equal_no_revision(new_root_ie, basis_root_ie):
380
for new_ie, basis_ie in zip(new_entries, basis_entries):
381
if new_ie != basis_ie:
384
# No actual changes present
387
def _check_pointless(self):
388
if self.allow_pointless:
390
# A merge with no effect on files
391
if len(self.parents) > 1:
393
# Shortcut, if the number of entries changes, then we obviously have
395
if len(self.builder.new_inventory) != len(self.basis_inv):
397
# If length == 1, then we only have the root entry. Which means
398
# that there is no real difference (only the root could be different)
399
if (len(self.builder.new_inventory) != 1 and self._any_real_changes()):
401
raise PointlessCommit()
343
403
def _check_bound_branch(self):
344
404
"""Check to see if the local branch is bound.
463
523
specific = self.specific_files
525
deleted_paths = set()
465
526
for path, ie in self.work_inv.iter_entries():
527
if is_inside_any(deleted_paths, path):
528
# The tree will delete the required ids recursively.
466
530
if specific and not is_inside_any(specific, path):
468
532
if not self.work_tree.has_filename(path):
533
deleted_paths.add(path)
469
534
self.reporter.missing(path)
470
deleted_ids.append((path, ie.file_id))
472
deleted_ids.sort(reverse=True)
473
for path, file_id in deleted_ids:
474
del self.work_inv[file_id]
475
self.work_tree._write_inventory(self.work_inv)
535
deleted_ids.append(ie.file_id)
536
self.work_tree.unversion(deleted_ids)
477
538
def _populate_new_inv(self):
478
539
"""Build revision inventory.