]> git.ipfire.org Git - thirdparty/git.git/blobdiff - t/t4203-mailmap.sh
Merge branch 'ab/mailmap'
[thirdparty/git.git] / t / t4203-mailmap.sh
index 3f82c651b4522e83d507a8f6efbf573dd9ee95df..6fb18a34b05a306134434f6d3279071363d660ed 100755 (executable)
@@ -7,28 +7,9 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
 . ./test-lib.sh
 
-fuzz_blame () {
-       sed "
-               s/$_x05[0-9a-f][0-9a-f][0-9a-f]/OBJID/g
-               s/$_x05[0-9a-f][0-9a-f]/OBJI/g
-               s/[-0-9]\{10\} [:0-9]\{8\} [-+][0-9]\{4\}/DATE/g
-       " "$@"
-}
-
-test_expect_success setup '
-       cat >contacts <<- EOF &&
-       $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
-       nick1 <bugs@company.xx>
-       EOF
-
-       echo one >one &&
-       git add one &&
-       test_tick &&
-       git commit -m initial &&
-       echo two >>one &&
-       git add one &&
-       test_tick &&
-       git commit --author "nick1 <bugs@company.xx>" -m second
+test_expect_success 'setup commits and contacts file' '
+       test_commit initial one one &&
+       test_commit --author "nick1 <bugs@company.xx>" --append second one two
 '
 
 test_expect_success 'check-mailmap no arguments' '
@@ -36,7 +17,7 @@ test_expect_success 'check-mailmap no arguments' '
 '
 
 test_expect_success 'check-mailmap arguments' '
-       cat >expect <<- EOF &&
+       cat >expect <<-EOF &&
        $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
        nick1 <bugs@company.xx>
        EOF
@@ -47,150 +28,229 @@ test_expect_success 'check-mailmap arguments' '
 '
 
 test_expect_success 'check-mailmap --stdin' '
-       cat >expect <<- EOF &&
+       cat >expect <<-EOF &&
        $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
        nick1 <bugs@company.xx>
        EOF
-       git check-mailmap --stdin <contacts >actual &&
+       git check-mailmap --stdin <expect >actual &&
        test_cmp expect actual
 '
 
-test_expect_success 'check-mailmap --stdin arguments' '
+test_expect_success 'check-mailmap --stdin arguments: no mapping' '
+       test_when_finished "rm contacts" &&
+       cat >contacts <<-EOF &&
+       $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
+       nick1 <bugs@company.xx>
+       EOF
        cat >expect <<-\EOF &&
        Internal Guy <bugs@company.xy>
        EOF
-       cat <contacts >>expect &&
+       cat contacts >>expect &&
+
        git check-mailmap --stdin "Internal Guy <bugs@company.xy>" \
                <contacts >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'check-mailmap --stdin arguments: mapping' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       New Name <$GIT_AUTHOR_EMAIL>
+       EOF
+       cat >stdin <<-EOF &&
+       Old Name <$GIT_AUTHOR_EMAIL>
+       EOF
+
+       cp .mailmap expect &&
+       git check-mailmap --stdin <stdin >actual &&
+       test_cmp expect actual &&
+
+       cat .mailmap >>expect &&
+       git check-mailmap --stdin "Another Old Name <$GIT_AUTHOR_EMAIL>" \
+               <stdin >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'check-mailmap bogus contact' '
        test_must_fail git check-mailmap bogus
 '
 
-cat >expect << EOF
-$GIT_AUTHOR_NAME (1):
-      initial
+test_expect_success 'check-mailmap bogus contact --stdin' '
+       test_must_fail git check-mailmap --stdin bogus </dev/null
+'
 
-nick1 (1):
-      second
+test_expect_success 'No mailmap' '
+       cat >expect <<-EOF &&
+       $GIT_AUTHOR_NAME (1):
+             initial
 
-EOF
+       nick1 (1):
+             second
 
-test_expect_success 'No mailmap' '
+       EOF
        git shortlog HEAD >actual &&
        test_cmp expect actual
 '
 
-cat >expect <<\EOF
-Repo Guy (1):
-      initial
+test_expect_success 'setup default .mailmap' '
+       cat >default.map <<-EOF
+       Repo Guy <$GIT_AUTHOR_EMAIL>
+       EOF
+'
 
-nick1 (1):
-      second
+test_expect_success 'test default .mailmap' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
 
-EOF
+       cat >expect <<-\EOF &&
+       Repo Guy (1):
+             initial
+
+       nick1 (1):
+             second
 
