18
18
"""Tests for the commit CLI of bzr."""
25
from testtools.matchers import DocTestMatches
33
from ...controldir import ControlDir
34
from ...sixish import PY3
39
from .. import TestCaseWithTransport
40
from ..matchers import ContainsNoVfsCalls
41
from ..test_bedding import override_whoami
44
class TestCommit(TestCaseWithTransport):
31
from bzrlib.bzrdir import BzrDir
32
from bzrlib.tests import (
36
from bzrlib.tests.blackbox import ExternalBase
39
class TestCommit(ExternalBase):
46
41
def test_05_empty_commit(self):
47
42
"""Commit of tree with no versioned files should fail"""
48
43
# If forced, it should succeed, but this is not tested here.
49
44
self.make_branch_and_tree('.')
50
45
self.build_tree(['hello.txt'])
51
out, err = self.run_bzr('commit -m empty', retcode=3)
46
out,err = self.run_bzr('commit -m empty', retcode=3)
52
47
self.assertEqual('', out)
54
# 1) We really don't want 'aborting commit write group' anymore.
55
# 2) brz: ERROR: is a really long line, so we wrap it with '\'
60
brz: ERROR: No changes to commit.\
61
Please 'brz add' the files you want to commit,\
62
or use --unchanged to force an empty commit.
63
""", flags=doctest.ELLIPSIS | doctest.REPORT_UDIFF))
48
self.assertContainsRe(err, 'bzr: ERROR: No changes to commit\.'
49
' Use --unchanged to commit anyhow.\n')
65
51
def test_commit_success(self):
66
52
"""Successful commit should not leave behind a bzr-commit-* file"""
72
58
self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
73
59
self.assertEqual('', self.run_bzr('unknowns')[0])
75
def test_commit_lossy_native(self):
76
"""A --lossy option to commit is supported."""
77
self.make_branch_and_tree('.')
78
self.run_bzr('commit --lossy --unchanged -m message')
79
self.assertEqual('', self.run_bzr('unknowns')[0])
81
def test_commit_lossy_foreign(self):
82
test_foreign.register_dummy_foreign_for_test(self)
83
self.make_branch_and_tree('.',
84
format=test_foreign.DummyForeignVcsDirFormat())
85
self.run_bzr('commit --lossy --unchanged -m message')
86
output = self.run_bzr('revision-info')[0]
87
self.assertTrue(output.startswith('1 dummy-'))
89
61
def test_commit_with_path(self):
90
62
"""Commit tree with path of root specified"""
91
63
a_tree = self.make_branch_and_tree('a')
93
65
a_tree.add('a_file')
94
66
self.run_bzr(['commit', '-m', 'first commit', 'a'])
96
b_tree = a_tree.controldir.sprout('b').open_workingtree()
97
self.build_tree_contents([('b/a_file', b'changes in b')])
68
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
69
self.build_tree_contents([('b/a_file', 'changes in b')])
98
70
self.run_bzr(['commit', '-m', 'first commit in b', 'b'])
100
self.build_tree_contents([('a/a_file', b'new contents')])
72
self.build_tree_contents([('a/a_file', 'new contents')])
101
73
self.run_bzr(['commit', '-m', 'change in a', 'a'])
103
75
b_tree.merge_from_branch(a_tree.branch)
128
101
def test_verbose_commit_modified(self):
129
102
# Verbose commit of modified file should say so
130
103
wt = self.prepare_simple_history()
131
self.build_tree_contents([('hello.txt', b'new contents')])
104
self.build_tree_contents([('hello.txt', 'new contents')])
132
105
out, err = self.run_bzr('commit -m modified')
133
106
self.assertEqual('', out)
134
107
self.assertContainsRe(err, '^Committing to: .*\n'
135
'modified hello\\.txt\n'
136
'Committed revision 2\\.\n$')
108
'modified hello\.txt\n'
109
'Committed revision 2\.\n$')
138
111
def test_unicode_commit_message_is_filename(self):
139
112
"""Unicode commit message same as a filename (Bug #563646).
141
self.requireFeature(features.UnicodeFilenameFeature)
142
114
file_name = u'\N{euro sign}'
143
115
self.run_bzr(['init'])
144
with open(file_name, 'w') as f:
145
f.write('hello world')
116
open(file_name, 'w').write('hello world')
146
117
self.run_bzr(['add'])
147
118
out, err = self.run_bzr(['commit', '-m', file_name])
148
reflags = re.MULTILINE | re.DOTALL | re.UNICODE
119
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
149
120
te = osutils.get_terminal_encoding()
150
self.assertContainsRe(err if PY3 else err.decode(te),
151
u'The commit message is a file name:',
121
self.assertContainsRe(err.decode(te),
122
u'The commit message is a file name:',
154
125
# Run same test with a filename that causes encode
155
126
# error for the terminal encoding. We do this
158
129
# by ui.text.show_warning
159
130
default_get_terminal_enc = osutils.get_terminal_encoding
161
osutils.get_terminal_encoding = lambda trace=None: 'ascii'
132
osutils.get_terminal_encoding = lambda: 'ascii'
162
133
file_name = u'foo\u1234'
163
with open(file_name, 'w') as f:
164
f.write('hello world')
134
open(file_name, 'w').write('hello world')
165
135
self.run_bzr(['add'])
166
136
out, err = self.run_bzr(['commit', '-m', file_name])
167
reflags = re.MULTILINE | re.DOTALL | re.UNICODE
137
reflags = re.MULTILINE|re.DOTALL|re.UNICODE
168
138
te = osutils.get_terminal_encoding()
169
self.assertContainsRe(err if PY3 else err.decode(te, 'replace'),
170
u'The commit message is a file name:',
139
self.assertContainsRe(err.decode(te, 'replace'),
140
u'The commit message is a file name:',
173
143
osutils.get_terminal_encoding = default_get_terminal_enc
175
def test_non_ascii_file_unversioned_utf8(self):
176
self.requireFeature(features.UnicodeFilenameFeature)
177
tree = self.make_branch_and_tree(".")
178
self.build_tree(["f"])
180
out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
181
encoding="utf-8", retcode=3)
182
self.assertContainsRe(err, b"(?m)not versioned: \"\xc2\xa7\"$")
184
def test_non_ascii_file_unversioned_iso_8859_5(self):
185
self.requireFeature(features.UnicodeFilenameFeature)
186
tree = self.make_branch_and_tree(".")
187
self.build_tree(["f"])
189
out, err = self.run_bzr_raw(["commit", "-m", "Wrong filename", u"\xa7"],
190
encoding="iso-8859-5", retcode=3)
192
self.expectFailure("Error messages are always written as UTF-8",
193
self.assertNotContainsString, err, b"\xc2\xa7")
195
self.assertNotContainsString(err, b"\xc2\xa7")
196
self.assertContainsRe(err, b"(?m)not versioned: \"\xfd\"$")
198
145
def test_warn_about_forgotten_commit_message(self):
199
146
"""Test that the lack of -m parameter is caught"""
200
147
wt = self.make_branch_and_tree('.')
221
168
wt.rename_one('hello.txt', 'subdir/hello.txt')
222
169
out, err = self.run_bzr('commit -m renamed')
223
170
self.assertEqual('', out)
171
self.assertEqual(set([
225
172
'Committing to: %s/' % osutils.getcwd(),
227
174
'renamed hello.txt => subdir/hello.txt',
228
175
'Committed revision 2.',
230
}, set(err.split('\n')))
177
]), set(err.split('\n')))
232
179
def test_verbose_commit_with_unknown(self):
233
180
"""Unknown files should not be listed by default in verbose output"""
234
181
# Is that really the best policy?
235
wt = ControlDir.create_standalone_workingtree('.')
182
wt = BzrDir.create_standalone_workingtree('.')
236
183
self.build_tree(['hello.txt', 'extra.txt'])
237
184
wt.add(['hello.txt'])
238
out, err = self.run_bzr('commit -m added')
185
out,err = self.run_bzr('commit -m added')
239
186
self.assertEqual('', out)
240
187
self.assertContainsRe(err, '^Committing to: .*\n'
241
'added hello\\.txt\n'
242
'Committed revision 1\\.\n$')
189
'Committed revision 1\.\n$')
244
191
def test_verbose_commit_with_unchanged(self):
245
192
"""Unchanged files should not be listed by default in verbose output"""
326
274
other_tree.remove(['dirtoremove', 'filetoremove'])
327
275
self.build_tree_contents([
328
276
('other/newdir/',),
329
('other/filetomodify', b'new content'),
330
('other/newfile', b'new file content')])
277
('other/filetomodify', 'new content'),
278
('other/newfile', 'new file content')])
331
279
other_tree.add('newfile')
332
280
other_tree.add('newdir/')
333
281
other_tree.commit('modify all sample files and dirs.')
334
284
this_tree.merge_from_branch(other_tree.branch)
335
out, err = self.run_bzr('commit -m added', working_dir='this')
286
out,err = self.run_bzr('commit -m added')
336
287
self.assertEqual('', out)
338
'Committing to: %s/' % osutils.pathjoin(osutils.getcwd(), 'this'),
288
self.assertEqual(set([
289
'Committing to: %s/' % osutils.getcwd(),
339
290
'modified filetomodify',
347
298
'deleted filetoremove',
348
299
'Committed revision 2.',
350
}, set(err.split('\n')))
301
]), set(err.split('\n')))
352
303
def test_empty_commit_message(self):
353
304
tree = self.make_branch_and_tree('.')
354
self.build_tree_contents([('foo.c', b'int main() {}')])
356
self.run_bzr('commit -m ""')
305
self.build_tree_contents([('foo.c', 'int main() {}')])
307
self.run_bzr('commit -m ""', retcode=3)
309
def test_unsupported_encoding_commit_message(self):
310
if sys.platform == 'win32':
311
raise tests.TestNotApplicable('Win32 parses arguments directly'
312
' as Unicode, so we can\'t pass invalid non-ascii')
313
tree = self.make_branch_and_tree('.')
314
self.build_tree_contents([('foo.c', 'int main() {}')])
316
# LANG env variable has no effect on Windows
317
# but some characters anyway cannot be represented
318
# in default user encoding
319
char = probe_bad_non_ascii(osutils.get_user_encoding())
321
raise TestSkipped('Cannot find suitable non-ascii character'
322
'for user_encoding (%s)' % osutils.get_user_encoding())
323
out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
325
env_changes={'LANG': 'C'})
326
self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
327
'unsupported by the current encoding.')
358
329
def test_other_branch_commit(self):
359
330
# this branch is to ensure consistent behaviour, whether we're run
383
353
# commit to the original branch to make the checkout out of date
384
354
tree.commit('message branch', allow_pointless=True)
385
355
# now commit to the checkout should emit
386
# ERROR: Out of date with the branch, 'brz update' is suggested
356
# ERROR: Out of date with the branch, 'bzr update' is suggested
387
357
output = self.run_bzr('commit --unchanged -m checkout_message '
388
'checkout', retcode=3)
358
'checkout', retcode=3)
389
359
self.assertEqual(output,
391
"brz: ERROR: Working tree is out of date, please "
392
"run 'brz update'.\n"))
361
"bzr: ERROR: Working tree is out of date, please "
362
"run 'bzr update'.\n"))
394
364
def test_local_commit_unbound(self):
395
365
# a --local commit on an unbound branch is an error
396
366
self.make_branch_and_tree('.')
397
367
out, err = self.run_bzr('commit --local', retcode=3)
398
368
self.assertEqualDiff('', out)
399
self.assertEqualDiff('brz: ERROR: Cannot perform local-only commits '
369
self.assertEqualDiff('bzr: ERROR: Cannot perform local-only commits '
400
370
'on unbound branches.\n', err)
402
372
def test_commit_a_text_merge_in_a_checkout(self):
408
378
trunk = self.make_branch_and_tree('trunk')
410
380
u1 = trunk.branch.create_checkout('u1')
411
self.build_tree_contents([('u1/hosts', b'initial contents\n')])
381
self.build_tree_contents([('u1/hosts', 'initial contents\n')])
413
383
self.run_bzr('commit -m add-hosts u1')
415
385
u2 = trunk.branch.create_checkout('u2')
416
self.build_tree_contents([('u2/hosts', b'altered in u2\n')])
386
self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
417
387
self.run_bzr('commit -m checkin-from-u2 u2')
419
389
# make an offline commits
420
self.build_tree_contents(
421
[('u1/hosts', b'first offline change in u1\n')])
390
self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
422
391
self.run_bzr('commit -m checkin-offline --local u1')
424
393
# now try to pull in online work from u2, and then commit our offline
425
394
# work as a merge
426
395
# retcode 1 as we expect a text conflict
427
396
self.run_bzr('update u1', retcode=1)
428
self.assertFileEqual(b'''\
397
self.assertFileEqual('''\
430
399
first offline change in u1
536
506
'commit -m hello --fixes=lp:23452 tree/hello.txt')
537
507
self.assertEqual('', output)
538
508
self.assertContainsRe(err, 'Committing to: .*\n'
539
'added hello\\.txt\n'
540
'Committed revision 1\\.\n')
542
def test_fixes_bug_unicode(self):
543
"""commit --fixes=lp:unicode succeeds without output."""
544
tree = self.make_branch_and_tree('tree')
545
self.build_tree(['tree/hello.txt'])
546
tree.add('hello.txt')
547
output, err = self.run_bzr_raw(
548
['commit', '-m', 'hello',
549
u'--fixes=generic:\u20ac', 'tree/hello.txt'],
550
encoding='utf-8', retcode=3)
551
self.assertEqual(b'', output)
552
self.assertContainsRe(err,
553
b'brz: ERROR: Unrecognized bug generic:\xe2\x82\xac\\. Commit refused.\n')
510
'Committed revision 1\.\n')
555
512
def test_no_bugs_no_properties(self):
556
513
"""If no bugs are fixed, the bugs property is not set.
568
525
del properties['branch-nick']
569
526
self.assertFalse('bugs' in properties)
571
def test_bugs_sets_property(self):
572
"""commit --bugs=lp:234 sets the lp:234 revprop to 'related'."""
573
tree = self.make_branch_and_tree('tree')
574
self.build_tree(['tree/hello.txt'])
575
tree.add('hello.txt')
576
self.run_bzr('commit -m hello --bugs=lp:234 tree/hello.txt')
578
# Get the revision properties, ignoring the branch-nick property, which
579
# we don't care about for this test.
580
last_rev = tree.branch.repository.get_revision(tree.last_revision())
581
properties = dict(last_rev.properties)
582
del properties[u'branch-nick']
584
self.assertEqual({u'bugs': 'https://launchpad.net/bugs/234 related'},
587
528
def test_fixes_bug_sets_property(self):
588
529
"""commit --fixes=lp:234 sets the lp:234 revprop to 'fixed'."""
589
530
tree = self.make_branch_and_tree('tree')
651
591
'commit -m add-b --fixes=xxx:123',
652
592
working_dir='tree')
654
def test_fixes_bug_with_default_tracker(self):
655
"""commit --fixes=234 uses the default bug tracker."""
656
tree = self.make_branch_and_tree('tree')
657
self.build_tree(['tree/hello.txt'])
658
tree.add('hello.txt')
660
["brz: ERROR: No tracker specified for bug 123. Use the form "
661
"'tracker:id' or specify a default bug tracker using the "
662
"`bugtracker` option.\n"
663
"See \"brz help bugs\" for more information on this feature. "
665
'commit -m add-b --fixes=123',
667
tree.branch.get_config_stack().set("bugtracker", "lp")
668
self.run_bzr('commit -m hello --fixes=234 tree/hello.txt')
669
last_rev = tree.branch.repository.get_revision(tree.last_revision())
670
self.assertEqual('https://launchpad.net/bugs/234 fixed',
671
last_rev.properties['bugs'])
673
594
def test_fixes_invalid_bug_number(self):
674
595
tree = self.make_branch_and_tree('tree')
675
596
self.build_tree(['tree/hello.txt'])
676
597
tree.add('hello.txt')
677
598
self.run_bzr_error(
678
599
["Did not understand bug identifier orange: Must be an integer. "
679
"See \"brz help bugs\" for more information on this feature.\n"
600
"See \"bzr help bugs\" for more information on this feature.\n"
680
601
"Commit refused."],
681
602
'commit -m add-b --fixes=lp:orange',
682
603
working_dir='tree')
745
665
self.build_tree(['tree/hello.txt'])
746
666
tree.add('hello.txt')
747
667
out, err = self.run_bzr("commit -m hello "
748
"--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
668
"--commit-time='2009-10-10 08:00:00 +0100' tree/hello.txt")
749
669
last_rev = tree.branch.repository.get_revision(tree.last_revision())
750
670
self.assertEqual(
751
671
'Sat 2009-10-10 08:00:00 +0100',
752
672
osutils.format_date(last_rev.timestamp, last_rev.timezone))
754
674
def test_commit_time_bad_time(self):
755
675
tree = self.make_branch_and_tree('tree')
756
676
self.build_tree(['tree/hello.txt'])
757
677
tree.add('hello.txt')
758
678
out, err = self.run_bzr("commit -m hello "
759
"--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
760
self.assertStartsWith(
761
err, "brz: ERROR: Could not parse --commit-time:")
763
def test_commit_time_missing_tz(self):
764
tree = self.make_branch_and_tree('tree')
765
self.build_tree(['tree/hello.txt'])
766
tree.add('hello.txt')
767
out, err = self.run_bzr("commit -m hello "
768
"--commit-time='2009-10-10 08:00:00' tree/hello.txt", retcode=3)
769
self.assertStartsWith(
770
err, "brz: ERROR: Could not parse --commit-time:")
771
# Test that it is actually checking and does not simply crash with
772
# some other exception
773
self.assertContainsString(err, "missing a timezone offset")
679
"--commit-time='NOT A TIME' tree/hello.txt", retcode=3)
680
self.assertStartsWith(
681
err, "bzr: ERROR: Could not parse --commit-time:")
775
683
def test_partial_commit_with_renames_in_tree(self):
776
684
# this test illustrates bug #140419
794
702
# "UnlockableTransport error trying to commit in checkout of readonly
796
704
self.make_branch('master')
797
master = ControlDir.open_from_transport(
705
master = BzrDir.open_from_transport(
798
706
self.get_readonly_transport('master')).open_branch()
799
707
master.create_checkout('checkout')
800
708
out, err = self.run_bzr(['commit', '--unchanged', '-mfoo', 'checkout'],
802
710
self.assertContainsRe(err,
803
r'^brz: ERROR: Cannot lock.*readonly transport')
711
r'^bzr: ERROR: Cannot lock.*readonly transport')
805
713
def setup_editor(self):
806
714
# Test that commit template hooks work
807
715
if sys.platform == "win32":
808
with open('fed.bat', 'w') as f:
809
f.write('@rem dummy fed')
810
self.overrideEnv('BRZ_EDITOR', "fed.bat")
716
f = file('fed.bat', 'w')
717
f.write('@rem dummy fed')
719
osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
812
with open('fed.sh', 'wb') as f:
813
f.write(b'#!/bin/sh\n')
814
os.chmod('fed.sh', 0o755)
815
self.overrideEnv('BRZ_EDITOR', "./fed.sh")
721
f = file('fed.sh', 'wb')
722
f.write('#!/bin/sh\n')
724
os.chmod('fed.sh', 0755)
725
osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
817
727
def setup_commit_with_template(self):
818
728
self.setup_editor()
819
729
msgeditor.hooks.install_named_hook("commit_message_template",
820
lambda commit_obj, msg: "save me some typing\n", None)
730
lambda commit_obj, msg: "save me some typing\n", None)
821
731
tree = self.make_branch_and_tree('tree')
822
732
self.build_tree(['tree/hello.txt'])
823
733
tree.add('hello.txt')
826
def test_edit_empty_message(self):
827
tree = self.make_branch_and_tree('tree')
829
self.build_tree(['tree/hello.txt'])
830
tree.add('hello.txt')
831
out, err = self.run_bzr("commit tree/hello.txt", retcode=3,
833
self.assertContainsRe(err,
834
"brz: ERROR: Empty commit message specified")
836
736
def test_commit_hook_template_accepted(self):
837
737
tree = self.setup_commit_with_template()
838
738
out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
842
742
def test_commit_hook_template_rejected(self):
843
743
tree = self.setup_commit_with_template()
844
744
expected = tree.last_revision()
845
out, err = self.run_bzr_error(["Empty commit message specified."
846
" Please specify a commit message with either"
847
" --message or --file or leave a blank message"
848
" with --message \"\"."],
849
"commit tree/hello.txt", stdin="n\n")
745
out, err = self.run_bzr_error(["empty commit message"],
746
"commit tree/hello.txt", stdin="n\n")
850
747
self.assertEqual(expected, tree.last_revision())
852
def test_set_commit_message(self):
853
msgeditor.hooks.install_named_hook("set_commit_message",
854
lambda commit_obj, msg: "save me some typing\n", None)
855
tree = self.make_branch_and_tree('tree')
856
self.build_tree(['tree/hello.txt'])
857
tree.add('hello.txt')
858
out, err = self.run_bzr("commit tree/hello.txt")
859
last_rev = tree.branch.repository.get_revision(tree.last_revision())
860
self.assertEqual('save me some typing\n', last_rev.message)
862
749
def test_commit_without_username(self):
863
750
"""Ensure commit error if username is not set.
865
752
self.run_bzr(['init', 'foo'])
866
with open('foo/foo.txt', 'w') as f:
868
self.run_bzr(['add'], working_dir='foo')
869
override_whoami(self)
871
['Unable to determine your name'],
872
['commit', '-m', 'initial'], working_dir='foo')
874
def test_commit_recursive_checkout(self):
875
"""Ensure that a commit to a recursive checkout fails cleanly.
877
self.run_bzr(['init', 'test_branch'])
878
self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
880
self.run_bzr(['bind', '.'], working_dir='test_checkout')
881
with open('test_checkout/foo.txt', 'w') as f:
883
self.run_bzr(['add'], working_dir='test_checkout')
884
out, err = self.run_bzr_error(
885
['Branch.*test_checkout.*appears to be bound to itself'],
886
['commit', '-m', 'addedfoo'], working_dir='test_checkout')
888
def test_mv_dirs_non_ascii(self):
889
"""Move directory with non-ascii name and containing files.
891
Regression test for bug 185211.
893
tree = self.make_branch_and_tree('.')
894
self.build_tree([u'abc\xa7/', u'abc\xa7/foo'])
896
tree.add([u'abc\xa7/', u'abc\xa7/foo'])
897
tree.commit('checkin')
899
tree.rename_one(u'abc\xa7', 'abc')
901
self.run_bzr('ci -m "non-ascii mv"')
904
class TestSmartServerCommit(TestCaseWithTransport):
906
def test_commit_to_lightweight(self):
907
self.setup_smart_server_with_call_log()
908
t = self.make_branch_and_tree('from')
909
for count in range(9):
910
t.commit(message='commit %d' % count)
911
out, err = self.run_bzr(['checkout', '--lightweight', self.get_url('from'),
913
self.reset_smart_call_log()
914
self.build_tree(['target/afile'])
915
self.run_bzr(['add', 'target/afile'])
916
out, err = self.run_bzr(['commit', '-m', 'do something', 'target'])
917
# This figure represent the amount of work to perform this use case. It
918
# is entirely ok to reduce this number if a test fails due to rpc_count
919
# being too low. If rpc_count increases, more network roundtrips have
920
# become necessary for this use case. Please do not adjust this number
921
# upwards without agreement from bzr's network support maintainers.
922
self.assertLength(211, self.hpss_calls)
923
self.assertLength(2, self.hpss_connections)
924
self.expectFailure("commit still uses VFS calls",
925
self.assertThat, self.hpss_calls, ContainsNoVfsCalls)
754
open('foo.txt', 'w').write('hello')
755
self.run_bzr(['add'])
756
osutils.set_or_unset_env('EMAIL', None)
757
osutils.set_or_unset_env('BZR_EMAIL', None)
758
out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
759
self.assertContainsRe(err, 'Unable to determine your name')