20
from bzrlib.selftest import TestCaseInTempDir
21
28
from bzrlib.branch import Branch
22
from bzrlib.commit import Commit
23
from bzrlib.errors import PointlessCommit, BzrError
29
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
30
from bzrlib.commit import Commit, NullCommitReporter
31
from bzrlib.config import BranchConfig
32
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
34
from bzrlib.tests import SymlinkFeature, TestCaseWithTransport
35
from bzrlib.workingtree import WorkingTree
26
38
# TODO: Test commit with some added, and added-but-missing files
28
class TestCommit(TestCaseInTempDir):
40
class MustSignConfig(BranchConfig):
42
def signature_needed(self):
45
def gpg_signing_command(self):
49
class BranchWithHooks(BranchConfig):
51
def post_commit(self):
52
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):
30
80
def test_simple_commit(self):
31
81
"""Commit and check two versions of a single file."""
32
b = Branch.initialize('.')
82
wt = self.make_branch_and_tree('.')
33
84
file('hello', 'w').write('hello world')
35
b.commit(message='add hello')
36
file_id = b.working_tree().path2id('hello')
86
wt.commit(message='add hello')
87
file_id = wt.path2id('hello')
38
89
file('hello', 'w').write('version 2')
39
b.commit(message='commit 2')
90
wt.commit(message='commit 2')
41
92
eq = self.assertEquals
43
94
rh = b.revision_history()
44
rev = b.get_revision(rh[0])
95
rev = b.repository.get_revision(rh[0])
45
96
eq(rev.message, 'add hello')
47
tree1 = b.revision_tree(rh[0])
98
tree1 = b.repository.revision_tree(rh[0])
48
100
text = tree1.get_file_text(file_id)
49
eq(text, 'hello world')
51
tree2 = b.revision_tree(rh[1])
52
eq(tree2.get_file_text(file_id), 'version 2')
102
self.assertEqual('hello world', text)
104
tree2 = b.repository.revision_tree(rh[1])
106
text = tree2.get_file_text(file_id)
108
self.assertEqual('version 2', text)
55
110
def test_delete_commit(self):
56
111
"""Test a commit with a deleted file"""
57
b = Branch.initialize('.')
112
wt = self.make_branch_and_tree('.')
58
114
file('hello', 'w').write('hello world')
59
b.add(['hello'], ['hello-id'])
60
b.commit(message='add hello')
115
wt.add(['hello'], ['hello-id'])
116
wt.commit(message='add hello')
62
118
os.remove('hello')
63
b.commit('removed hello', rev_id='rev2')
119
wt.commit('removed hello', rev_id='rev2')
65
tree = b.revision_tree('rev2')
121
tree = b.repository.revision_tree('rev2')
66
122
self.assertFalse(tree.has_id('hello-id'))
69
124
def test_pointless_commit(self):
70
125
"""Commit refuses unless there are changes or it's forced."""
71
b = Branch.initialize('.')
126
wt = self.make_branch_and_tree('.')
72
128
file('hello', 'w').write('hello')
74
b.commit(message='add hello')
130
wt.commit(message='add hello')
75
131
self.assertEquals(b.revno(), 1)
76
132
self.assertRaises(PointlessCommit,
79
135
allow_pointless=False)
80
136
self.assertEquals(b.revno(), 1)
84
138
def test_commit_empty(self):
85
139
"""Commiting an empty tree works."""
86
b = Branch.initialize('.')
87
b.commit(message='empty tree', allow_pointless=True)
140
wt = self.make_branch_and_tree('.')
142
wt.commit(message='empty tree', allow_pointless=True)
88
143
self.assertRaises(PointlessCommit,
90
145
message='empty tree',
91
146
allow_pointless=False)
92
b.commit(message='empty tree', allow_pointless=True)
147
wt.commit(message='empty tree', allow_pointless=True)
93
148
self.assertEquals(b.revno(), 2)
96
150
def test_selective_delete(self):
97
151
"""Selective commit in tree with deletions"""
98
b = Branch.initialize('.')
152
wt = self.make_branch_and_tree('.')
99
154
file('hello', 'w').write('hello')
100
155
file('buongia', 'w').write('buongia')
101
b.add(['hello', 'buongia'],
156
wt.add(['hello', 'buongia'],
102
157
['hello-id', 'buongia-id'])
103
b.commit(message='add files',
158
wt.commit(message='add files',
104
159
rev_id='test@rev-1')
106
161
os.remove('hello')
107
162
file('buongia', 'w').write('new text')
108
b.commit(message='update text',
163
wt.commit(message='update text',
109
164
specific_files=['buongia'],
110
165
allow_pointless=False,
111
166
rev_id='test@rev-2')
113
b.commit(message='remove hello',
168
wt.commit(message='remove hello',
114
169
specific_files=['hello'],
115
170
allow_pointless=False,
116
171
rev_id='test@rev-3')
147
208
ie = tree1.inventory['hello-id']
148
209
eq(ie.revision, 'test@rev-1')
150
tree2 = b.revision_tree('test@rev-2')
211
tree2 = b.repository.revision_tree('test@rev-2')
213
self.addCleanup(tree2.unlock)
151
214
eq(tree2.id2path('hello-id'), 'fruity')
152
215
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
153
216
self.check_inventory_shape(tree2.inventory, ['fruity'])
154
217
ie = tree2.inventory['hello-id']
155
218
eq(ie.revision, 'test@rev-2')
158
220
def test_reused_rev_id(self):
159
221
"""Test that a revision id cannot be reused in a branch"""
160
b = Branch.initialize('.')
161
b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
222
wt = self.make_branch_and_tree('.')
224
wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
162
225
self.assertRaises(Exception,
164
227
message='reused id',
165
228
rev_id='test@rev-1',
166
229
allow_pointless=True)
170
231
def test_commit_move(self):
171
232
"""Test commit of revisions with moved files and directories"""
172
233
eq = self.assertEquals
173
b = Branch.initialize('.')
234
wt = self.make_branch_and_tree('.')
174
236
r1 = 'test@rev-1'
175
237
self.build_tree(['hello', 'a/', 'b/'])
176
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
177
b.commit('initial', rev_id=r1, allow_pointless=False)
179
b.move(['hello'], 'a')
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')
180
241
r2 = 'test@rev-2'
181
b.commit('two', rev_id=r2, allow_pointless=False)
182
self.check_inventory_shape(b.inventory,
183
['a', 'a/hello', 'b'])
242
wt.commit('two', rev_id=r2, allow_pointless=False)
245
self.check_inventory_shape(wt.read_working_inventory(),
246
['a/', 'a/hello', 'b/'])
186
251
r3 = 'test@rev-3'
187
b.commit('three', rev_id=r3, allow_pointless=False)
188
self.check_inventory_shape(b.inventory,
189
['a', 'a/hello', 'a/b'])
190
self.check_inventory_shape(b.get_revision_inventory(r3),
191
['a', 'a/hello', 'a/b'])
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/'])
193
b.move([os.sep.join(['a', 'hello'])],
194
os.sep.join(['a', 'b']))
262
wt.move(['a/hello'], 'a/b')
195
263
r4 = 'test@rev-4'
196
b.commit('four', rev_id=r4, allow_pointless=False)
197
self.check_inventory_shape(b.inventory,
198
['a', 'a/b/hello', 'a/b'])
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/'])
200
inv = b.get_revision_inventory(r4)
272
inv = b.repository.get_revision_inventory(r4)
201
273
eq(inv['hello-id'].revision, r4)
202
274
eq(inv['a-id'].revision, r1)
203
275
eq(inv['b-id'].revision, r3)
206
277
def test_removed_commit(self):
207
"""Test a commit with a removed file"""
208
b = Branch.initialize('.')
278
"""Commit with a removed file"""
279
wt = self.make_branch_and_tree('.')
209
281
file('hello', 'w').write('hello world')
210
b.add(['hello'], ['hello-id'])
211
b.commit(message='add hello')
214
b.commit('removed hello', rev_id='rev2')
216
tree = b.revision_tree('rev2')
282
wt.add(['hello'], ['hello-id'])
283
wt.commit(message='add hello')
285
wt.commit('removed hello', rev_id='rev2')
287
tree = b.repository.revision_tree('rev2')
217
288
self.assertFalse(tree.has_id('hello-id'))
220
290
def test_committed_ancestry(self):
221
291
"""Test commit appends revisions to ancestry."""
222
b = Branch.initialize('.')
292
wt = self.make_branch_and_tree('.')
224
295
for i in range(4):
225
296
file('hello', 'w').write((str(i) * 4) + '\n')
227
b.add(['hello'], ['hello-id'])
298
wt.add(['hello'], ['hello-id'])
228
299
rev_id = 'test@rev-%d' % (i+1)
229
300
rev_ids.append(rev_id)
230
b.commit(message='rev %d' % (i+1),
301
wt.commit(message='rev %d' % (i+1),
232
303
eq = self.assertEquals
233
304
eq(b.revision_history(), rev_ids)
234
305
for i in range(4):
235
anc = b.get_ancestry(rev_ids[i])
306
anc = b.repository.get_ancestry(rev_ids[i])
236
307
eq(anc, [None] + rev_ids[:i+1])
309
def test_commit_new_subdir_child_selective(self):
310
wt = self.make_branch_and_tree('.')
312
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
313
wt.add(['dir', 'dir/file1', 'dir/file2'],
314
['dirid', 'file1id', 'file2id'])
315
wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
316
inv = b.repository.get_inventory('1')
317
self.assertEqual('1', inv['dirid'].revision)
318
self.assertEqual('1', inv['file1id'].revision)
319
# FIXME: This should raise a KeyError I think, rbc20051006
320
self.assertRaises(BzrError, inv.__getitem__, 'file2id')
322
def test_strict_commit(self):
323
"""Try and commit with unknown files and strict = True, should fail."""
324
from bzrlib.errors import StrictCommitFailed
325
wt = self.make_branch_and_tree('.')
327
file('hello', 'w').write('hello world')
329
file('goodbye', 'w').write('goodbye cruel world!')
330
self.assertRaises(StrictCommitFailed, wt.commit,
331
message='add hello but not goodbye', strict=True)
333
def test_strict_commit_without_unknowns(self):
334
"""Try and commit with no unknown files and strict = True,
336
from bzrlib.errors import StrictCommitFailed
337
wt = self.make_branch_and_tree('.')
339
file('hello', 'w').write('hello world')
341
wt.commit(message='add hello', strict=True)
343
def test_nonstrict_commit(self):
344
"""Try and commit with unknown files and strict = False, should work."""
345
wt = self.make_branch_and_tree('.')
347
file('hello', 'w').write('hello world')
349
file('goodbye', 'w').write('goodbye cruel world!')
350
wt.commit(message='add hello but not goodbye', strict=False)
352
def test_nonstrict_commit_without_unknowns(self):
353
"""Try and commit with no unknown files and strict = False,
355
wt = self.make_branch_and_tree('.')
357
file('hello', 'w').write('hello world')
359
wt.commit(message='add hello', strict=False)
361
def test_signed_commit(self):
363
import bzrlib.commit as commit
364
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'))
370
from bzrlib.testament import Testament
371
# monkey patch gpg signing mechanism
372
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
373
commit.Commit(config=MustSignConfig(branch)).commit(message="base",
374
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'))
383
bzrlib.gpg.GPGStrategy = oldstrategy
385
def test_commit_failed_signature(self):
387
import bzrlib.commit as commit
388
oldstrategy = bzrlib.gpg.GPGStrategy
389
wt = self.make_branch_and_tree('.')
391
wt.commit("base", allow_pointless=True, rev_id='A')
392
self.failIf(branch.repository.has_signature_for_revision_id('A'))
394
from bzrlib.testament import Testament
395
# monkey patch gpg signing mechanism
396
bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
397
config = MustSignConfig(branch)
398
self.assertRaises(SigningFailed,
399
commit.Commit(config=config).commit,
401
allow_pointless=True,
404
branch = Branch.open(self.get_url('.'))
405
self.assertEqual(branch.revision_history(), ['A'])
406
self.failIf(branch.repository.has_revision('B'))
408
bzrlib.gpg.GPGStrategy = oldstrategy
410
def test_commit_invokes_hooks(self):
411
import bzrlib.commit as commit
412
wt = self.make_branch_and_tree('.')
415
def called(branch, rev_id):
416
calls.append('called')
417
bzrlib.ahook = called
419
config = BranchWithHooks(branch)
420
commit.Commit(config=config).commit(
422
allow_pointless=True,
423
rev_id='A', working_tree = wt)
424
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'))
447
master_branch.lock_write()
449
self.assertRaises(LockContention, wt.commit, 'silly')
451
master_branch.unlock()
453
def test_commit_bound_merge(self):
454
# see bug #43959; commit of a merge in a bound branch fails to push
455
# the new commit into the master
456
master_branch = self.make_branch('master')
457
bound_tree = self.make_branch_and_tree('bound')
458
bound_tree.branch.bind(master_branch)
460
self.build_tree_contents([('bound/content_file', 'initial contents\n')])
461
bound_tree.add(['content_file'])
462
bound_tree.commit(message='woo!')
464
other_bzrdir = master_branch.bzrdir.sprout('other')
465
other_tree = other_bzrdir.open_workingtree()
467
# do a commit to the the other branch changing the content file so
468
# that our commit after merging will have a merged revision in the
469
# content file history.
470
self.build_tree_contents([('other/content_file', 'change in other\n')])
471
other_tree.commit('change in other')
473
# do a merge into the bound branch from other, and then change the
474
# content file locally to force a new revision (rather than using the
475
# revision from other). This forces extra processing in commit.
476
bound_tree.merge_from_branch(other_tree.branch)
477
self.build_tree_contents([('bound/content_file', 'change in bound\n')])
479
# before #34959 was fixed, this failed with 'revision not present in
480
# weave' when trying to implicitly push from the bound branch to the master
481
bound_tree.commit(message='commit of merge in bound tree')
483
def test_commit_reporting_after_merge(self):
484
# when doing a commit of a merge, the reporter needs to still
485
# be called for each item that is added/removed/deleted.
486
this_tree = self.make_branch_and_tree('this')
487
# we need a bunch of files and dirs, to perform one action on each.
490
'this/dirtoreparent/',
493
'this/filetoreparent',
510
this_tree.commit('create_files')
511
other_dir = this_tree.bzrdir.sprout('other')
512
other_tree = other_dir.open_workingtree()
513
other_tree.lock_write()
514
# perform the needed actions on the files and dirs.
516
other_tree.rename_one('dirtorename', 'renameddir')
517
other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
518
other_tree.rename_one('filetorename', 'renamedfile')
519
other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
520
other_tree.remove(['dirtoremove', 'filetoremove'])
521
self.build_tree_contents([
523
('other/filetomodify', 'new content'),
524
('other/newfile', 'new file content')])
525
other_tree.add('newfile')
526
other_tree.add('newdir/')
527
other_tree.commit('modify all sample files and dirs.')
530
this_tree.merge_from_branch(other_tree.branch)
531
reporter = CapturingReporter()
532
this_tree.commit('do the commit', reporter=reporter)
534
('change', 'unchanged', ''),
535
('change', 'unchanged', 'dirtoleave'),
536
('change', 'unchanged', 'filetoleave'),
537
('change', 'modified', 'filetomodify'),
538
('change', 'added', 'newdir'),
539
('change', 'added', 'newfile'),
540
('renamed', 'renamed', 'dirtorename', 'renameddir'),
541
('renamed', 'renamed', 'filetorename', 'renamedfile'),
542
('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
543
('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
544
('deleted', 'dirtoremove'),
545
('deleted', 'filetoremove'),
549
def test_commit_removals_respects_filespec(self):
550
"""Commit respects the specified_files for removals."""
551
tree = self.make_branch_and_tree('.')
552
self.build_tree(['a', 'b'])
554
tree.commit('added a, b')
555
tree.remove(['a', 'b'])
556
tree.commit('removed a', specific_files='a')
557
basis = tree.basis_tree()
560
self.assertIs(None, basis.path2id('a'))
561
self.assertFalse(basis.path2id('b') is None)
565
def test_commit_saves_1ms_timestamp(self):
566
"""Passing in a timestamp is saved with 1ms resolution"""
567
tree = self.make_branch_and_tree('.')
568
self.build_tree(['a'])
570
tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
573
rev = tree.branch.repository.get_revision('a1')
574
self.assertEqual(1153248633.419, rev.timestamp)
576
def test_commit_has_1ms_resolution(self):
577
"""Allowing commit to generate the timestamp also has 1ms resolution"""
578
tree = self.make_branch_and_tree('.')
579
self.build_tree(['a'])
581
tree.commit('added a', rev_id='a1')
583
rev = tree.branch.repository.get_revision('a1')
584
timestamp = rev.timestamp
585
timestamp_1ms = round(timestamp, 3)
586
self.assertEqual(timestamp_1ms, timestamp)
588
def assertBasisTreeKind(self, kind, tree, file_id):
589
basis = tree.basis_tree()
592
self.assertEqual(kind, basis.kind(file_id))
596
def test_commit_kind_changes(self):
597
self.requireFeature(SymlinkFeature)
598
tree = self.make_branch_and_tree('.')
599
os.symlink('target', 'name')
600
tree.add('name', 'a-file-id')
601
tree.commit('Added a symlink')
602
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
605
self.build_tree(['name'])
606
tree.commit('Changed symlink to file')
607
self.assertBasisTreeKind('file', tree, 'a-file-id')
610
os.symlink('target', 'name')
611
tree.commit('file to symlink')
612
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
616
tree.commit('symlink to directory')
617
self.assertBasisTreeKind('directory', tree, 'a-file-id')
620
os.symlink('target', 'name')
621
tree.commit('directory to symlink')
622
self.assertBasisTreeKind('symlink', tree, 'a-file-id')
624
# prepare for directory <-> file tests
627
tree.commit('symlink to directory')
628
self.assertBasisTreeKind('directory', tree, 'a-file-id')
631
self.build_tree(['name'])
632
tree.commit('Changed directory to file')
633
self.assertBasisTreeKind('file', tree, 'a-file-id')
637
tree.commit('file to directory')
638
self.assertBasisTreeKind('directory', tree, 'a-file-id')
640
def test_commit_unversioned_specified(self):
641
"""Commit should raise if specified files isn't in basis or worktree"""
642
tree = self.make_branch_and_tree('.')
643
self.assertRaises(errors.PathsNotVersionedError, tree.commit,
644
'message', specific_files=['bogus'])
646
class Callback(object):
648
def __init__(self, message, testcase):
650
self.message = message
651
self.testcase = testcase
653
def __call__(self, commit_obj):
655
self.testcase.assertTrue(isinstance(commit_obj, Commit))
658
def test_commit_callback(self):
659
"""Commit should invoke a callback to get the message"""
661
tree = self.make_branch_and_tree('.')
665
self.assertTrue(isinstance(e, BzrError))
666
self.assertEqual('The message or message_callback keyword'
667
' parameter is required for commit().', str(e))
669
self.fail('exception not raised')
670
cb = self.Callback(u'commit 1', self)
671
tree.commit(message_callback=cb)
672
self.assertTrue(cb.called)
673
repository = tree.branch.repository
674
message = repository.get_revision(tree.last_revision()).message
675
self.assertEqual('commit 1', message)
677
def test_no_callback_pointless(self):
678
"""Callback should not be invoked for pointless commit"""
679
tree = self.make_branch_and_tree('.')
680
cb = self.Callback(u'commit 2', self)
681
self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
682
allow_pointless=False)
683
self.assertFalse(cb.called)
685
def test_no_callback_netfailure(self):
686
"""Callback should not be invoked if connectivity fails"""
687
tree = self.make_branch_and_tree('.')
688
cb = self.Callback(u'commit 2', self)
689
repository = tree.branch.repository
690
# simulate network failure
691
def raise_(self, arg, arg2):
692
raise errors.NoSuchFile('foo')
693
repository.add_inventory = raise_
694
self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
695
self.assertFalse(cb.called)
697
def test_selected_file_merge_commit(self):
698
"""Ensure the correct error is raised"""
699
tree = self.make_branch_and_tree('foo')
700
# pending merge would turn into a left parent
701
tree.commit('commit 1')
702
tree.add_parent_tree_id('example')
703
self.build_tree(['foo/bar', 'foo/baz'])
704
tree.add(['bar', 'baz'])
705
err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
706
tree.commit, 'commit 2', specific_files=['bar', 'baz'])
707
self.assertEqual(['bar', 'baz'], err.files)
708
self.assertEqual('Selected-file commit of merges is not supported'
709
' yet: files bar, baz', str(err))
711
def test_commit_ordering(self):
712
"""Test of corner-case commit ordering error"""
713
tree = self.make_branch_and_tree('.')
714
self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
715
tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
717
self.build_tree(['a/c/d/'])
719
tree.rename_one('a/z/x', 'a/c/d/x')
720
tree.commit('test', specific_files=['a/z/y'])
722
def test_commit_no_author(self):
723
"""The default kwarg author in MutableTree.commit should not add
724
the 'author' revision property.
726
tree = self.make_branch_and_tree('foo')
727
rev_id = tree.commit('commit 1')
728
rev = tree.branch.repository.get_revision(rev_id)
729
self.assertFalse('author' in rev.properties)
731
def test_commit_author(self):
732
"""Passing a non-empty author kwarg to MutableTree.commit should add
733
the 'author' revision property.
735
tree = self.make_branch_and_tree('foo')
736
rev_id = tree.commit('commit 1', author='John Doe <jdoe@example.com>')
737
rev = tree.branch.repository.get_revision(rev_id)
738
self.assertEqual('John Doe <jdoe@example.com>',
739
rev.properties['author'])
741
def test_commit_with_checkout_and_branch_sharing_repo(self):
742
repo = self.make_repository('repo', shared=True)
743
# make_branch_and_tree ignores shared repos
744
branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
745
tree2 = branch.create_checkout('repo/tree2')
746
tree2.commit('message', rev_id='rev1')
747
self.assertTrue(tree2.branch.repository.has_revision('rev1'))