-test_expect_success 'default .mailmap' '
-       echo "Repo Guy <$GIT_AUTHOR_EMAIL>" > .mailmap &&
+       EOF
        git shortlog HEAD >actual &&
        test_cmp expect actual
 '
 
-# Using a mailmap file in a subdirectory of the repo here, but
-# could just as well have been a file outside of the repository
-cat >expect <<\EOF
-Internal Guy (1):
-      second
+test_expect_success 'mailmap.file set' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
 
-Repo Guy (1):
-      initial
+       test_config mailmap.file internal.map &&
+       cat >internal.map <<-\EOF &&
+       Internal Guy <bugs@company.xx>
+       EOF
 
-EOF
-test_expect_success 'mailmap.file set' '
-       mkdir -p internal_mailmap &&
-       echo "Internal Guy <bugs@company.xx>" > internal_mailmap/.mailmap &&
-       git config mailmap.file internal_mailmap/.mailmap &&
+       cat >expect <<-\EOF &&
+       Internal Guy (1):
+             second
+
+       Repo Guy (1):
+             initial
+
+       EOF
        git shortlog HEAD >actual &&
-       test_cmp expect actual
+       test_cmp expect actual &&
+
+       # The internal_mailmap/.mailmap file is an a subdirectory, but
+       # as shown here it can also be outside the repository
+       test_when_finished "rm -rf sub-repo" &&
+       git clone . sub-repo &&
+       (
+               cd sub-repo &&
+               cp ../.mailmap . &&
+               git config mailmap.file ../internal.map &&
+               git shortlog HEAD >actual &&
+               test_cmp ../expect actual
+       )
 '
 
-cat >expect <<\EOF
-External Guy (1):
-      initial
+test_expect_success 'mailmap.file override' '
+       test_config mailmap.file internal.map &&
+       cat >internal.map <<-EOF &&
+       Internal Guy <bugs@company.xx>
+       External Guy <$GIT_AUTHOR_EMAIL>
+       EOF
 
-Internal Guy (1):
-      second
+       cat >expect <<-\EOF &&
+       External Guy (1):
+             initial
 
-EOF
-test_expect_success 'mailmap.file override' '
-       echo "External Guy <$GIT_AUTHOR_EMAIL>" >> internal_mailmap/.mailmap &&
-       git config mailmap.file internal_mailmap/.mailmap &&
+       Internal Guy (1):
+             second
+
+       EOF
        git shortlog HEAD >actual &&
        test_cmp expect actual
 '
 
-cat >expect <<\EOF
-Repo Guy (1):
-      initial
+test_expect_success 'mailmap.file non-existent' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
 
-nick1 (1):
-      second
+       cat >expect <<-\EOF &&
+       Repo Guy (1):
+             initial
 
-EOF
+       nick1 (1):
+             second
 
-test_expect_success 'mailmap.file non-existent' '
-       rm internal_mailmap/.mailmap &&
-       rmdir internal_mailmap &&
+       EOF
        git shortlog HEAD >actual &&
        test_cmp expect actual
 '
 
-cat >expect <<\EOF
-Internal Guy (1):
-      second
+test_expect_success 'name entry after email entry' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
+
+       test_config mailmap.file internal.map &&
+       cat >internal.map <<-\EOF &&
+       <bugs@company.xy> <bugs@company.xx>
+       Internal Guy <bugs@company.xx>
+       EOF
 
-Repo Guy (1):
-      initial
+       cat >expect <<-\EOF &&
+       Internal Guy (1):
+             second
 
-EOF
+       Repo Guy (1):
+             initial
+
+       EOF
 
-test_expect_success 'name entry after email entry' '
-       mkdir -p internal_mailmap &&
-       echo "<bugs@company.xy> <bugs@company.xx>" >internal_mailmap/.mailmap &&
-       echo "Internal Guy <bugs@company.xx>" >>internal_mailmap/.mailmap &&
        git shortlog HEAD >actual &&
        test_cmp expect actual
 '
 
-cat >expect <<\EOF
-Internal Guy (1):
-      second
+test_expect_success 'name entry after email entry, case-insensitive' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
 
-Repo Guy (1):
-      initial
+       test_config mailmap.file internal.map &&
+       cat >internal.map <<-\EOF &&
+       <bugs@company.xy> <bugs@company.xx>
+       Internal Guy <BUGS@Company.xx>
+       EOF
 
