Commit 983b8c2df818c92afa9b15041d3480b671b59a14

Nika Layzell 2018-03-17T18:15:41

mailmap: Add a bunch of tests for the new mailmap functionality

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
diff --git a/tests/mailmap/blame.c b/tests/mailmap/blame.c
new file mode 100644
index 0000000..2dd3095
--- /dev/null
+++ b/tests/mailmap/blame.c
@@ -0,0 +1,70 @@
+#include "clar_libgit2.h"
+#include "git2/repository.h"
+#include "git2/blame.h"
+#include "git2/mailmap.h"
+#include "mailmap_helpers.h"
+
+static git_repository *g_repo;
+static git_blame *g_blame;
+static git_mailmap *g_mailmap;
+
+void test_mailmap_blame__initialize(void)
+{
+	g_repo = NULL;
+	g_blame = NULL;
+}
+
+void test_mailmap_blame__cleanup(void)
+{
+	cl_git_sandbox_cleanup();
+	g_repo = NULL;
+
+	git_blame_free(g_blame);
+	g_blame = NULL;
+}
+
+void test_mailmap_blame__hunks(void)
+{
+	size_t idx = 0;
+	const git_blame_hunk *hunk = NULL;
+	git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
+
+	g_repo = cl_git_sandbox_init("mailmap");
+
+	opts.flags |= GIT_BLAME_USE_MAILMAP;
+
+	cl_check_pass(git_blame_file(&g_blame, g_repo, "file.txt", &opts));
+	if (!g_blame)
+		return;
+
+	for (idx = 0; idx < ARRAY_SIZE(resolved); ++idx) {
+		hunk = git_blame_get_hunk_byline(g_blame, idx + 1);
+
+		cl_assert(hunk->final_signature != NULL);
+		cl_assert(hunk->orig_signature != NULL);
+		cl_assert_equal_s(hunk->final_signature->name, resolved[idx].real_name);
+		cl_assert_equal_s(hunk->final_signature->email, resolved[idx].real_email);
+	}
+}
+
+void test_mailmap_blame__hunks_no_mailmap(void)
+{
+	size_t idx = 0;
+	const git_blame_hunk *hunk = NULL;
+	git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
+
+	g_repo = cl_git_sandbox_init("mailmap");
+
+	cl_check_pass(git_blame_file(&g_blame, g_repo, "file.txt", &opts));
+	if (!g_blame)
+		return;
+
+	for (idx = 0; idx < ARRAY_SIZE(resolved); ++idx) {
+		hunk = git_blame_get_hunk_byline(g_blame, idx + 1);
+
+		cl_assert(hunk->final_signature != NULL);
+		cl_assert(hunk->orig_signature != NULL);
+		cl_assert_equal_s(hunk->final_signature->name, resolved[idx].replace_name);
+		cl_assert_equal_s(hunk->final_signature->email, resolved[idx].replace_email);
+	}
+}
diff --git a/tests/mailmap/mailmap_helpers.h b/tests/mailmap/mailmap_helpers.h
new file mode 100644
index 0000000..49df55f
--- /dev/null
+++ b/tests/mailmap/mailmap_helpers.h
@@ -0,0 +1,52 @@
+#include "git2/mailmap.h"
+
+typedef struct mailmap_entry {
+	const char *real_name;
+	const char *real_email;
+	const char *replace_name;
+	const char *replace_email;
+} mailmap_entry;
+
+static const char string_mailmap[] =
+	"# Simple Comment line\n"
+	"<cto@company.xx>                       <cto@coompany.xx>\n"
+	"Some Dude <some@dude.xx>         nick1 <bugs@company.xx>\n"
+	"Other Author <other@author.xx>   nick2 <bugs@company.xx>\n"
+	"Other Author <other@author.xx>         <nick2@company.xx>\n"
+	"Phil Hill <phil@company.xx>  # Comment at end of line\n"
+	"<joseph@company.xx>             Joseph <bugs@company.xx>\n"
+	"Santa Claus <santa.claus@northpole.xx> <me@company.xx>\n"
+	"Untracked <untracked@company.xx>";
+
+static const mailmap_entry entries[] = {
+	{ NULL, "cto@company.xx", NULL, "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", NULL, "nick2@company.xx" },
+	{ "Phil Hill", NULL, NULL, "phil@company.xx" },
+	{ NULL, "joseph@company.xx", "Joseph", "bugs@company.xx" },
+	{ "Santa Claus", "santa.claus@northpole.xx", NULL, "me@company.xx" },
+	/* This entry isn't in the bare repository */
+	{ "Untracked", NULL, NULL, "untracked@company.xx" }
+};
+
+static const mailmap_entry resolved[] = {
+	{ "Brad", "cto@company.xx", "Brad", "cto@coompany.xx" },
+	{ "Brad L", "cto@company.xx", "Brad L", "cto@coompany.xx" },
+	{ "Some Dude", "some@dude.xx", "nick1", "bugs@company.xx" },
+	{ "Other Author", "other@author.xx", "nick2", "bugs@company.xx" },
+	{ "nick3", "bugs@company.xx", "nick3", "bugs@company.xx" },
+	{ "Other Author", "other@author.xx", "Some Garbage", "nick2@company.xx" },
+	{ "Phil Hill", "phil@company.xx", "unknown", "phil@company.xx" },
+	{ "Joseph", "joseph@company.xx", "Joseph", "bugs@company.xx" },
+	{ "Santa Claus", "santa.claus@northpole.xx", "Clause", "me@company.xx" },
+	{ "Charles", "charles@charles.xx", "Charles", "charles@charles.xx" }
+};
+
+static const mailmap_entry resolved_bare[] = {
+	{ "xx", "untracked@company.xx", "xx", "untracked@company.xx" }
+};
+
+static const mailmap_entry resolved_untracked[] = {
+	{ "Untracked", "untracked@company.xx", "xx", "untracked@company.xx" }
+};
diff --git a/tests/mailmap/parsing.c b/tests/mailmap/parsing.c
new file mode 100644
index 0000000..3fda25f
--- /dev/null
+++ b/tests/mailmap/parsing.c
@@ -0,0 +1,123 @@
+#include "clar_libgit2.h"
+#include "repository.h"
+#include "git2/sys/repository.h"
+#include "mailmap_helpers.h"
+
+static git_repository *g_repo;
+static git_mailmap *g_mailmap;
+
+void test_mailmap_parsing__initialize(void)
+{
+	g_repo = NULL;
+	g_mailmap = NULL;
+}
+
+void test_mailmap_parsing__cleanup(void)
+{
+	cl_git_sandbox_cleanup();
+	g_repo = NULL;
+
+	git_mailmap_free(g_mailmap);
+	g_mailmap = NULL;
+}
+
+static void check_mailmap_entries(
+	const git_mailmap *mailmap, const mailmap_entry *entries, size_t entries_size)
+{
+	const mailmap_entry *parsed = NULL;
+	size_t idx = 0;
+
+	/* Check that the parsed entries match */
+	cl_assert_equal_sz(entries_size, git_mailmap_entry_count(mailmap));
+	for (idx = 0; idx < entries_size; ++idx) {
+		parsed = git_mailmap_entry_byindex(mailmap, idx);
+		cl_assert_equal_s(parsed->real_name, entries[idx].real_name);
+		cl_assert_equal_s(parsed->real_email, entries[idx].real_email);
+		cl_assert_equal_s(parsed->replace_name, entries[idx].replace_name);
+		cl_assert_equal_s(parsed->replace_email, entries[idx].replace_email);
+	}
+}
+
+static void check_mailmap_resolve(
+	const git_mailmap *mailmap, const mailmap_entry *resolved, size_t resolved_size)
+{
+	const char *resolved_name = NULL;
+	const char *resolved_email = NULL;
+	size_t idx = 0;
+
+	/* Check that the resolver behaves correctly */
+	for (idx = 0; idx < resolved_size; ++idx) {
+		git_mailmap_resolve(
+			&resolved_name,
+			&resolved_email,
+			mailmap,
+			resolved[idx].replace_name,
+			resolved[idx].replace_email);
+		cl_assert_equal_s(resolved_name, resolved[idx].real_name);
+		cl_assert_equal_s(resolved_email, resolved[idx].real_email);
+	}
+}
+
+void test_mailmap_parsing__string(void)
+{
+	cl_check_pass(git_mailmap_parse(
+		&g_mailmap,
+		string_mailmap,
+		strlen(string_mailmap)));
+
+	/* We should have parsed all of the entries */
+	check_mailmap_entries(
+		g_mailmap,
+		entries, ARRAY_SIZE(entries));
+
+	/* Check that resolving the entries works */
+	check_mailmap_resolve(
+		g_mailmap,
+		resolved, ARRAY_SIZE(resolved));
+	check_mailmap_resolve(
+		g_mailmap,
+		resolved_untracked, ARRAY_SIZE(resolved_untracked));
+}
+
+void test_mailmap_parsing__fromrepo(void)
+{
+	g_repo = cl_git_sandbox_init("mailmap");
+	cl_check(!git_repository_is_bare(g_repo));
+
+	cl_check_pass(git_mailmap_from_repo(&g_mailmap, g_repo));
+
+	/* We should have parsed all of the entries */
+	check_mailmap_entries(
+		g_mailmap,
+		entries, ARRAY_SIZE(entries));
+
+	/* Check that resolving the entries works */
+	check_mailmap_resolve(
+		g_mailmap,
+		resolved, ARRAY_SIZE(resolved));
+	check_mailmap_resolve(
+		g_mailmap,
+		resolved_untracked, ARRAY_SIZE(resolved_untracked));
+}
+
+void test_mailmap_parsing__frombare(void)
+{
+	g_repo = cl_git_sandbox_init("mailmap/.gitted");
+	cl_check_pass(git_repository_set_bare(g_repo));
+	cl_check(git_repository_is_bare(g_repo));
+
+	cl_check_pass(git_mailmap_from_repo(&g_mailmap, g_repo));
+
+	/* We should have parsed all of the entries, except for the untracked one */
+	check_mailmap_entries(
+		g_mailmap,
+		entries, ARRAY_SIZE(entries) - 1);
+
+	/* Check that resolving the entries works */
+	check_mailmap_resolve(
+		g_mailmap,
+		resolved, ARRAY_SIZE(resolved));
+	check_mailmap_resolve(
+		g_mailmap,
+		resolved_bare, ARRAY_SIZE(resolved_bare));
+}
diff --git a/tests/resources/mailmap/.gitted/COMMIT_EDITMSG b/tests/resources/mailmap/.gitted/COMMIT_EDITMSG
new file mode 100644
index 0000000..14bee00
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/COMMIT_EDITMSG
@@ -0,0 +1 @@
++.mailmap
diff --git a/tests/resources/mailmap/.gitted/HEAD b/tests/resources/mailmap/.gitted/HEAD
new file mode 100644
index 0000000..cb089cd
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/mailmap/.gitted/config b/tests/resources/mailmap/.gitted/config
new file mode 100644
index 0000000..515f483
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/config
@@ -0,0 +1,5 @@
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = false
+	logallrefupdates = true
diff --git a/tests/resources/mailmap/.gitted/description b/tests/resources/mailmap/.gitted/description
new file mode 100644
index 0000000..498b267
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests/resources/mailmap/.gitted/hooks/applypatch-msg.sample b/tests/resources/mailmap/.gitted/hooks/applypatch-msg.sample
new file mode 100755
index 0000000..a5d7b84
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message taken by
+# applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.  The hook is
+# allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "applypatch-msg".
+
+. git-sh-setup
+commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
+test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
+:
diff --git a/tests/resources/mailmap/.gitted/hooks/commit-msg.sample b/tests/resources/mailmap/.gitted/hooks/commit-msg.sample
new file mode 100755
index 0000000..b58d118
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/commit-msg.sample
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# An example hook script to check the commit log message.
+# Called by "git commit" with one argument, the name of the file
+# that has the commit message.  The hook should exit with non-zero
+# status after issuing an appropriate message if it wants to stop the
+# commit.  The hook is allowed to edit the commit message file.
+#
+# To enable this hook, rename this file to "commit-msg".
+
+# Uncomment the below to add a Signed-off-by line to the message.
+# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
+# hook is more suited to it.
+#
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
+
+# This example catches duplicate Signed-off-by lines.
+
+test "" = "$(grep '^Signed-off-by: ' "$1" |
+	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
+	echo >&2 Duplicate Signed-off-by lines.
+	exit 1
+}
diff --git a/tests/resources/mailmap/.gitted/hooks/post-update.sample b/tests/resources/mailmap/.gitted/hooks/post-update.sample
new file mode 100755
index 0000000..ec17ec1
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/post-update.sample
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# An example hook script to prepare a packed repository for use over
+# dumb transports.
+#
+# To enable this hook, rename this file to "post-update".
+
+exec git update-server-info
diff --git a/tests/resources/mailmap/.gitted/hooks/pre-applypatch.sample b/tests/resources/mailmap/.gitted/hooks/pre-applypatch.sample
new file mode 100755
index 0000000..4142082
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/pre-applypatch.sample
@@ -0,0 +1,14 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed
+# by applypatch from an e-mail message.
+#
+# The hook should exit with non-zero status after issuing an
+# appropriate message if it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-applypatch".
+
+. git-sh-setup
+precommit="$(git rev-parse --git-path hooks/pre-commit)"
+test -x "$precommit" && exec "$precommit" ${1+"$@"}
+:
diff --git a/tests/resources/mailmap/.gitted/hooks/pre-commit.sample b/tests/resources/mailmap/.gitted/hooks/pre-commit.sample
new file mode 100755
index 0000000..68d62d5
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/pre-commit.sample
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by "git commit" with no arguments.  The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+if git rev-parse --verify HEAD >/dev/null 2>&1
+then
+	against=HEAD
+else
+	# Initial commit: diff against an empty tree object
+	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+# If you want to allow non-ASCII filenames set this variable to true.
+allownonascii=$(git config --bool hooks.allownonascii)
+
+# Redirect output to stderr.
+exec 1>&2
+
+# Cross platform projects tend to avoid non-ASCII filenames; prevent
+# them from being added to the repository. We exploit the fact that the
+# printable range starts at the space character and ends with tilde.
+if [ "$allownonascii" != "true" ] &&
+	# Note that the use of brackets around a tr range is ok here, (it's
+	# even required, for portability to Solaris 10's /usr/bin/tr), since
+	# the square bracket bytes happen to fall in the designated range.
+	test $(git diff --cached --name-only --diff-filter=A -z $against |
+	  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
+then
+	cat <<\EOF
+Error: Attempt to add a non-ASCII file name.
+
+This can cause problems if you want to work with people on other platforms.
+
+To be portable it is advisable to rename the file.
+
+If you know what you are doing you can disable this check using:
+
+  git config hooks.allownonascii true
+EOF
+	exit 1
+fi
+
+# If there are whitespace errors, print the offending file names and fail.
+exec git diff-index --check --cached $against --
diff --git a/tests/resources/mailmap/.gitted/hooks/pre-push.sample b/tests/resources/mailmap/.gitted/hooks/pre-push.sample
new file mode 100755
index 0000000..6187dbf
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/pre-push.sample
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+# An example hook script to verify what is about to be pushed.  Called by "git
+# push" after it has checked the remote status, but before anything has been
+# pushed.  If this script exits with a non-zero status nothing will be pushed.
+#
+# This hook is called with the following parameters:
+#
+# $1 -- Name of the remote to which the push is being done
+# $2 -- URL to which the push is being done
+#
+# If pushing without using a named remote those arguments will be equal.
+#
+# Information about the commits which are being pushed is supplied as lines to
+# the standard input in the form:
+#
+#   <local ref> <local sha1> <remote ref> <remote sha1>
+#
+# This sample shows how to prevent push of commits where the log message starts
+# with "WIP" (work in progress).
+
+remote="$1"
+url="$2"
+
+z40=0000000000000000000000000000000000000000
+
+while read local_ref local_sha remote_ref remote_sha
+do
+	if [ "$local_sha" = $z40 ]
+	then
+		# Handle delete
+		:
+	else
+		if [ "$remote_sha" = $z40 ]
+		then
+			# New branch, examine all commits
+			range="$local_sha"
+		else
+			# Update to existing branch, examine new commits
+			range="$remote_sha..$local_sha"
+		fi
+
+		# Check for WIP commit
+		commit=`git rev-list -n 1 --grep '^WIP' "$range"`
+		if [ -n "$commit" ]
+		then
+			echo >&2 "Found WIP commit in $local_ref, not pushing"
+			exit 1
+		fi
+	fi
+done
+
+exit 0
diff --git a/tests/resources/mailmap/.gitted/hooks/pre-rebase.sample b/tests/resources/mailmap/.gitted/hooks/pre-rebase.sample
new file mode 100755
index 0000000..33730ca
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/pre-rebase.sample
@@ -0,0 +1,169 @@
+#!/bin/sh
+#
+# Copyright (c) 2006, 2008 Junio C Hamano
+#
+# The "pre-rebase" hook is run just before "git rebase" starts doing
+# its job, and can prevent the command from running by exiting with
+# non-zero status.
+#
+# The hook is called with the following parameters:
+#
+# $1 -- the upstream the series was forked from.
+# $2 -- the branch being rebased (or empty when rebasing the current branch).
+#
+# This sample shows how to prevent topic branches that are already
+# merged to 'next' branch from getting rebased, because allowing it
+# would result in rebasing already published history.
+
+publish=next
+basebranch="$1"
+if test "$#" = 2
+then
+	topic="refs/heads/$2"
+else
+	topic=`git symbolic-ref HEAD` ||
+	exit 0 ;# we do not interrupt rebasing detached HEAD
+fi
+
+case "$topic" in
+refs/heads/??/*)
+	;;
+*)
+	exit 0 ;# we do not interrupt others.
+	;;
+esac
+
+# Now we are dealing with a topic branch being rebased
+# on top of master.  Is it OK to rebase it?
+
+# Does the topic really exist?
+git show-ref -q "$topic" || {
+	echo >&2 "No such branch $topic"
+	exit 1
+}
+
+# Is topic fully merged to master?
+not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
+if test -z "$not_in_master"
+then
+	echo >&2 "$topic is fully merged to master; better remove it."
+	exit 1 ;# we could allow it, but there is no point.
+fi
+
+# Is topic ever merged to next?  If so you should not be rebasing it.
+only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
+only_next_2=`git rev-list ^master           ${publish} | sort`
+if test "$only_next_1" = "$only_next_2"
+then
+	not_in_topic=`git rev-list "^$topic" master`
+	if test -z "$not_in_topic"
+	then
+		echo >&2 "$topic is already up-to-date with master"
+		exit 1 ;# we could allow it, but there is no point.
+	else
+		exit 0
+	fi
+else
+	not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
+	/usr/bin/perl -e '
+		my $topic = $ARGV[0];
+		my $msg = "* $topic has commits already merged to public branch:\n";
+		my (%not_in_next) = map {
+			/^([0-9a-f]+) /;
+			($1 => 1);
+		} split(/\n/, $ARGV[1]);
+		for my $elem (map {
+				/^([0-9a-f]+) (.*)$/;
+				[$1 => $2];
+			} split(/\n/, $ARGV[2])) {
+			if (!exists $not_in_next{$elem->[0]}) {
+				if ($msg) {
+					print STDERR $msg;
+					undef $msg;
+				}
+				print STDERR " $elem->[1]\n";
+			}
+		}
+	' "$topic" "$not_in_next" "$not_in_master"
+	exit 1
+fi
+
+<<\DOC_END
+
+This sample hook safeguards topic branches that have been
+published from being rewound.
+
+The workflow assumed here is:
+
+ * Once a topic branch forks from "master", "master" is never
+   merged into it again (either directly or indirectly).
+
+ * Once a topic branch is fully cooked and merged into "master",
+   it is deleted.  If you need to build on top of it to correct
+   earlier mistakes, a new topic branch is created by forking at
+   the tip of the "master".  This is not strictly necessary, but
+   it makes it easier to keep your history simple.
+
+ * Whenever you need to test or publish your changes to topic
+   branches, merge them into "next" branch.
+
+The script, being an example, hardcodes the publish branch name
+to be "next", but it is trivial to make it configurable via
+$GIT_DIR/config mechanism.
+
+With this workflow, you would want to know:
+
+(1) ... if a topic branch has ever been merged to "next".  Young
+    topic branches can have stupid mistakes you would rather
+    clean up before publishing, and things that have not been
+    merged into other branches can be easily rebased without
+    affecting other people.  But once it is published, you would
+    not want to rewind it.
+
+(2) ... if a topic branch has been fully merged to "master".
+    Then you can delete it.  More importantly, you should not
+    build on top of it -- other people may already want to
+    change things related to the topic as patches against your
+    "master", so if you need further changes, it is better to
+    fork the topic (perhaps with the same name) afresh from the
+    tip of "master".
+
+Let's look at this example:
+
+		   o---o---o---o---o---o---o---o---o---o "next"
+		  /       /           /           /
+		 /   a---a---b A     /           /
+		/   /               /           /
+	       /   /   c---c---c---c B         /
+	      /   /   /             \         /
+	     /   /   /   b---b C     \       /
+	    /   /   /   /             \     /
+    ---o---o---o---o---o---o---o---o---o---o---o "master"
+
+
+A, B and C are topic branches.
+
+ * A has one fix since it was merged up to "next".
+
+ * B has finished.  It has been fully merged up to "master" and "next",
+   and is ready to be deleted.
+
+ * C has not merged to "next" at all.
+
+We would want to allow C to be rebased, refuse A, and encourage
+B to be deleted.
+
+To compute (1):
+
+	git rev-list ^master ^topic next
+	git rev-list ^master        next
+
+	if these match, topic has not merged in next at all.
+
+To compute (2):
+
+	git rev-list master..topic
+
+	if this is empty, it is fully merged to "master".
+
+DOC_END
diff --git a/tests/resources/mailmap/.gitted/hooks/pre-receive.sample b/tests/resources/mailmap/.gitted/hooks/pre-receive.sample
new file mode 100755
index 0000000..a1fd29e
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/pre-receive.sample
@@ -0,0 +1,24 @@
+#!/bin/sh
+#
+# An example hook script to make use of push options.
+# The example simply echoes all push options that start with 'echoback='
+# and rejects all pushes when the "reject" push option is used.
+#
+# To enable this hook, rename this file to "pre-receive".
+
+if test -n "$GIT_PUSH_OPTION_COUNT"
+then
+	i=0
+	while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
+	do
+		eval "value=\$GIT_PUSH_OPTION_$i"
+		case "$value" in
+		echoback=*)
+			echo "echo from the pre-receive-hook: ${value#*=}" >&2
+			;;
+		reject)
+			exit 1
+		esac
+		i=$((i + 1))
+	done
+fi
diff --git a/tests/resources/mailmap/.gitted/hooks/prepare-commit-msg.sample b/tests/resources/mailmap/.gitted/hooks/prepare-commit-msg.sample
new file mode 100755
index 0000000..f093a02
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/prepare-commit-msg.sample
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# An example hook script to prepare the commit log message.
+# Called by "git commit" with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source.  The hook's purpose is to edit the commit
+# message file.  If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# To enable this hook, rename this file to "prepare-commit-msg".
+
+# This hook includes three examples.  The first comments out the
+# "Conflicts:" part of a merge commit.
+#
+# The second includes the output of "git diff --name-status -r"
+# into the message, just before the "git status" output.  It is
+# commented because it doesn't cope with --amend or with squashed
+# commits.
+#
+# The third example adds a Signed-off-by line to the message, that can
+# still be edited.  This is rarely a good idea.
+
+case "$2,$3" in
+  merge,)
+    /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
+
+# ,|template,)
+#   /usr/bin/perl -i.bak -pe '
+#      print "\n" . `git diff --cached --name-status -r`
+#	 if /^#/ && $first++ == 0' "$1" ;;
+
+  *) ;;
+esac
+
+# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff --git a/tests/resources/mailmap/.gitted/hooks/update.sample b/tests/resources/mailmap/.gitted/hooks/update.sample
new file mode 100755
index 0000000..80ba941
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/hooks/update.sample
@@ -0,0 +1,128 @@
+#!/bin/sh
+#
+# An example hook script to block unannotated tags from entering.
+# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
+#
+# To enable this hook, rename this file to "update".
+#
+# Config
+# ------
+# hooks.allowunannotated
+#   This boolean sets whether unannotated tags will be allowed into the
+#   repository.  By default they won't be.
+# hooks.allowdeletetag
+#   This boolean sets whether deleting tags will be allowed in the
+#   repository.  By default they won't be.
+# hooks.allowmodifytag
+#   This boolean sets whether a tag may be modified after creation. By default
+#   it won't be.
+# hooks.allowdeletebranch
+#   This boolean sets whether deleting branches will be allowed in the
+#   repository.  By default they won't be.
+# hooks.denycreatebranch
+#   This boolean sets whether remotely creating branches will be denied
+#   in the repository.  By default this is allowed.
+#
+
+# --- Command line
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+# --- Safety check
+if [ -z "$GIT_DIR" ]; then
+	echo "Don't run this script from the command line." >&2
+	echo " (if you want, you could supply GIT_DIR then run" >&2
+	echo "  $0 <ref> <oldrev> <newrev>)" >&2
+	exit 1
+fi
+
+if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
+	echo "usage: $0 <ref> <oldrev> <newrev>" >&2
+	exit 1
+fi
+
+# --- Config
+allowunannotated=$(git config --bool hooks.allowunannotated)
+allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
+denycreatebranch=$(git config --bool hooks.denycreatebranch)
+allowdeletetag=$(git config --bool hooks.allowdeletetag)
+allowmodifytag=$(git config --bool hooks.allowmodifytag)
+
+# check for no description
+projectdesc=$(sed -e '1q' "$GIT_DIR/description")
+case "$projectdesc" in
+"Unnamed repository"* | "")
+	echo "*** Project description file hasn't been set" >&2
+	exit 1
+	;;
+esac
+
+# --- Check types
+# if $newrev is 0000...0000, it's a commit to delete a ref.
+zero="0000000000000000000000000000000000000000"
+if [ "$newrev" = "$zero" ]; then
+	newrev_type=delete
+else
+	newrev_type=$(git cat-file -t $newrev)
+fi
+
+case "$refname","$newrev_type" in
+	refs/tags/*,commit)
+		# un-annotated tag
+		short_refname=${refname##refs/tags/}
+		if [ "$allowunannotated" != "true" ]; then
+			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
+			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,delete)
+		# delete tag
+		if [ "$allowdeletetag" != "true" ]; then
+			echo "*** Deleting a tag is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/tags/*,tag)
+		# annotated tag
+		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
+		then
+			echo "*** Tag '$refname' already exists." >&2
+			echo "*** Modifying a tag is not allowed in this repository." >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,commit)
+		# branch
+		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
+			echo "*** Creating a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/heads/*,delete)
+		# delete branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	refs/remotes/*,commit)
+		# tracking branch
+		;;
+	refs/remotes/*,delete)
+		# delete tracking branch
+		if [ "$allowdeletebranch" != "true" ]; then
+			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
+			exit 1
+		fi
+		;;
+	*)
+		# Anything else (is there anything else?)
+		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
+		exit 1
+		;;
+esac
+
+# --- Finished
+exit 0
diff --git a/tests/resources/mailmap/.gitted/index b/tests/resources/mailmap/.gitted/index
new file mode 100644
index 0000000..c46a1b4
Binary files /dev/null and b/tests/resources/mailmap/.gitted/index differ
diff --git a/tests/resources/mailmap/.gitted/info/exclude b/tests/resources/mailmap/.gitted/info/exclude
new file mode 100644
index 0000000..a5196d1
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/tests/resources/mailmap/.gitted/logs/HEAD b/tests/resources/mailmap/.gitted/logs/HEAD
new file mode 100644
index 0000000..53945f7
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/logs/HEAD
@@ -0,0 +1,11 @@
+0000000000000000000000000000000000000000 43179dc93939196f59b25387b5e44e9e8794f84c Nika Layzell <nika@thelayzells.com> 1521306034 -0400	commit (initial): Brad <cto@company.xx>
+43179dc93939196f59b25387b5e44e9e8794f84c 3a1295dbc9234c0c5947c72803618c7112a01447 Nika Layzell <nika@thelayzells.com> 1521306086 -0400	commit: Brad L. <cto@company.xx>
+3a1295dbc9234c0c5947c72803618c7112a01447 a7054a4b356b3ecdec60cee66e50beaa5b863755 Nika Layzell <nika@thelayzells.com> 1521306181 -0400	commit: Some Dude <some@dude.xx>
+a7054a4b356b3ecdec60cee66e50beaa5b863755 95d03c49d94de67d5a05553a1bb22e78f7cdf5ca Nika Layzell <nika@thelayzells.com> 1521306222 -0400	commit: Other Author <other@author.xx>
+95d03c49d94de67d5a05553a1bb22e78f7cdf5ca 1e1212e7674820c17f7b8797aee7bf38ece0e838 Nika Layzell <nika@thelayzells.com> 1521306263 -0400	commit: nick3 <bugs@company.xx>
+1e1212e7674820c17f7b8797aee7bf38ece0e838 3f134546ae8fbe95a39dd20ea8c12b5fb0f48afb Nika Layzell <nika@thelayzells.com> 1521306341 -0400	commit: Other Author <other@author.xx>
+3f134546ae8fbe95a39dd20ea8c12b5fb0f48afb 50d69f4e64be2cff2cedde8f9b7f970257caf4dd Nika Layzell <nika@thelayzells.com> 1521306417 -0400	commit: Phil Hill <phil@company.xx>
+50d69f4e64be2cff2cedde8f9b7f970257caf4dd feef8f2135df4835496e4d576b1f1bd23510e1c5 Nika Layzell <nika@thelayzells.com> 1521306468 -0400	commit: Joseph <joseph@company.xx>
+feef8f2135df4835496e4d576b1f1bd23510e1c5 7ecbb98d860b304f622b38ce9ab8f08d14d981a8 Nika Layzell <nika@thelayzells.com> 1521306510 -0400	commit: Santa Claus <santa.claus@northpole.xx>
+7ecbb98d860b304f622b38ce9ab8f08d14d981a8 87ce8d4920a30ddb9547334e7c65806518863ff1 Nika Layzell <nika@thelayzells.com> 1521306549 -0400	commit: Charles <charles@charles.xx>
+87ce8d4920a30ddb9547334e7c65806518863ff1 7100e631fb4d5deba31fdc8acc98f4fb5c1573fd Nika Layzell <nika@thelayzells.com> 1521306767 -0400	commit: +.mailmap
diff --git a/tests/resources/mailmap/.gitted/logs/refs/heads/master b/tests/resources/mailmap/.gitted/logs/refs/heads/master
new file mode 100644
index 0000000..53945f7
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/logs/refs/heads/master
@@ -0,0 +1,11 @@
+0000000000000000000000000000000000000000 43179dc93939196f59b25387b5e44e9e8794f84c Nika Layzell <nika@thelayzells.com> 1521306034 -0400	commit (initial): Brad <cto@company.xx>
+43179dc93939196f59b25387b5e44e9e8794f84c 3a1295dbc9234c0c5947c72803618c7112a01447 Nika Layzell <nika@thelayzells.com> 1521306086 -0400	commit: Brad L. <cto@company.xx>
+3a1295dbc9234c0c5947c72803618c7112a01447 a7054a4b356b3ecdec60cee66e50beaa5b863755 Nika Layzell <nika@thelayzells.com> 1521306181 -0400	commit: Some Dude <some@dude.xx>
+a7054a4b356b3ecdec60cee66e50beaa5b863755 95d03c49d94de67d5a05553a1bb22e78f7cdf5ca Nika Layzell <nika@thelayzells.com> 1521306222 -0400	commit: Other Author <other@author.xx>
+95d03c49d94de67d5a05553a1bb22e78f7cdf5ca 1e1212e7674820c17f7b8797aee7bf38ece0e838 Nika Layzell <nika@thelayzells.com> 1521306263 -0400	commit: nick3 <bugs@company.xx>
+1e1212e7674820c17f7b8797aee7bf38ece0e838 3f134546ae8fbe95a39dd20ea8c12b5fb0f48afb Nika Layzell <nika@thelayzells.com> 1521306341 -0400	commit: Other Author <other@author.xx>
+3f134546ae8fbe95a39dd20ea8c12b5fb0f48afb 50d69f4e64be2cff2cedde8f9b7f970257caf4dd Nika Layzell <nika@thelayzells.com> 1521306417 -0400	commit: Phil Hill <phil@company.xx>
+50d69f4e64be2cff2cedde8f9b7f970257caf4dd feef8f2135df4835496e4d576b1f1bd23510e1c5 Nika Layzell <nika@thelayzells.com> 1521306468 -0400	commit: Joseph <joseph@company.xx>
+feef8f2135df4835496e4d576b1f1bd23510e1c5 7ecbb98d860b304f622b38ce9ab8f08d14d981a8 Nika Layzell <nika@thelayzells.com> 1521306510 -0400	commit: Santa Claus <santa.claus@northpole.xx>
+7ecbb98d860b304f622b38ce9ab8f08d14d981a8 87ce8d4920a30ddb9547334e7c65806518863ff1 Nika Layzell <nika@thelayzells.com> 1521306549 -0400	commit: Charles <charles@charles.xx>
+87ce8d4920a30ddb9547334e7c65806518863ff1 7100e631fb4d5deba31fdc8acc98f4fb5c1573fd Nika Layzell <nika@thelayzells.com> 1521306767 -0400	commit: +.mailmap
diff --git a/tests/resources/mailmap/.gitted/objects/00/1387531bed84262f137837125d4d998a9ba65d b/tests/resources/mailmap/.gitted/objects/00/1387531bed84262f137837125d4d998a9ba65d
new file mode 100644
index 0000000..1c56490
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/00/1387531bed84262f137837125d4d998a9ba65d differ
diff --git a/tests/resources/mailmap/.gitted/objects/02/7b2816ae0d7a08ba656d0417c09b4eac18cf00 b/tests/resources/mailmap/.gitted/objects/02/7b2816ae0d7a08ba656d0417c09b4eac18cf00
new file mode 100644
index 0000000..a4e8249
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/02/7b2816ae0d7a08ba656d0417c09b4eac18cf00 differ
diff --git a/tests/resources/mailmap/.gitted/objects/09/20975110511365e56aec2263082d0c3d56d1fa b/tests/resources/mailmap/.gitted/objects/09/20975110511365e56aec2263082d0c3d56d1fa
new file mode 100644
index 0000000..49bceea
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/09/20975110511365e56aec2263082d0c3d56d1fa differ
diff --git a/tests/resources/mailmap/.gitted/objects/0c/d99501dfbec781a22ff7b84426b7bb308e709a b/tests/resources/mailmap/.gitted/objects/0c/d99501dfbec781a22ff7b84426b7bb308e709a
new file mode 100644
index 0000000..23149a4
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/0c/d99501dfbec781a22ff7b84426b7bb308e709a differ
diff --git a/tests/resources/mailmap/.gitted/objects/1e/1212e7674820c17f7b8797aee7bf38ece0e838 b/tests/resources/mailmap/.gitted/objects/1e/1212e7674820c17f7b8797aee7bf38ece0e838
new file mode 100644
index 0000000..89a8598
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/1e/1212e7674820c17f7b8797aee7bf38ece0e838
@@ -0,0 +1,2 @@
+xu]
+0})f7iZ(;l#5zz|LDZ/@B:i8bc163,:h|BIKZ,49Ĕ}#rxeh~x{>`=YƊ*-:D뱢Q^ohUEq߭3d>I
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/36/370b71f5aad1dd46bec5e14145280a843c9f49 b/tests/resources/mailmap/.gitted/objects/36/370b71f5aad1dd46bec5e14145280a843c9f49
new file mode 100644
index 0000000..5e8e3e5
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/36/370b71f5aad1dd46bec5e14145280a843c9f49 differ
diff --git a/tests/resources/mailmap/.gitted/objects/3a/1295dbc9234c0c5947c72803618c7112a01447 b/tests/resources/mailmap/.gitted/objects/3a/1295dbc9234c0c5947c72803618c7112a01447
new file mode 100644
index 0000000..347828c
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/3a/1295dbc9234c0c5947c72803618c7112a01447
@@ -0,0 +1,2 @@
+xmA
+0D]$m(";$??(-dV34*(V0.>H	#TQEeNd+"t]j]P}hvl{g5$s]0P[yVRY?<0̋#,?s!5_ԏ$^H
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/3f/134546ae8fbe95a39dd20ea8c12b5fb0f48afb b/tests/resources/mailmap/.gitted/objects/3f/134546ae8fbe95a39dd20ea8c12b5fb0f48afb
new file mode 100644
index 0000000..489c610
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/3f/134546ae8fbe95a39dd20ea8c12b5fb0f48afb
@@ -0,0 +1,3 @@
+xmMn0) {lbGB(Teqcd\	zze^H<@s("6<{5G[t6PkqK
+mq(zg[K̶"Kv	-;ʞ~FBﴼ	6
+vH)jX5iZёri3Zp֏iUeoO
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/43/179dc93939196f59b25387b5e44e9e8794f84c b/tests/resources/mailmap/.gitted/objects/43/179dc93939196f59b25387b5e44e9e8794f84c
new file mode 100644
index 0000000..2f3693a
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/43/179dc93939196f59b25387b5e44e9e8794f84c
@@ -0,0 +1,2 @@
+xmA
+0P9\4"ŵx1bHzzp?laP6.'f-+ԕcU-:|ƋLCA<D:coc7bYP5^¾	D듧	yK}xb_ˈA:
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/46/b5bb908c78b575cac9f9e6e42ff9ba3f769a46 b/tests/resources/mailmap/.gitted/objects/46/b5bb908c78b575cac9f9e6e42ff9ba3f769a46
new file mode 100644
index 0000000..62c9db0
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/46/b5bb908c78b575cac9f9e6e42ff9ba3f769a46 differ
diff --git a/tests/resources/mailmap/.gitted/objects/4b/4d2010ba256ef339c1d1854d20249da7478f01 b/tests/resources/mailmap/.gitted/objects/4b/4d2010ba256ef339c1d1854d20249da7478f01
new file mode 100644
index 0000000..169c7e7
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/4b/4d2010ba256ef339c1d1854d20249da7478f01 differ
diff --git a/tests/resources/mailmap/.gitted/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 b/tests/resources/mailmap/.gitted/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904
new file mode 100644
index 0000000..adf6411
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/4b/825dc642cb6eb9a060e54bf8d69288fbee4904 differ
diff --git a/tests/resources/mailmap/.gitted/objects/4d/61d588546529ad27b2d77a3d6b05460ecb4be0 b/tests/resources/mailmap/.gitted/objects/4d/61d588546529ad27b2d77a3d6b05460ecb4be0
new file mode 100644
index 0000000..dabbf4e
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/4d/61d588546529ad27b2d77a3d6b05460ecb4be0 differ
diff --git a/tests/resources/mailmap/.gitted/objects/50/d69f4e64be2cff2cedde8f9b7f970257caf4dd b/tests/resources/mailmap/.gitted/objects/50/d69f4e64be2cff2cedde8f9b7f970257caf4dd
new file mode 100644
index 0000000..e6b337e
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/50/d69f4e64be2cff2cedde8f9b7f970257caf4dd
@@ -0,0 +1 @@
+xmMj0)	HcBY+6e(Qt~>ym>&&ޓ=gOĞRBֹ6Zy\&c%(-mpFJQ'8Eŷ2,%/uS+8!4V7xiaVdϗLrU2k\z`KN
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/61/293f4c3d7500d227a755a7a8258e28e53449b2 b/tests/resources/mailmap/.gitted/objects/61/293f4c3d7500d227a755a7a8258e28e53449b2
new file mode 100644
index 0000000..409e6fd
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/61/293f4c3d7500d227a755a7a8258e28e53449b2 differ
diff --git a/tests/resources/mailmap/.gitted/objects/62/7f0bd2f4fb5e949b79ba450d84676fa876b1c8 b/tests/resources/mailmap/.gitted/objects/62/7f0bd2f4fb5e949b79ba450d84676fa876b1c8
new file mode 100644
index 0000000..6009c30
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/62/7f0bd2f4fb5e949b79ba450d84676fa876b1c8 differ
diff --git a/tests/resources/mailmap/.gitted/objects/68/dfd5e5cb6138488680246d134f47ce559f4cf1 b/tests/resources/mailmap/.gitted/objects/68/dfd5e5cb6138488680246d134f47ce559f4cf1
new file mode 100644
index 0000000..ac5229f
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/68/dfd5e5cb6138488680246d134f47ce559f4cf1 differ
diff --git a/tests/resources/mailmap/.gitted/objects/6c/dec08ab9bfcd5a3d889f27bbed650317e3ec13 b/tests/resources/mailmap/.gitted/objects/6c/dec08ab9bfcd5a3d889f27bbed650317e3ec13
new file mode 100644
index 0000000..856ba31
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/6c/dec08ab9bfcd5a3d889f27bbed650317e3ec13 differ
diff --git a/tests/resources/mailmap/.gitted/objects/71/00e631fb4d5deba31fdc8acc98f4fb5c1573fd b/tests/resources/mailmap/.gitted/objects/71/00e631fb4d5deba31fdc8acc98f4fb5c1573fd
new file mode 100644
index 0000000..3b20e6d
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/71/00e631fb4d5deba31fdc8acc98f4fb5c1573fd differ
diff --git a/tests/resources/mailmap/.gitted/objects/7e/cbb98d860b304f622b38ce9ab8f08d14d981a8 b/tests/resources/mailmap/.gitted/objects/7e/cbb98d860b304f622b38ce9ab8f08d14d981a8
new file mode 100644
index 0000000..53e775e
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/7e/cbb98d860b304f622b38ce9ab8f08d14d981a8 differ
diff --git a/tests/resources/mailmap/.gitted/objects/7e/e7b9a4a2a1eda925f6260338c063d8211d5ad5 b/tests/resources/mailmap/.gitted/objects/7e/e7b9a4a2a1eda925f6260338c063d8211d5ad5
new file mode 100644
index 0000000..0d4e94b
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/7e/e7b9a4a2a1eda925f6260338c063d8211d5ad5
@@ -0,0 +1,2 @@
+x
+0D=+z* =~AFMMA޴m'sag+
XgEB[o$dtF;0(d=wb\R8k̫('8-Xޚk:
9ʋGmr</ ]hHS?9.p
o3KљQ'"
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/83/714a9223f3e072b85f0d4301cd2081fff3acf2 b/tests/resources/mailmap/.gitted/objects/83/714a9223f3e072b85f0d4301cd2081fff3acf2
new file mode 100644
index 0000000..a50f87e
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/83/714a9223f3e072b85f0d4301cd2081fff3acf2 differ
diff --git a/tests/resources/mailmap/.gitted/objects/87/ce8d4920a30ddb9547334e7c65806518863ff1 b/tests/resources/mailmap/.gitted/objects/87/ce8d4920a30ddb9547334e7c65806518863ff1
new file mode 100644
index 0000000..b8c4808
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/87/ce8d4920a30ddb9547334e7c65806518863ff1
@@ -0,0 +1,2 @@
+x}NKjC1ڧd?=[PݖAe^KRt5f)0 >n1ZCeʚ
+XbM8E݇t;
HVT3WR!Ų(7fN>rH_ _^'3e !nXûܾl]awXl}=GW=MV
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/8c/f0547fcb649b44ebaf39b8104982bb0abb4e69 b/tests/resources/mailmap/.gitted/objects/8c/f0547fcb649b44ebaf39b8104982bb0abb4e69
new file mode 100644
index 0000000..402a48e
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/8c/f0547fcb649b44ebaf39b8104982bb0abb4e69 differ
diff --git a/tests/resources/mailmap/.gitted/objects/94/7ff75c33ac7941a32fe9900118b6ba85ab2be9 b/tests/resources/mailmap/.gitted/objects/94/7ff75c33ac7941a32fe9900118b6ba85ab2be9
new file mode 100644
index 0000000..8b23320
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/94/7ff75c33ac7941a32fe9900118b6ba85ab2be9 differ
diff --git a/tests/resources/mailmap/.gitted/objects/95/d03c49d94de67d5a05553a1bb22e78f7cdf5ca b/tests/resources/mailmap/.gitted/objects/95/d03c49d94de67d5a05553a1bb22e78f7cdf5ca
new file mode 100644
index 0000000..cd91a3f
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/95/d03c49d94de67d5a05553a1bb22e78f7cdf5ca
@@ -0,0 +1 @@
+xmKn0D)x$R`h@tcğ@Qo7۲L/B Ad;s7I؏2.Vh1p$^fYHъ2t#[=m)ry[.>%`ia;Vtfǯ3kSC=CxWs|L
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/96/78a4325710507f7bf598a0fde5ebbd88148614 b/tests/resources/mailmap/.gitted/objects/96/78a4325710507f7bf598a0fde5ebbd88148614
new file mode 100644
index 0000000..8874366
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/96/78a4325710507f7bf598a0fde5ebbd88148614 differ
diff --git a/tests/resources/mailmap/.gitted/objects/a1/6db1cbb8817dddcf199c12d3c81221cf8eefc4 b/tests/resources/mailmap/.gitted/objects/a1/6db1cbb8817dddcf199c12d3c81221cf8eefc4
new file mode 100644
index 0000000..d23d8cc
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/a1/6db1cbb8817dddcf199c12d3c81221cf8eefc4
@@ -0,0 +1 @@
+x+)JMU06c040031QHI+(aUإV_+
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/a7/054a4b356b3ecdec60cee66e50beaa5b863755 b/tests/resources/mailmap/.gitted/objects/a7/054a4b356b3ecdec60cee66e50beaa5b863755
new file mode 100644
index 0000000..06a3abc
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/a7/054a4b356b3ecdec60cee66e50beaa5b863755
@@ -0,0 +1,3 @@
+xmNKj0Z4I`]lz44&[Jٽ/e
+G]E$|bIH].1!ՍW+&]I9jc3f^4G
+iF+eYaKe8' `|ETlǪpqnn_vh7uL_{zPG
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/objects/a7/eb40274887baeb01a958ead80d106b5977312c b/tests/resources/mailmap/.gitted/objects/a7/eb40274887baeb01a958ead80d106b5977312c
new file mode 100644
index 0000000..39f70c2
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/a7/eb40274887baeb01a958ead80d106b5977312c differ
diff --git a/tests/resources/mailmap/.gitted/objects/c9/e5462de8ec453e94d85f26f64b80ea76fda6d4 b/tests/resources/mailmap/.gitted/objects/c9/e5462de8ec453e94d85f26f64b80ea76fda6d4
new file mode 100644
index 0000000..dbf9523
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/c9/e5462de8ec453e94d85f26f64b80ea76fda6d4 differ
diff --git a/tests/resources/mailmap/.gitted/objects/d3/e5e624cc7bfb09ac1960ebb6c458021b098f87 b/tests/resources/mailmap/.gitted/objects/d3/e5e624cc7bfb09ac1960ebb6c458021b098f87
new file mode 100644
index 0000000..c69ebe8
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/d3/e5e624cc7bfb09ac1960ebb6c458021b098f87 differ
diff --git a/tests/resources/mailmap/.gitted/objects/fe/dd34e8baffdb2acfe9a6860bf339287ca942bc b/tests/resources/mailmap/.gitted/objects/fe/dd34e8baffdb2acfe9a6860bf339287ca942bc
new file mode 100644
index 0000000..a13b83d
Binary files /dev/null and b/tests/resources/mailmap/.gitted/objects/fe/dd34e8baffdb2acfe9a6860bf339287ca942bc differ
diff --git a/tests/resources/mailmap/.gitted/objects/fe/ef8f2135df4835496e4d576b1f1bd23510e1c5 b/tests/resources/mailmap/.gitted/objects/fe/ef8f2135df4835496e4d576b1f1bd23510e1c5
new file mode 100644
index 0000000..31f979b
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/objects/fe/ef8f2135df4835496e4d576b1f1bd23510e1c5
@@ -0,0 +1 @@
+xmK1]u%J
22/#7(4,`2x-QR)-+Thu#Aیi᱀U똳7
>^j#eLIЭti幃}}8
3jeCVYΗ=:j%]Ŀ,pK
\ No newline at end of file
diff --git a/tests/resources/mailmap/.gitted/refs/heads/master b/tests/resources/mailmap/.gitted/refs/heads/master
new file mode 100644
index 0000000..0daf56a
--- /dev/null
+++ b/tests/resources/mailmap/.gitted/refs/heads/master
@@ -0,0 +1 @@
+7100e631fb4d5deba31fdc8acc98f4fb5c1573fd
diff --git a/tests/resources/mailmap/.mailmap b/tests/resources/mailmap/.mailmap
new file mode 100644
index 0000000..7da2ed6
--- /dev/null
+++ b/tests/resources/mailmap/.mailmap
@@ -0,0 +1,9 @@
+# Simple Comment line
+<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>
+Phil Hill <phil@company.xx>  # Comment at end of line
+<joseph@company.xx>             Joseph <bugs@company.xx>
+Santa Claus <santa.claus@northpole.xx> <me@company.xx>
+Untracked <untracked@company.xx>
diff --git a/tests/resources/mailmap/file.txt b/tests/resources/mailmap/file.txt
new file mode 100644
index 0000000..68dfd5e
--- /dev/null
+++ b/tests/resources/mailmap/file.txt
@@ -0,0 +1,10 @@
+Added by Brad <cto@coompany.xx>
+Added by Brad L. <cto@coompany.xx>
+Added by nick1 <bugs@company.xx>
+Added by nick2 <bugs@company.xx>
+Added by nick3 <bugs@company.xx>
+Added by Some Garbage <nick2@company.xx>
+Added by unknown <phil@company.xx>
+Added by Joseph <bugs@company.xx>
+Added by Clause <me@company.xx>
+Added by Charles <charles@charles.xx>