232
234
self.revprops.update(revprops)
234
# check for out of date working trees
235
if self.work_tree.last_revision() != self.branch.last_revision():
236
raise errors.OutOfDateTree(self.work_tree)
239
# raise an exception as soon as we find a single unknown.
240
for unknown in self.work_tree.unknowns():
241
raise StrictCommitFailed()
243
if timestamp is None:
244
self.timestamp = time.time()
246
self.timestamp = long(timestamp)
248
if self.config is None:
249
self.config = bzrlib.config.BranchConfig(self.branch)
252
self.rev_id = _gen_revision_id(self.config, self.timestamp)
256
if committer is None:
257
self.committer = self.config.username()
259
assert isinstance(committer, basestring), type(committer)
260
self.committer = committer
263
self.timezone = local_time_offset()
265
self.timezone = int(timezone)
267
if isinstance(message, str):
268
message = message.decode(bzrlib.user_encoding)
269
assert isinstance(message, unicode), type(message)
270
self.message = message
271
self._escape_commit_message()
273
self.branch.lock_write()
236
self.work_tree.lock_write()
238
# setup the bound branch variables as needed.
239
self._check_bound_branch()
241
# check for out of date working trees
242
# if we are bound, then self.branch is the master branch and this
243
# test is thus all we need.
244
if self.work_tree.last_revision() != self.branch.last_revision():
245
raise errors.OutOfDateTree(self.work_tree)
248
# raise an exception as soon as we find a single unknown.
249
for unknown in self.work_tree.unknowns():
250
raise StrictCommitFailed()
252
if timestamp is None:
253
self.timestamp = time.time()
255
self.timestamp = long(timestamp)
257
if self.config is None:
258
self.config = bzrlib.config.BranchConfig(self.branch)
261
self.rev_id = _gen_revision_id(self.config, self.timestamp)
265
if committer is None:
266
self.committer = self.config.username()
268
assert isinstance(committer, basestring), type(committer)
269
self.committer = committer
272
self.timezone = local_time_offset()
274
self.timezone = int(timezone)
276
if isinstance(message, str):
277
message = message.decode(bzrlib.user_encoding)
278
assert isinstance(message, unicode), type(message)
279
self.message = message
280
self._escape_commit_message()
275
282
self.work_inv = self.work_tree.inventory
276
283
self.basis_tree = self.work_tree.basis_tree()
277
284
self.basis_inv = self.basis_tree.inventory
300
307
self.present_parents
302
309
self._make_revision()
310
# revision is in the master branch now.
312
self.branch.append_revision(self.rev_id)
313
# now its in the master branch history.
315
self._update_bound_branch()
316
# now the local branch is up to date
303
318
self.work_tree.set_pending_merges([])
304
self.branch.append_revision(self.rev_id)
305
319
if len(self.parents):
306
320
precursor = self.parents[0]
309
323
self.work_tree.set_last_revision(self.rev_id, precursor)
324
# now the work tree is up to date with the branch
310
326
self.reporter.completed(self.branch.revno()+1, self.rev_id)
311
327
if self.config.post_commit() is not None:
312
328
hooks = self.config.post_commit().split(' ')
318
334
'rev_id':self.rev_id})
336
self._cleanup_bound_branch()
337
self.work_tree.unlock()
339
def _check_bound_branch(self):
340
"""Check to see if the local branch is bound.
342
If it is bound, then most of the commit will actually be
343
done using the remote branch as the target branch.
344
Only at the end will the local branch be updated.
346
# TODO: jam 20051230 Consider a special error for the case
347
# where the local branch is bound, and can't access the
349
self.master_branch = self.branch.get_master_branch()
350
if not self.master_branch:
353
# If the master branch is bound, we must fail
354
master_bound_location = self.master_branch.get_bound_location()
355
if master_bound_location:
356
raise errors.CommitToDoubleBoundBranch(self.branch,
357
self.master_branch, master_bound_location)
359
# TODO: jam 20051230 We could automatically push local
360
# commits to the remote branch if they would fit.
361
# But for now, just require remote to be identical
364
# Make sure the local branch is identical to the master
365
master_rh = self.master_branch.revision_history()
366
local_rh = self.branch.revision_history()
367
if local_rh != master_rh:
368
raise errors.BoundBranchOutOfDate(self.branch,
371
# Now things are ready to change the master branch
373
self.bound_branch = self.branch
374
self.master_branch.lock_write()
375
self.branch = self.master_branch
377
# Check to see if we have any pending merges. If we do
378
# those need to be pushed into the master branch
379
pending_merges = self.work_tree.pending_merges()
381
for revision_id in pending_merges:
382
self.master_branch.repository.fetch(self.bound_branch.repository,
383
revision_id=revision_id)
385
def _cleanup_bound_branch(self):
386
"""Executed at the end of a try/finally to cleanup a bound branch.
388
If the branch wasn't bound, this is a no-op.
389
If it was, it resents self.branch to the local branch, instead
392
if not self.bound_branch:
394
self.branch = self.bound_branch
395
self.master_branch.unlock()
397
def _update_bound_branch(self):
398
"""Update the local bound branch, after commit.
400
This only runs if the commit to the master branch succeeds.
402
if not self.bound_branch:
404
# We always want the local branch to look like the remote one
405
# TODO: jam 20051231 We might want overwrite=True here, but
406
# the local branch should be a prefix of master anyway
407
self.bound_branch.pull(self.master_branch)
409
# TODO: jam 20051231 At this point we probably
410
# want to merge any changes into master branch's
322
413
def _escape_commit_message(self):
323
414
"""Replace xml-incompatible control characters."""
324
415
# Python strings can include characters that can't be