-EOF
+       cat >expect <<-\EOF &&
+       Internal Guy (1):
+             second
 
-test_expect_success 'name entry after email entry, case-insensitive' '
-       mkdir -p internal_mailmap &&
-       echo "<bugs@company.xy> <bugs@company.xx>" >internal_mailmap/.mailmap &&
-       echo "Internal Guy <BUGS@Company.xx>" >>internal_mailmap/.mailmap &&
+       Repo Guy (1):
+             initial
+
+       EOF
+       git shortlog HEAD >actual &&
+       test_cmp expect actual &&
+
+       cat >internal.map <<-\EOF &&
+       NiCk <BuGs@CoMpAnY.Xy> NICK1 <BUGS@COMPANY.XX>
+       EOF
+
+       cat >expect <<-\EOF &&
+       NiCk (1):
+             second
+
+       Repo Guy (1):
+             initial
+
+       EOF
        git shortlog HEAD >actual &&
        test_cmp expect actual
 '
 
-cat >expect << EOF
-$GIT_AUTHOR_NAME (1):
-      initial
+test_expect_success 'No mailmap files, but configured' '
+       cat >expect <<-EOF &&
+       $GIT_AUTHOR_NAME (1):
+             initial
 
-nick1 (1):
-      second
+       nick1 (1):
+             second
 
-EOF
-test_expect_success 'No mailmap files, but configured' '
-       rm -f .mailmap internal_mailmap/.mailmap &&
+       EOF
        git shortlog HEAD >actual &&
        test_cmp expect actual
 '
@@ -198,21 +258,26 @@ test_expect_success 'No mailmap files, but configured' '
 test_expect_success 'setup mailmap blob tests' '
        git checkout -b map &&
        test_when_finished "git checkout main" &&
-       cat >just-bugs <<- EOF &&
+       cat >just-bugs <<-\EOF &&
        Blob Guy <bugs@company.xx>
        EOF
-       cat >both <<- EOF &&
+       cat >both <<-EOF &&
        Blob Guy <$GIT_AUTHOR_EMAIL>
        Blob Guy <bugs@company.xx>
        EOF
        printf "Tricky Guy <$GIT_AUTHOR_EMAIL>" >no-newline &&
        git add just-bugs both no-newline &&
        git commit -m "my mailmaps" &&
-       echo "Repo Guy <$GIT_AUTHOR_EMAIL>" >.mailmap &&
-       echo "Internal Guy <$GIT_AUTHOR_EMAIL>" >internal.map
+
+       cat >internal.map <<-EOF
+       Internal Guy <$GIT_AUTHOR_EMAIL>
+       EOF
 '
 
 test_expect_success 'mailmap.blob set' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
+
        cat >expect <<-\EOF &&
        Blob Guy (1):
              second
@@ -226,6 +291,9 @@ test_expect_success 'mailmap.blob set' '
 '
 
 test_expect_success 'mailmap.blob overrides .mailmap' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
+
        cat >expect <<-\EOF &&
        Blob Guy (2):
              initial
@@ -252,7 +320,28 @@ test_expect_success 'mailmap.file overrides mailmap.blob' '
        test_cmp expect actual
 '
 
+test_expect_success 'mailmap.file can be missing' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
+
+       test_config mailmap.file nonexistent &&
+       cat >expect <<-\EOF &&
+       Repo Guy (1):
+             initial
+
+       nick1 (1):
+             second
+
+       EOF
+       git shortlog HEAD >actual 2>err &&
+       test_must_be_empty err &&
+       test_cmp expect actual
+'
+
 test_expect_success 'mailmap.blob can be missing' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
+
        cat >expect <<-\EOF &&
        Repo Guy (1):
              initial
@@ -261,7 +350,17 @@ test_expect_success 'mailmap.blob can be missing' '
              second
 
        EOF
-       git -c mailmap.blob=map:nonexistent shortlog HEAD >actual &&
+       git -c mailmap.blob=map:nonexistent shortlog HEAD >actual 2>err &&
+       test_must_be_empty err &&
+       test_cmp expect actual
+'
+
+test_expect_success 'mailmap.blob might be the wrong type' '
+       test_when_finished "rm .mailmap" &&
+       cp default.map .mailmap &&
+
+       git -c mailmap.blob=HEAD: shortlog HEAD >actual 2>err &&
+       test_i18ngrep "mailmap is not a blob" err &&
        test_cmp expect actual
 '
 
