52
43
return "bzrlib.ahook bzrlib.ahook"
55
class CapturingReporter(NullCommitReporter):
56
"""This reporter captures the calls made to it for evaluation later."""
59
# a list of the calls this received
62
def snapshot_change(self, change, path):
63
self.calls.append(('change', change, path))
65
def deleted(self, file_id):
66
self.calls.append(('deleted', file_id))
68
def missing(self, path):
69
self.calls.append(('missing', path))
71
def renamed(self, change, old_path, new_path):
72
self.calls.append(('renamed', change, old_path, new_path))
78
class TestCommit(TestCaseWithTransport):
46
class TestCommit(TestCaseInTempDir):
80
48
def test_simple_commit(self):
81
49
"""Commit and check two versions of a single file."""
82
wt = self.make_branch_and_tree('.')
50
b = Branch.initialize('.')
84
51
file('hello', 'w').write('hello world')
86
wt.commit(message='add hello')
87
file_id = wt.path2id('hello')
53
b.commit(message='add hello')
54
file_id = b.working_tree().path2id('hello')
89
56
file('hello', 'w').write('version 2')
90
wt.commit(message='commit 2')
57
b.commit(message='commit 2')
92
59
eq = self.assertEquals
94
61
rh = b.revision_history()
95
rev = b.repository.get_revision(rh[0])
62
rev = b.get_revision(rh[0])
96
63
eq(rev.message, 'add hello')
98
tree1 = b.repository.revision_tree(rh[0])
65
tree1 = b.revision_tree(rh[0])
100
66
text = tree1.get_file_text(file_id)
102
self.assertEqual('hello world', text)
67
eq(text, 'hello world')
104
tree2 = b.repository.revision_tree(rh[1])
106
text = tree2.get_file_text(file_id)
108
self.assertEqual('version 2', text)
69
tree2 = b.revision_tree(rh[1])
70
eq(tree2.get_file_text(file_id), 'version 2')
110
72
def test_delete_commit(self):
111
73
"""Test a commit with a deleted file"""
112
wt = self.make_branch_and_tree('.')
74
b = Branch.initialize('.')
114
75
file('hello', 'w').write('hello world')
115
wt.add(['hello'], ['hello-id'])
116
wt.commit(message='add hello')
76
b.add(['hello'], ['hello-id'])
77
b.commit(message='add hello')
118
79
os.remove('hello')
119
wt.commit('removed hello', rev_id='rev2')
80
b.commit('removed hello', rev_id='rev2')
121
tree = b.repository.revision_tree('rev2')
82
tree = b.revision_tree('rev2')
122
83
self.assertFalse(tree.has_id('hello-id'))
124
86
def test_pointless_commit(self):
125
87
"""Commit refuses unless there are changes or it's forced."""
126
wt = self.make_branch_and_tree('.')
88
b = Branch.initialize('.')
128
89
file('hello', 'w').write('hello')
130
wt.commit(message='add hello')
91
b.commit(message='add hello')
131
92
self.assertEquals(b.revno(), 1)
132
93
self.assertRaises(PointlessCommit,
135
96
allow_pointless=False)
136
97
self.assertEquals(b.revno(), 1)
138
101
def test_commit_empty(self):
139
102
"""Commiting an empty tree works."""
140
wt = self.make_branch_and_tree('.')
142
wt.commit(message='empty tree', allow_pointless=True)
103
b = Branch.initialize('.')
104
b.commit(message='empty tree', allow_pointless=True)
143
105
self.assertRaises(PointlessCommit,
145
107
message='empty tree',
146
108
allow_pointless=False)
147
wt.commit(message='empty tree', allow_pointless=True)
109
b.commit(message='empty tree', allow_pointless=True)
148
110
self.assertEquals(b.revno(), 2)
150
113
def test_selective_delete(self):
151
114
"""Selective commit in tree with deletions"""
152
wt = self.make_branch_and_tree('.')
115
b = Branch.initialize('.')
154
116
file('hello', 'w').write('hello')
155
117
file('buongia', 'w').write('buongia')
156
wt.add(['hello', 'buongia'],
118
b.add(['hello', 'buongia'],
157
119
['hello-id', 'buongia-id'])
158
wt.commit(message='add files',
120
b.commit(message='add files',
159
121
rev_id='test@rev-1')
161
123
os.remove('hello')
162
124
file('buongia', 'w').write('new text')
163
wt.commit(message='update text',
125
b.commit(message='update text',
164
126
specific_files=['buongia'],
165
127
allow_pointless=False,
166
128
rev_id='test@rev-2')
168
wt.commit(message='remove hello',
130
b.commit(message='remove hello',
169
131
specific_files=['hello'],
170
132
allow_pointless=False,
171
133
rev_id='test@rev-3')
208
164
ie = tree1.inventory['hello-id']
209
165
eq(ie.revision, 'test@rev-1')
211
tree2 = b.repository.revision_tree('test@rev-2')
213
self.addCleanup(tree2.unlock)
167
tree2 = b.revision_tree('test@rev-2')
214
168
eq(tree2.id2path('hello-id'), 'fruity')
215
169
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
216
170
self.check_inventory_shape(tree2.inventory, ['fruity'])
217
171
ie = tree2.inventory['hello-id']
218
172
eq(ie.revision, 'test@rev-2')
220
175
def test_reused_rev_id(self):
221
176
"""Test that a revision id cannot be reused in a branch"""
222
wt = self.make_branch_and_tree('.')
224
wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
177
b = Branch.initialize('.')
178
b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
225
179
self.assertRaises(Exception,
227
181
message='reused id',
228
182
rev_id='test@rev-1',
229
183
allow_pointless=True)
231
187
def test_commit_move(self):
232
188
"""Test commit of revisions with moved files and directories"""
233
189
eq = self.assertEquals
234
wt = self.make_branch_and_tree('.')
190
b = Branch.initialize('.')
236
191
r1 = 'test@rev-1'
237
192
self.build_tree(['hello', 'a/', 'b/'])
238
wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
239
wt.commit('initial', rev_id=r1, allow_pointless=False)
240
wt.move(['hello'], 'a')
193
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
194
b.commit('initial', rev_id=r1, allow_pointless=False)
196
b.move(['hello'], 'a')
241
197
r2 = 'test@rev-2'
242
wt.commit('two', rev_id=r2, allow_pointless=False)
245
self.check_inventory_shape(wt.read_working_inventory(),
246
['a/', 'a/hello', 'b/'])
198
b.commit('two', rev_id=r2, allow_pointless=False)
199
self.check_inventory_shape(b.working_tree().read_working_inventory(),
200
['a', 'a/hello', 'b'])
251
203
r3 = 'test@rev-3'
252
wt.commit('three', rev_id=r3, allow_pointless=False)
255
self.check_inventory_shape(wt.read_working_inventory(),
256
['a/', 'a/hello', 'a/b/'])
257
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
258
['a/', 'a/hello', 'a/b/'])
204
b.commit('three', rev_id=r3, allow_pointless=False)
205
self.check_inventory_shape(b.working_tree().read_working_inventory(),
206
['a', 'a/hello', 'a/b'])
207
self.check_inventory_shape(b.get_revision_inventory(r3),
208
['a', 'a/hello', 'a/b'])
262
wt.move(['a/hello'], 'a/b')
210
b.move([os.sep.join(['a', 'hello'])],
211
os.sep.join(['a', 'b']))
263
212
r4 = 'test@rev-4'
264
wt.commit('four', rev_id=r4, allow_pointless=False)
267
self.check_inventory_shape(wt.read_working_inventory(),
268
['a/', 'a/b/hello', 'a/b/'])
213
b.commit('four', rev_id=r4, allow_pointless=False)
214
self.check_inventory_shape(b.working_tree().read_working_inventory(),
215
['a', 'a/b/hello', 'a/b'])
272
inv = b.repository.get_revision_inventory(r4)
217
inv = b.get_revision_inventory(r4)
273
218
eq(inv['hello-id'].revision, r4)
274
219
eq(inv['a-id'].revision, r1)
275
220
eq(inv['b-id'].revision, r3)
277
223
def test_removed_commit(self):
278
224
"""Commit with a removed file"""
279
wt = self.make_branch_and_tree('.')
225
b = Branch.initialize('.')
226
wt = b.working_tree()
281
227
file('hello', 'w').write('hello world')
282
wt.add(['hello'], ['hello-id'])
283
wt.commit(message='add hello')
228
b.add(['hello'], ['hello-id'])
229
b.commit(message='add hello')
231
wt = b.working_tree() # FIXME: kludge for aliasing of working inventory
284
232
wt.remove('hello')
285
wt.commit('removed hello', rev_id='rev2')
233
b.commit('removed hello', rev_id='rev2')
287
tree = b.repository.revision_tree('rev2')
235
tree = b.revision_tree('rev2')
288
236
self.assertFalse(tree.has_id('hello-id'))
290
239
def test_committed_ancestry(self):
291
240
"""Test commit appends revisions to ancestry."""
292
wt = self.make_branch_and_tree('.')
241
b = Branch.initialize('.')
295
243
for i in range(4):
296
244
file('hello', 'w').write((str(i) * 4) + '\n')
298
wt.add(['hello'], ['hello-id'])
246
b.add(['hello'], ['hello-id'])
299
247
rev_id = 'test@rev-%d' % (i+1)
300
248
rev_ids.append(rev_id)
301
wt.commit(message='rev %d' % (i+1),
249
b.commit(message='rev %d' % (i+1),
303
251
eq = self.assertEquals
304
252
eq(b.revision_history(), rev_ids)
305
253
for i in range(4):
306
anc = b.repository.get_ancestry(rev_ids[i])
254
anc = b.get_ancestry(rev_ids[i])
307
255
eq(anc, [None] + rev_ids[:i+1])
309
257
def test_commit_new_subdir_child_selective(self):
310
wt = self.make_branch_and_tree('.')
258
b = Branch.initialize('.')
312
259
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
313
wt.add(['dir', 'dir/file1', 'dir/file2'],
260
b.add(['dir', 'dir/file1', 'dir/file2'],
314
261
['dirid', 'file1id', 'file2id'])
315
wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
316
inv = b.repository.get_inventory('1')
262
b.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
263
inv = b.get_inventory('1')
317
264
self.assertEqual('1', inv['dirid'].revision)
318
265
self.assertEqual('1', inv['file1id'].revision)
319
266
# FIXME: This should raise a KeyError I think, rbc20051006
322
269
def test_strict_commit(self):
323
270
"""Try and commit with unknown files and strict = True, should fail."""
324
271
from bzrlib.errors import StrictCommitFailed
325
wt = self.make_branch_and_tree('.')
272
b = Branch.initialize('.')
327
273
file('hello', 'w').write('hello world')
329
275
file('goodbye', 'w').write('goodbye cruel world!')
330
self.assertRaises(StrictCommitFailed, wt.commit,
276
self.assertRaises(StrictCommitFailed, b.commit,
331
277
message='add hello but not goodbye', strict=True)
333
279
def test_strict_commit_without_unknowns(self):
334
280
"""Try and commit with no unknown files and strict = True,
336
282
from bzrlib.errors import StrictCommitFailed
337
wt = self.make_branch_and_tree('.')
283
b = Branch.initialize('.')
339
284
file('hello', 'w').write('hello world')
341
wt.commit(message='add hello', strict=True)
286
b.commit(message='add hello', strict=True)
343
288
def test_nonstrict_commit(self):
344
289
"""Try and commit with unknown files and strict = False, should work."""
345
wt = self.make_branch_and_tree('.')
290
b = Branch.initialize('.')
347
291
file('hello', 'w').write('hello world')
349
293
file('goodbye', 'w').write('goodbye cruel world!')
350
wt.commit(message='add hello but not goodbye', strict=False)
294
b.commit(message='add hello but not goodbye', strict=False)
352
296
def test_nonstrict_commit_without_unknowns(self):
353
297
"""Try and commit with no unknown files and strict = False,
355
wt = self.make_branch_and_tree('.')
299
b = Branch.initialize('.')
357
300
file('hello', 'w').write('hello world')
359
wt.commit(message='add hello', strict=False)
302
b.commit(message='add hello', strict=False)
361
304
def test_signed_commit(self):
362
305
import bzrlib.gpg
363
306
import bzrlib.commit as commit
364
307
oldstrategy = bzrlib.gpg.GPGStrategy
365
wt = self.make_branch_and_tree('.')
367
wt.commit("base", allow_pointless=True, rev_id='A')
368
self.failIf(branch.repository.has_signature_for_revision_id('A'))
308
branch = Branch.initialize('.')
309
branch.commit("base", allow_pointless=True, rev_id='A')
310
self.failIf(branch.revision_store.has_id('A', 'sig'))
370
312
from bzrlib.testament import Testament
371
313
# monkey patch gpg signing mechanism
372
314
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
373
commit.Commit(config=MustSignConfig(branch)).commit(message="base",
315
commit.Commit(config=MustSignConfig(branch)).commit(branch, "base",
374
316
allow_pointless=True,
378
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
379
self.assertEqual(sign(Testament.from_revision(branch.repository,
380
'B').as_short_text()),
381
branch.repository.get_signature_text('B'))
318
self.assertEqual(Testament.from_revision(branch,'B').as_short_text(),
319
branch.revision_store.get('B', 'sig').read())
383
321
bzrlib.gpg.GPGStrategy = oldstrategy
419
354
config = BranchWithHooks(branch)
420
355
commit.Commit(config=config).commit(
422
357
allow_pointless=True,
423
rev_id='A', working_tree = wt)
424
359
self.assertEqual(['called', 'called'], calls)
428
def test_commit_object_doesnt_set_nick(self):
429
# using the Commit object directly does not set the branch nick.
430
wt = self.make_branch_and_tree('.')
432
c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
433
self.assertEquals(wt.branch.revno(), 1)
435
wt.branch.repository.get_revision(
436
wt.branch.last_revision()).properties)
438
def test_safe_master_lock(self):
440
master = BzrDirMetaFormat1().initialize('master')
441
master.create_repository()
442
master_branch = master.create_branch()
443
master.create_workingtree()
444
bound = master.sprout('bound')
445
wt = bound.open_workingtree()
446
wt.branch.set_bound_location(os.path.realpath('master'))
448
orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
449
master_branch.lock_write()
451
lockdir._DEFAULT_TIMEOUT_SECONDS = 1
452
self.assertRaises(LockContention, wt.commit, 'silly')
454
lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
455
master_branch.unlock()
457
def test_commit_bound_merge(self):
458
# see bug #43959; commit of a merge in a bound branch fails to push
459
# the new commit into the master
460
master_branch = self.make_branch('master')
461
bound_tree = self.make_branch_and_tree('bound')
462
bound_tree.branch.bind(master_branch)
464
self.build_tree_contents([('bound/content_file', 'initial contents\n')])
465
bound_tree.add(['content_file'])
466
bound_tree.commit(message='woo!')
468
other_bzrdir = master_branch.bzrdir.sprout('other')
469
other_tree = other_bzrdir.open_workingtree()
471
# do a commit to the the other branch changing the content file so
472
# that our commit after merging will have a merged revision in the
473
# content file history.
474
self.build_tree_contents([('other/content_file', 'change in other\n')])
475
other_tree.commit('change in other')
477
# do a merge into the bound branch from other, and then change the
478
# content file locally to force a new revision (rather than using the
479
# revision from other). This forces extra processing in commit.
480
bound_tree.merge_from_branch(other_tree.branch)
481
self.build_tree_contents([('bound/content_file', 'change in bound\n')])
483
# before #34959 was fixed, this failed with 'revision not present in
484
# weave' when trying to implicitly push from the bound branch to the master
485
bound_tree.commit(message='commit of merge in bound tree')
487
def test_commit_reporting_after_merge(self):
488
# when doing a commit of a merge, the reporter needs to still
489
# be called for each item that is added/removed/deleted.
490
this_tree = self.make_branch_and_tree('this')
491
# we need a bunch of files and dirs, to perform one action on each.
494
'this/dirtoreparent/',
497
'this/filetoreparent',
514
this_tree.commit('create_files')
515
other_dir = this_tree.bzrdir.sprout('other')
516
other_tree = other_dir.open_workingtree()
517
other_tree.lock_write()
518
# perform the needed actions on the files and dirs.
520
other_tree.rename_one('dirtorename', 'renameddir')
521
other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
522
other_tree.rename_one('filetorename', 'renamedfile')
523
other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
524
other_tree.remove(['dirtoremove', 'filetoremove'])
525
self.build_tree_contents([
527
('other/filetomodify', 'new content'),
528
('other/newfile', 'new file content')])
529
other_tree.add('newfile')
530
other_tree.add('newdir/')
531
other_tree.commit('modify all sample files and dirs.')
534
this_tree.merge_from_branch(other_tree.branch)
535
reporter = CapturingReporter()
536
this_tree.commit('do the commit', reporter=reporter)
538
('change', 'unchanged', ''),
539
('change', 'unchanged', 'dirtoleave'),
540
('change', 'unchanged', 'filetoleave'),
541
('change', 'modified', 'filetomodify'),
542
('change', 'added', 'newdir'),
543
('change', 'added', 'newfile'),
544
('renamed', 'renamed', 'dirtorename', 'renameddir'),
545
('renamed', 'renamed', 'filetorename', 'renamedfile'),
546
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
547
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
548
('deleted', 'dirtoremove'),
549
('deleted', 'filetoremove'),
553
def test_commit_removals_respects_filespec(self):
554
"""Commit respects the specified_files for removals."""
555
tree = self.make_branch_and_tree('.')
556
self.build_tree(['a', 'b'])
558
tree.commit('added a, b')
559
tree.remove(['a', 'b'])
560
tree.commit('removed a', specific_files='a')
561
basis = tree.basis_tree()
564
self.assertIs(None, basis.path2id('a'))
565
self.assertFalse(basis.path2id('b') is None)
569
def test_commit_saves_1ms_timestamp(self):
570
"""Passing in a timestamp is saved with 1ms resolution"""
571
tree = self.make_branch_and_tree('.')
572
self.build_tree(['a'])
574
tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
577
rev = tree.branch.repository.get_revision('a1')
578
self.assertEqual(1153248633.419, rev.timestamp)
580
def test_commit_has_1ms_resolution(self):
581
"""Allowing commit to generate the timestamp also has 1ms resolution"""
582
tree = self.make_branch_and_tree('.')
583
self.build_tree(['a'])
585
tree.commit('added a', rev_id='a1')
587
rev = tree.branch.repository.get_revision('a1')
588
timestamp = rev.timestamp
589
timestamp_1ms = round(timestamp, 3)
590
self.assertEqual(timestamp_1ms, timestamp)
592
def assertBasisTreeKind(self, kind, tree, file_id):
593
basis = tree.basis_tree()
596
self.assertEqual(kind, basis.kind(file_id))
600
def test_commit_kind_changes(self):
601
self.requireFeature(SymlinkFeature)
602
tree = self.make_branch_and_tree('.')
603
os.symlink('target', 'name')
604
tree.add('name', 'a-file-id')
605
tree.commit('Added a symlink')
606
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
609
self.build_tree(['name'])
610
tree.commit('Changed symlink to file')
611
self.assertBasisTreeKind('file', tree, 'a-file-id')
614
os.symlink('target', 'name')
615
tree.commit('file to symlink')
616
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
620
tree.commit('symlink to directory')
621
self.assertBasisTreeKind('directory', tree, 'a-file-id')
624
os.symlink('target', 'name')
625
tree.commit('directory to symlink')
626
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
628
# prepare for directory <-> file tests
631
tree.commit('symlink to directory')
632
self.assertBasisTreeKind('directory', tree, 'a-file-id')
635
self.build_tree(['name'])
636
tree.commit('Changed directory to file')
637
self.assertBasisTreeKind('file', tree, 'a-file-id')
641
tree.commit('file to directory')
642
self.assertBasisTreeKind('directory', tree, 'a-file-id')
644
def test_commit_unversioned_specified(self):
645
"""Commit should raise if specified files isn't in basis or worktree"""
646
tree = self.make_branch_and_tree('.')
647
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
648
'message', specific_files=['bogus'])
650
class Callback(object):
652
def __init__(self, message, testcase):
654
self.message = message
655
self.testcase = testcase
657
def __call__(self, commit_obj):
659
self.testcase.assertTrue(isinstance(commit_obj, Commit))
662
def test_commit_callback(self):
663
"""Commit should invoke a callback to get the message"""
665
tree = self.make_branch_and_tree('.')
669
self.assertTrue(isinstance(e, BzrError))
670
self.assertEqual('The message or message_callback keyword'
671
' parameter is required for commit().', str(e))
673
self.fail('exception not raised')
674
cb = self.Callback(u'commit 1', self)
675
tree.commit(message_callback=cb)
676
self.assertTrue(cb.called)
677
repository = tree.branch.repository
678
message = repository.get_revision(tree.last_revision()).message
679
self.assertEqual('commit 1', message)
681
def test_no_callback_pointless(self):
682
"""Callback should not be invoked for pointless commit"""
683
tree = self.make_branch_and_tree('.')
684
cb = self.Callback(u'commit 2', self)
685
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
686
allow_pointless=False)
687
self.assertFalse(cb.called)
689
def test_no_callback_netfailure(self):
690
"""Callback should not be invoked if connectivity fails"""
691
tree = self.make_branch_and_tree('.')
692
cb = self.Callback(u'commit 2', self)
693
repository = tree.branch.repository
694
# simulate network failure
695
def raise_(self, arg, arg2):
696
raise errors.NoSuchFile('foo')
697
repository.add_inventory = raise_
698
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
699
self.assertFalse(cb.called)
701
def test_selected_file_merge_commit(self):
702
"""Ensure the correct error is raised"""
703
tree = self.make_branch_and_tree('foo')
704
# pending merge would turn into a left parent
705
tree.commit('commit 1')
706
tree.add_parent_tree_id('example')
707
self.build_tree(['foo/bar', 'foo/baz'])
708
tree.add(['bar', 'baz'])
709
err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
710
tree.commit, 'commit 2', specific_files=['bar', 'baz'])
711
self.assertEqual(['bar', 'baz'], err.files)
712
self.assertEqual('Selected-file commit of merges is not supported'
713
' yet: files bar, baz', str(err))
715
def test_commit_ordering(self):
716
"""Test of corner-case commit ordering error"""
717
tree = self.make_branch_and_tree('.')
718
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
719
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
721
self.build_tree(['a/c/d/'])
723
tree.rename_one('a/z/x', 'a/c/d/x')
724
tree.commit('test', specific_files=['a/z/y'])
726
def test_commit_no_author(self):
727
"""The default kwarg author in MutableTree.commit should not add
728
the 'author' revision property.
730
tree = self.make_branch_and_tree('foo')
731
rev_id = tree.commit('commit 1')
732
rev = tree.branch.repository.get_revision(rev_id)
733
self.assertFalse('author' in rev.properties)
735
def test_commit_author(self):
736
"""Passing a non-empty author kwarg to MutableTree.commit should add
737
the 'author' revision property.
739
tree = self.make_branch_and_tree('foo')
740
rev_id = tree.commit('commit 1', author='John Doe <jdoe@example.com>')
741
rev = tree.branch.repository.get_revision(rev_id)
742
self.assertEqual('John Doe <jdoe@example.com>',
743
rev.properties['author'])
745
def test_commit_with_checkout_and_branch_sharing_repo(self):
746
repo = self.make_repository('repo', shared=True)
747
# make_branch_and_tree ignores shared repos
748
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
749
tree2 = branch.create_checkout('repo/tree2')
750
tree2.commit('message', rev_id='rev1')
751
self.assertTrue(tree2.branch.repository.has_revision('rev1'))