@@ -270,11 +369,15 @@ test_expect_success 'mailmap.blob defaults to off in non-bare repo' '
        (
                cd non-bare &&
                test_commit one .mailmap "Fake Name <$GIT_AUTHOR_EMAIL>" &&
-               echo "     1    Fake Name" >expect &&
+               cat >expect <<-\EOF &&
+                    1  Fake Name
+               EOF
                git shortlog -ns HEAD >actual &&
                test_cmp expect actual &&
                rm .mailmap &&
-               echo "     1    $GIT_AUTHOR_NAME" >expect &&
+               cat >expect <<-EOF &&
+                    1  $GIT_AUTHOR_NAME
+               EOF
                git shortlog -ns HEAD >actual &&
                test_cmp expect actual
        )
@@ -284,7 +387,9 @@ test_expect_success 'mailmap.blob defaults to HEAD:.mailmap in bare repo' '
        git clone --bare non-bare bare &&
        (
                cd bare &&
-               echo "     1    Fake Name" >expect &&
+               cat >expect <<-\EOF &&
+                    1  Fake Name
+               EOF
                git shortlog -ns HEAD >actual &&
                test_cmp expect actual
        )
@@ -303,178 +408,258 @@ test_expect_success 'mailmap.blob can handle blobs without trailing newline' '
        test_cmp expect actual
 '
 
-test_expect_success 'cleanup after mailmap.blob tests' '
-       rm -f .mailmap
-'
-
 test_expect_success 'single-character name' '
-       echo "     1    A <$GIT_AUTHOR_EMAIL>" >expect &&
-       echo "     1    nick1 <bugs@company.xx>" >>expect &&
-       echo "A <$GIT_AUTHOR_EMAIL>" >.mailmap &&
        test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       A <$GIT_AUTHOR_EMAIL>
+       EOF
+
+       cat >expect <<-EOF &&
+            1  A <$GIT_AUTHOR_EMAIL>
+            1  nick1 <bugs@company.xx>
+       EOF
        git shortlog -es HEAD >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'preserve canonical email case' '
-       echo "     1    $GIT_AUTHOR_NAME <AUTHOR@example.com>" >expect &&
-       echo "     1    nick1 <bugs@company.xx>" >>expect &&
-       echo "<AUTHOR@example.com> <$GIT_AUTHOR_EMAIL>" >.mailmap &&
        test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-EOF &&
+       <AUTHOR@example.com> <$GIT_AUTHOR_EMAIL>
+       EOF
+
+       cat >expect <<-EOF &&
+            1  $GIT_AUTHOR_NAME <AUTHOR@example.com>
+            1  nick1 <bugs@company.xx>
+       EOF
        git shortlog -es HEAD >actual &&
        test_cmp expect actual
 '
 
-# Extended mailmap configurations should give us the following output for shortlog
-cat >expect << EOF
-$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> (1):
-      initial
+test_expect_success 'gitmailmap(5) example output: setup' '
+       test_create_repo doc &&
+       test_commit -C doc --author "Joe Developer <joe@example.com>" A &&
+       test_commit -C doc --author "Joe R. Developer <joe@example.com>" B &&
+       test_commit -C doc --author "Jane Doe <jane@example.com>" C &&
+       test_commit -C doc --author "Jane Doe <jane@laptop.(none)>" D &&
+       test_commit -C doc --author "Jane D. <jane@desktop.(none)>" E
+'
+
+test_expect_success 'gitmailmap(5) example output: example #1' '
+       test_config -C doc mailmap.file ../doc.map &&
+       cat >doc.map <<-\EOF &&
+       Joe R. Developer <joe@example.com>
+       Jane Doe <jane@example.com>
+       Jane Doe <jane@desktop.(none)>
+       EOF
+
+       cat >expect <<-\EOF &&
+       Author Joe Developer <joe@example.com> maps to Joe R. Developer <joe@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Joe R. Developer <joe@example.com> maps to Joe R. Developer <joe@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Jane Doe <jane@example.com> maps to Jane Doe <jane@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@laptop.(none)>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@desktop.(none)>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+       EOF
+       git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'gitmailmap(5) example output: example #2' '
+       test_config -C doc mailmap.file ../doc.map &&
+       cat >doc.map <<-\EOF &&
+       Joe R. Developer <joe@example.com>
+       Jane Doe <jane@example.com> <jane@laptop.(none)>
+       Jane Doe <jane@example.com> <jane@desktop.(none)>
+       EOF
+
+       cat >expect <<-\EOF &&
+       Author Joe Developer <joe@example.com> maps to Joe R. Developer <joe@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Joe R. Developer <joe@example.com> maps to Joe R. Developer <joe@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Jane Doe <jane@example.com> maps to Jane Doe <jane@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Jane Doe <jane@laptop.(none)> maps to Jane Doe <jane@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author Jane D <jane@desktop.(none)> maps to Jane Doe <jane@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+       EOF
+       git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'gitmailmap(5) example output: example #3' '
+       test_config -C doc mailmap.file ../doc.map &&
+       cat >>doc.map <<-\EOF &&
+       Joe R. Developer <joe@example.com> Joe <bugs@example.com>
+       Jane Doe <jane@example.com> Jane <bugs@example.com>
+       EOF
 
-CTO <cto@company.xx> (1):
-      seventh
+       test_commit -C doc --author "Joe <bugs@example.com>" F &&
+       test_commit -C doc --author "Jane <bugs@example.com>" G &&
 
-Other Author <other@author.xx> (2):
-      third
-      fourth
+       cat >>expect <<-\EOF &&
 
-Santa Claus <santa.claus@northpole.xx> (2):
-      fifth
-      sixth
+       Author Joe <bugs@example.com> maps to Joe R. Developer <joe@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
 
-Some Dude <some@dude.xx> (1):
-      second
+       Author Jane <bugs@example.com> maps to Jane Doe <jane@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+       EOF
+       git -C doc log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
+       test_cmp expect actual
+'
 
-EOF
 
 test_expect_success 'Shortlog output (complex mapping)' '
-       echo three >>one &&
-       git add one &&
-       test_tick &&
-       git commit --author "nick2 <bugs@company.xx>" -m third &&
-
-       echo four >>one &&
-       git add one &&
-       test_tick &&
-       git commit --author "nick2 <nick2@company.xx>" -m fourth &&
-
-       echo five >>one &&
-       git add one &&
-       test_tick &&
-       git commit --author "santa <me@company.xx>" -m fifth &&
-
-       echo six >>one &&
-       git add one &&
-       test_tick &&
-       git commit --author "claus <me@company.xx>" -m sixth &&
-
-       echo seven >>one &&
-       git add one &&
-       test_tick &&
-       git commit --author "CTO <cto@coompany.xx>" -m seventh &&
-
-       mkdir -p internal_mailmap &&
-       echo "Committed <$GIT_COMMITTER_EMAIL>" > internal_mailmap/.mailmap &&
-       echo "<cto@company.xx>                       <cto@coompany.xx>" >> internal_mailmap/.mailmap &&
-       echo "Some Dude <some@dude.xx>         nick1 <bugs@company.xx>" >> internal_mailmap/.mailmap &&
-       echo "Other Author <other@author.xx>   nick2 <bugs@company.xx>" >> internal_mailmap/.mailmap &&
-       echo "Other Author <other@author.xx>         <nick2@company.xx>" >> internal_mailmap/.mailmap &&
-       echo "Santa Claus <santa.claus@northpole.xx> <me@company.xx>" >> internal_mailmap/.mailmap &&
-       echo "Santa Claus <santa.claus@northpole.xx> <me@company.xx>" >> internal_mailmap/.mailmap &&
+       test_config mailmap.file complex.map &&
+       cat >complex.map <<-EOF &&
+       Committed <$GIT_COMMITTER_EMAIL>
+       <cto@company.xx> <cto@coompany.xx>
+       Some Dude <some@dude.xx>         nick1 <bugs@company.xx>
+       Other Author <other@author.xx>   nick2 <bugs@company.xx>
+       Other Author <other@author.xx>         <nick2@company.xx>
+       Santa Claus <santa.claus@northpole.xx> <me@company.xx>
+       EOF
+
+       test_commit --author "nick2 <bugs@company.xx>" --append third one three &&
+       test_commit --author "nick2 <nick2@company.xx>" --append fourth one four &&
+       test_commit --author "santa <me@company.xx>" --append fifth one five &&
+       test_commit --author "claus <me@company.xx>" --append sixth one six &&
+       test_commit --author "CTO <cto@coompany.xx>" --append seventh one seven &&
+
+       cat >expect <<-EOF &&
+       $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> (1):
+             initial
+
+       CTO <cto@company.xx> (1):
+             seventh
+
+       Other Author <other@author.xx> (2):
+             third
+             fourth
+
+       Santa Claus <santa.claus@northpole.xx> (2):
+             fifth
+             sixth
+
+       Some Dude <some@dude.xx> (1):
+             second
+
+       EOF
 
        git shortlog -e HEAD >actual &&
        test_cmp expect actual
 
 '
 
-# git log with --pretty format which uses the name and email mailmap placemarkers
-cat >expect << EOF
-Author CTO <cto@coompany.xx> maps to CTO <cto@company.xx>
-Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+test_expect_success 'Log output (complex mapping)' '
+       test_config mailmap.file complex.map &&
 
-Author claus <me@company.xx> maps to Santa Claus <santa.claus@northpole.xx>
-Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+       cat >expect <<-EOF &&
+       Author CTO <cto@coompany.xx> maps to CTO <cto@company.xx>
+       Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
 
-Author santa <me@company.xx> maps to Santa Claus <santa.claus@northpole.xx>
-Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+       Author claus <me@company.xx> maps to Santa Claus <santa.claus@northpole.xx>
+       Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
 
-Author nick2 <nick2@company.xx> maps to Other Author <other@author.xx>
-Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+       Author santa <me@company.xx> maps to Santa Claus <santa.claus@northpole.xx>
+       Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
 
-Author nick2 <bugs@company.xx> maps to Other Author <other@author.xx>
-Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+       Author nick2 <nick2@company.xx> maps to Other Author <other@author.xx>
+       Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
 
-Author nick1 <bugs@company.xx> maps to Some Dude <some@dude.xx>
-Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+       Author nick2 <bugs@company.xx> maps to Other Author <other@author.xx>
+       Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
 
-Author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> maps to $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
-Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
-EOF
+       Author nick1 <bugs@company.xx> maps to Some Dude <some@dude.xx>
+       Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+
+       Author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> maps to $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
+       Committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> maps to Committed <$GIT_COMMITTER_EMAIL>
+       EOF
 
-test_expect_success 'Log output (complex mapping)' '
        git log --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
        test_cmp expect actual
 '
 
-cat >expect << EOF
-Author email cto@coompany.xx has local-part cto
-Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
+test_expect_success 'Log output (local-part email address)' '
+       cat >expect <<-EOF &&
+       Author email cto@coompany.xx has local-part cto
+       Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
 
-Author email me@company.xx has local-part me
-Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
+       Author email me@company.xx has local-part me
+       Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
 
-Author email me@company.xx has local-part me
-Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
+       Author email me@company.xx has local-part me
+       Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
 
-Author email nick2@company.xx has local-part nick2
-Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
+       Author email nick2@company.xx has local-part nick2
+       Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
 
-Author email bugs@company.xx has local-part bugs
-Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
+       Author email bugs@company.xx has local-part bugs
+       Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
 
-Author email bugs@company.xx has local-part bugs
-Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
+       Author email bugs@company.xx has local-part bugs
+       Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
 
-Author email author@example.com has local-part author
-Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
-EOF
+       Author email author@example.com has local-part author
+       Committer email $GIT_COMMITTER_EMAIL has local-part $TEST_COMMITTER_LOCALNAME
+       EOF
 
-test_expect_success 'Log output (local-part email address)' '
        git log --pretty=format:"Author email %ae has local-part %al%nCommitter email %ce has local-part %cl%n" >actual &&
        test_cmp expect actual
 '
 
-cat >expect << EOF
-Author: CTO <cto@company.xx>
-Author: Santa Claus <santa.claus@northpole.xx>
-Author: Santa Claus <santa.claus@northpole.xx>
-Author: Other Author <other@author.xx>
-Author: Other Author <other@author.xx>
-Author: Some Dude <some@dude.xx>
-Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
-EOF
-
 test_expect_success 'Log output with --use-mailmap' '
+       test_config mailmap.file complex.map &&
+
+       cat >expect <<-EOF &&
+       Author: CTO <cto@company.xx>
+       Author: Santa Claus <santa.claus@northpole.xx>
+       Author: Santa Claus <santa.claus@northpole.xx>
+       Author: Other Author <other@author.xx>
+       Author: Other Author <other@author.xx>
+       Author: Some Dude <some@dude.xx>
+       Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
+       EOF
+
        git log --use-mailmap | grep Author >actual &&
        test_cmp expect actual
 '
 
-cat >expect << EOF
-Author: CTO <cto@company.xx>
-Author: Santa Claus <santa.claus@northpole.xx>
-Author: Santa Claus <santa.claus@northpole.xx>
-Author: Other Author <other@author.xx>
-Author: Other Author <other@author.xx>
-Author: Some Dude <some@dude.xx>
-Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
-EOF
-
 test_expect_success 'Log output with log.mailmap' '
+       test_config mailmap.file complex.map &&
+
+       cat >expect <<-EOF &&
+       Author: CTO <cto@company.xx>
+       Author: Santa Claus <santa.claus@northpole.xx>
+       Author: Santa Claus <santa.claus@northpole.xx>
+       Author: Other Author <other@author.xx>
+       Author: Other Author <other@author.xx>
+       Author: Some Dude <some@dude.xx>
+       Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
+       EOF
+
        git -c log.mailmap=True log | grep Author >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'log.mailmap=false disables mailmap' '
-       cat >expect <<- EOF &&
+       cat >expect <<-EOF &&
        Author: CTO <cto@coompany.xx>
        Author: claus <me@company.xx>
        Author: santa <me@company.xx>
@@ -483,12 +668,12 @@ test_expect_success 'log.mailmap=false disables mailmap' '
        Author: nick1 <bugs@company.xx>
        Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL>
        EOF
-       git -c log.mailmap=False log | grep Author > actual &&
+       git -c log.mailmap=false log | grep Author >actual &&
        test_cmp expect actual
 '
 
 test_expect_success '--no-use-mailmap disables mailmap' '
-       cat >expect <<- EOF &&
+       cat >expect <<-EOF &&
        Author: CTO <cto@coompany.xx>
        Author: claus <me@company.xx>
        Author: santa <me@company.xx>
@@ -501,60 +686,200 @@ test_expect_success '--no-use-mailmap disables mailmap' '
        test_cmp expect actual
 '
 
-cat >expect <<\EOF
-Author: Santa Claus <santa.claus@northpole.xx>
-Author: Santa Claus <santa.claus@northpole.xx>
-EOF
-
 test_expect_success 'Grep author with --use-mailmap' '
+       test_config mailmap.file complex.map &&
+
+       cat >expect <<-\EOF &&
+       Author: Santa Claus <santa.claus@northpole.xx>
+       Author: Santa Claus <santa.claus@northpole.xx>
+       EOF
        git log --use-mailmap --author Santa | grep Author >actual &&
        test_cmp expect actual
 '
-cat >expect <<\EOF
-Author: Santa Claus <santa.claus@northpole.xx>
-Author: Santa Claus <santa.claus@northpole.xx>
-EOF
 
 test_expect_success 'Grep author with log.mailmap' '
+       test_config mailmap.file complex.map &&
+
+       cat >expect <<-\EOF &&
+       Author: Santa Claus <santa.claus@northpole.xx>
+       Author: Santa Claus <santa.claus@northpole.xx>
+       EOF
+
        git -c log.mailmap=True log --author Santa | grep Author >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'log.mailmap is true by default these days' '
+       test_config mailmap.file complex.map &&
        git log --author Santa | grep Author >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'Only grep replaced author with --use-mailmap' '
+       test_config mailmap.file complex.map &&
        git log --use-mailmap --author "<cto@coompany.xx>" >actual &&
        test_must_be_empty actual
 '
 
-# git blame
-cat >expect <<EOF
-^OBJI ($GIT_AUTHOR_NAME     DATE 1) one
-OBJID (Some Dude    DATE 2) two
-OBJID (Other Author DATE 3) three
-OBJID (Other Author DATE 4) four
-OBJID (Santa Claus  DATE 5) five
-OBJID (Santa Claus  DATE 6) six
-OBJID (CTO          DATE 7) seven
-EOF
-test_expect_success 'Blame output (complex mapping)' '
-       git blame one >actual &&
-       fuzz_blame actual >actual.fuzz &&
+test_expect_success 'Blame --porcelain output (complex mapping)' '
+       test_config mailmap.file complex.map &&
+
+       cat >expect <<-EOF &&
+       1 1 1
+       A U Thor
+       2 2 1
+       Some Dude
+       3 3 1
+       Other Author
+       4 4 1
+       Other Author
+       5 5 1
+       Santa Claus
+       6 6 1
+       Santa Claus
+       7 7 1
+       CTO
+       EOF
+
+       git blame --porcelain one >actual.blame &&
+       grep -E \
+               -e "[0-9]+ [0-9]+ [0-9]+$" \
+               -e "^author .*$" \
+               actual.blame >actual.grep &&
+       cut -d " " -f2-4 <actual.grep >actual.fuzz &&
        test_cmp expect actual.fuzz
 '
 
-cat >expect <<\EOF
-Some Dude <some@dude.xx>
-EOF
+test_expect_success 'Blame output (complex mapping)' '
+       git -c mailmap.file=complex.map blame one >a &&
+       git blame one >b &&
+       test_file_not_empty a &&
+       ! cmp a b
+'
 
 test_expect_success 'commit --author honors mailmap' '
+       test_config mailmap.file complex.map &&
+
+       cat >expect <<-\EOF &&
+       Some Dude <some@dude.xx>
+       EOF
+
        test_must_fail git commit --author "nick" --allow-empty -meight &&
        git commit --author "Some Dude" --allow-empty -meight &&
        git show --pretty=format:"%an <%ae>%n" >actual &&
        test_cmp expect actual
 '
 
+test_expect_success 'comment syntax: setup' '
+       test_create_repo comm &&
+       test_commit -C comm --author "A <a@example.com>" A &&
+       test_commit -C comm --author "B <b@example.com>" B &&
+       test_commit -C comm --author "C <#@example.com>" C &&
+       test_commit -C comm --author "D <d@e#ample.com>" D &&
+
+       test_config -C comm mailmap.file ../doc.map &&
+       cat >>doc.map <<-\EOF &&
+       # Ah <a@example.com>
+
+       ; Bee <b@example.com>
+       Cee <cee@example.com> <#@example.com>
+       Dee <dee@example.com> <d@e#ample.com>
+       EOF
+
+       cat >expect <<-\EOF &&
+       Author A <a@example.com> maps to A <a@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author B <b@example.com> maps to ; Bee <b@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author C <#@example.com> maps to Cee <cee@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author D <d@e#ample.com> maps to Dee <dee@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+       EOF
+       git -C comm log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'whitespace syntax: setup' '
+       test_create_repo space &&
+       test_commit -C space --author "A <a@example.com>" A &&
+       test_commit -C space --author "B <b@example.com>" B &&
+       test_commit -C space --author " C <c@example.com>" C &&
+       test_commit -C space --author " D  <d@example.com>" D &&
+       test_commit -C space --author "E E <e@example.com>" E &&
+       test_commit -C space --author "F  F <f@example.com>" F &&
+       test_commit -C space --author "G   G <g@example.com>" G &&
+       test_commit -C space --author "H   H <h@example.com>" H &&
+
+       test_config -C space mailmap.file ../space.map &&
+       cat >>space.map <<-\EOF &&
+       Ah <ah@example.com> < a@example.com >
+       Bee <bee@example.com  > <  b@example.com  >
+       Cee <cee@example.com> C <c@example.com>
+       dee <dee@example.com>  D  <d@example.com>
+       eee <eee@example.com> E E <e@example.com>
+       eff <eff@example.com> F  F <f@example.com>
+       gee <gee@example.com> G   G <g@example.com>
+       aitch <aitch@example.com> H  H <h@example.com>
+       EOF
+
+       cat >expect <<-\EOF &&
+       Author A <a@example.com> maps to A <a@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author B <b@example.com> maps to B <b@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author C <c@example.com> maps to Cee <cee@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author D <d@example.com> maps to dee <dee@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author E E <e@example.com> maps to eee <eee@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author F  F <f@example.com> maps to eff <eff@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author G   G <g@example.com> maps to gee <gee@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author H   H <h@example.com> maps to H   H <h@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+       EOF
+       git -C space log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'empty syntax: setup' '
+       test_create_repo empty &&
+       test_commit -C empty --author "A <>" A &&
+       test_commit -C empty --author "B <b@example.com>" B &&
+       test_commit -C empty --author "C <c@example.com>" C &&
+
+       test_config -C empty mailmap.file ../empty.map &&
+       cat >>empty.map <<-\EOF &&
+       Ah <ah@example.com> <>
+       Bee <bee@example.com> <>
+       Cee <> <c@example.com>
+       EOF
+
+       cat >expect <<-\EOF &&
+       Author A <> maps to Bee <bee@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author B <b@example.com> maps to B <b@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+
+       Author C <c@example.com> maps to C <c@example.com>
+       Committer C O Mitter <committer@example.com> maps to C O Mitter <committer@example.com>
+       EOF
+       git -C empty log --reverse --pretty=format:"Author %an <%ae> maps to %aN <%aE>%nCommitter %cn <%ce> maps to %cN <%cE>%n" >actual &&
+       test_cmp expect actual
+'
+
 test_done