1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2024 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // gitdll.cpp : Defines the exported functions for the DLL application.
23 #include "../build/libgit-defines.h"
25 #pragma warning(disable: 4100 4267)
26 #include "git-compat-util.h"
28 #include "read-cache.h"
29 #include "object-name.h"
41 #include "environment.h"
48 extern char g_last_error
[];
49 static const char* g_prefix
;
51 /* also see GitHash.h */
52 static_assert(GIT_SHA1_RAWSZ
<= LIBGIT_GIT_HASH_SIZE
&& GIT_SHA256_RAWSZ
<= LIBGIT_GIT_HASH_SIZE
&& GIT_MAX_RAWSZ
== LIBGIT_GIT_HASH_SIZE
, "Required to be equal in gitdll.h");
53 static_assert(sizeof(struct object_id
) == sizeof(struct GIT_OBJECT_OID
), "Required to be equal in gitdll.h");
55 extern NORETURN
void die_dll(const char* err
, va_list params
);
56 extern void handle_error(const char* err
, va_list params
);
57 extern void handle_warning(const char* warn
, va_list params
);
58 extern int die_is_recursing_dll(void);
60 extern void libgit_initialize(void);
61 extern void cleanup_chdir_notify(void);
62 extern void free_all_pack(void);
63 extern void reset_git_env(const LPWSTR
*);
64 extern void drop_all_attr_stacks(void);
65 extern void git_atexit_dispatch(void);
66 extern void git_atexit_clear(void);
67 extern void invalidate_ref_cache(void);
68 extern void clear_ref_decorations(void);
69 extern void cmd_log_init(int argc
, const char** argv
, const char* prefix
, struct rev_info
* rev
, struct setup_revision_opt
* opt
);
70 extern int estimate_commit_count(struct commit_list
* list
);
71 extern int log_tree_commit(struct rev_info
*, struct commit
*);
72 extern int write_entry(struct cache_entry
* ce
, char* path
, struct conv_attrs
* ca
, const struct checkout
* state
, int to_tempfile
, int* nr_checkouts
);
73 extern void diff_flush_stat(struct diff_filepair
* p
, struct diff_options
* o
, struct diffstat_t
* diffstat
);
74 extern void free_diffstat_info(struct diffstat_t
* diffstat
);
75 static_assert(sizeof(unsigned long long) == sizeof(timestamp_t
), "Required for each_reflog_ent_fn definition in gitdll.h");
76 extern int for_each_reflog_ent(const char* refname
, each_reflog_ent_fn fn
, void* cb_data
);
80 set_die_routine(die_dll
);
81 set_error_routine(handle_error
);
82 set_warn_routine(handle_warning
);
83 set_die_is_recursing_routine(die_is_recursing_dll
);
87 int git_get_sha1(const char *name
, GIT_HASH sha1
)
89 struct object_id oid
= { 0 };
90 int ret
= repo_get_oid(the_repository
, name
, &oid
);
91 hashcpy(sha1
, oid
.hash
);
95 int git_init(const LPWSTR
* env
)
98 _setmode(_fileno(stdin
), _O_BINARY
);
99 _setmode(_fileno(stdout
), _O_BINARY
);
100 _setmode(_fileno(stderr
), _O_BINARY
);
102 cleanup_chdir_notify();
105 assert(getenv("HOME")); // make sure HOME is already set
106 drop_all_attr_stacks();
108 g_prefix
= setup_git_directory();
109 git_config(git_default_config
, NULL
);
110 invalidate_ref_cache();
111 clear_ref_decorations();
113 /* add a safeguard until we have full support in TortoiseGit */
114 if (the_repository
&& the_repository
->hash_algo
&& strcmp(the_repository
->hash_algo
->name
, "sha1") != 0)
115 die("Only SHA1 is supported right now.");
120 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR
* author
, const char* pbuff
)
124 end
=strchr(pbuff
,'<');
125 if (!end
|| end
- pbuff
- 1 >= INT_MAX
)
127 author
->Name
= pbuff
;
128 author
->NameSize
= (int)(end
- pbuff
- 1);
131 end
= strchr(pbuff
, '>');
132 if (!end
|| end
[1] != ' ' || end
- pbuff
>= INT_MAX
)
134 author
->Email
= pbuff
;
135 author
->EmailSize
= (int)(end
- pbuff
);
139 author
->Date
= parse_timestamp(pbuff
, &end
, 10);
140 if (end
== pbuff
|| !end
|| *end
!= ' ' || end
[1] != '+' && end
[1] != '-' || !isdigit(end
[2]) || !isdigit(end
[3]) || !isdigit(end
[4]) || !isdigit(end
[5]))
143 author
->TimeZone
= strtol(pbuff
, NULL
, 10);
148 int git_parse_commit(GIT_COMMIT
*commit
)
155 p
= (struct commit
*)commit
->m_pGitCommit
;
157 memcpy(commit
->m_hash
, p
->object
.oid
.hash
, GIT_SHA1_RAWSZ
);
159 commit
->m_Encode
= NULL
;
160 commit
->m_EncodeSize
= 0;
162 commit
->buffer
= detach_commit_buffer(commit
->m_pGitCommit
, NULL
);
164 pbuf
= commit
->buffer
;
167 if (strncmp(pbuf
, "author ", strlen("author ")) == 0)
169 ret
= git_parse_commit_author(&commit
->m_Author
, pbuf
+ strlen("author "));
173 else if (strncmp(pbuf
, "committer ", strlen("committer ")) == 0)
175 ret
= git_parse_commit_author(&commit
->m_Committer
, pbuf
+ strlen("committer "));
179 pbuf
= strchr(pbuf
,'\n');
183 else if (strncmp(pbuf
, "encoding ", strlen("encoding ")) == 0)
185 pbuf
+= strlen("encoding ");
186 commit
->m_Encode
=pbuf
;
187 end
= strchr(pbuf
,'\n');
188 if (!pbuf
|| end
- pbuf
>= INT_MAX
)
190 commit
->m_EncodeSize
= (int)(end
-pbuf
);
193 // the headers end after the first empty line
194 else if (*pbuf
== '\n')
198 commit
->m_Subject
=pbuf
;
199 end
= strchr(pbuf
,'\n');
202 size_t subjLen
= strlen(pbuf
);
203 if (subjLen
>= INT_MAX
)
205 commit
->m_SubjectSize
= (int)subjLen
;
210 if (end
- pbuf
>= INT_MAX
)
212 commit
->m_SubjectSize
= (int)(end
- pbuf
);
214 commit
->m_Body
= pbuf
;
215 bodyLen
= strlen(pbuf
);
216 if (bodyLen
>= INT_MAX
)
218 commit
->m_BodySize
= (int)bodyLen
;
223 pbuf
= strchr(pbuf
,'\n');
230 int git_get_commit_from_hash(GIT_COMMIT
* commit
, const GIT_HASH hash
)
235 struct object_id oid
;
240 memset(commit
,0,sizeof(GIT_COMMIT
));
242 hashcpy(oid
.hash
, hash
);
245 commit
->m_pGitCommit
= p
= lookup_commit(the_repository
, &oid
);
250 ret
= repo_parse_commit(the_repository
, p
);
254 return git_parse_commit(commit
);
257 int git_get_commit_first_parent(const GIT_COMMIT
* commit
, GIT_COMMIT_LIST
* list
)
259 struct commit
*p
= commit
->m_pGitCommit
;
264 *list
= (GIT_COMMIT_LIST
*)p
->parents
;
268 int git_commit_is_root(const GIT_COMMIT
* commit
)
270 struct commit
* p
= commit
->m_pGitCommit
;
271 return (struct commit_list
**)p
->parents
? 1 : 0;
274 int git_get_commit_next_parent(GIT_COMMIT_LIST
*list
, GIT_HASH hash
)
276 struct commit_list
*l
;
280 l
= *(struct commit_list
**)list
;
285 memcpy(hash
, l
->item
->object
.oid
.hash
, GIT_SHA1_RAWSZ
);
287 *list
= (GIT_COMMIT_LIST
*)l
->next
;
293 int git_free_commit(GIT_COMMIT
*commit
)
295 struct commit
*p
= commit
->m_pGitCommit
;
298 free_commit_list(p
->parents
);
301 free_tree_buffer(p
->maybe_tree
);
303 free_commit_buffer(the_repository
->parsed_objects
, p
);
304 free((void*)commit
->buffer
);
306 p
->object
.parsed
= 0;
308 p
->maybe_tree
= NULL
;
310 memset(commit
,0,sizeof(GIT_COMMIT
));
314 static char** strtoargv(const char* arg
, int* size
)
317 const char* parg
= arg
;
328 assert(*parg
!= '\\' && "no backslashes allowed, use a Git path (with slashes) - no escaping of chars possible");
332 argv
= malloc(strlen(arg
) + 2 + (count
+ 3) * sizeof(char*)); // 1 char* for every parameter + 1 for argv[0] + 1 NULL as end end; and some space for the actual parameters: strlen() + 1 for \0, + 1 for \0 for argv[0]
335 p
= (char*)(argv
+ count
+ 3);
358 if (*parg
== space
|| !*parg
)
374 int git_open_log(GIT_LOG
* handle
, const char* arg
)
376 struct rev_info
*p_Rev
;
379 struct setup_revision_opt opt
;
382 unsigned int obj_size
= get_max_object_index();
383 for (unsigned int i
= 0; i
< obj_size
; ++i
)
385 struct object
*ob
= get_indexed_object(i
);
389 if (ob
->parsed
&& ob
->type
== OBJ_COMMIT
)
391 struct commit
* commit
= (struct commit
*)ob
;
392 free_commit_list(commit
->parents
);
393 commit
->parents
= NULL
;
394 if (commit
->maybe_tree
)
395 free_tree_buffer(commit
->maybe_tree
);
396 commit
->maybe_tree
= NULL
;
402 argv
= strtoargv(arg
, &argc
);
406 p_Rev
= malloc(sizeof(struct rev_info
));
413 memset(p_Rev
,0,sizeof(struct rev_info
));
415 invalidate_ref_cache();
416 clear_ref_decorations();
418 repo_init_revisions(the_repository
, p_Rev
, g_prefix
);
421 memset(&opt
, 0, sizeof(opt
));
424 cmd_log_init(argc
, argv
, g_prefix
,p_Rev
,&opt
);
426 p_Rev
->pPrivate
= argv
;
431 int git_get_log_firstcommit(GIT_LOG handle
)
433 return prepare_revision_walk(handle
);
436 int git_get_log_estimate_commit_count(GIT_LOG handle
)
438 struct rev_info
*p_Rev
;
439 p_Rev
=(struct rev_info
*)handle
;
441 return estimate_commit_count(p_Rev
->commits
);
444 int git_get_log_nextcommit(GIT_LOG handle
, GIT_COMMIT
*commit
, int follow
)
451 memset(commit
, 0, sizeof(GIT_COMMIT
));
453 commit
->m_pGitCommit
= get_revision(handle
);
454 if( commit
->m_pGitCommit
== NULL
)
459 struct rev_info
* p_Rev
= (struct rev_info
*)handle
;
460 p_Rev
->diffopt
.no_free
= 1;
461 if (!log_tree_commit(handle
, commit
->m_pGitCommit
))
463 commit
->m_ignore
= 1;
467 commit
->m_ignore
= 0;
469 ret
=git_parse_commit(commit
);
476 struct notes_tree
**display_notes_trees
;
477 int git_close_log(GIT_LOG handle
, int releaseRevsisions
)
481 struct rev_info
*p_Rev
;
482 p_Rev
=(struct rev_info
*)handle
;
483 p_Rev
->diffopt
.no_free
= 0;
484 if (releaseRevsisions
)
485 release_revisions(p_Rev
);
486 diff_free(&p_Rev
->diffopt
);
487 free(p_Rev
->pPrivate
);
492 if (display_notes_trees
)
493 free_notes(*display_notes_trees
);
494 display_notes_trees
= 0;
498 int git_open_diff(GIT_DIFF
* diff
, const char* arg
)
500 struct rev_info
*p_Rev
;
504 argv
= strtoargv(arg
, &argc
);
508 p_Rev
= malloc(sizeof(struct rev_info
));
511 memset(p_Rev
,0,sizeof(struct rev_info
));
513 p_Rev
->pPrivate
= argv
;
514 *diff
= (GIT_DIFF
)p_Rev
;
516 repo_init_revisions(the_repository
, p_Rev
, g_prefix
);
517 git_config(git_diff_basic_config
, NULL
); /* no "diff" UI options */
520 argc
= setup_revisions(argc
, argv
, p_Rev
, NULL
);
524 int git_close_diff(GIT_DIFF handle
)
526 git_diff_flush(handle
);
529 struct rev_info
*p_Rev
;
530 p_Rev
=(struct rev_info
*)handle
;
531 free(p_Rev
->pPrivate
);
536 int git_diff_flush(GIT_DIFF diff
)
538 struct diff_queue_struct
*q
= &diff_queued_diff
;
539 struct rev_info
*p_Rev
;
540 p_Rev
= (struct rev_info
*)diff
;
545 for (int i
= 0; i
< q
->nr
; ++i
)
546 diff_free_filepair(q
->queue
[i
]);
552 q
->nr
= q
->alloc
= 0;
555 if (p_Rev
->diffopt
.close_file
)
556 fclose(p_Rev
->diffopt
.file
);
558 free_diffstat_info(&p_Rev
->diffstat
);
562 int git_root_diff(GIT_DIFF diff
, const GIT_HASH hash
, GIT_FILE
* file
, int* count
, int isstat
)
564 struct object_id oid
= { 0 };
565 struct rev_info
*p_Rev
;
566 struct diff_queue_struct
*q
= &diff_queued_diff
;
568 p_Rev
= (struct rev_info
*)diff
;
570 hashcpy(oid
.hash
, hash
);
572 diff_root_tree_oid(&oid
, "", &p_Rev
->diffopt
);
576 diffcore_std(&p_Rev
->diffopt
);
578 memset(&p_Rev
->diffstat
, 0, sizeof(struct diffstat_t
));
579 for (int i
= 0; i
< q
->nr
; ++i
) {
580 struct diff_filepair
*p
= q
->queue
[i
];
581 //if (check_pair_status(p))
582 diff_flush_stat(p
, &p_Rev
->diffopt
, &p_Rev
->diffstat
);
594 int git_do_diff(GIT_DIFF diff
, const GIT_HASH hash1
, const GIT_HASH hash2
, GIT_FILE
* file
, int* count
, int isstat
)
596 struct rev_info
*p_Rev
;
597 struct object_id oid1
, oid2
;
598 struct diff_queue_struct
*q
= &diff_queued_diff
;
600 p_Rev
= (struct rev_info
*)diff
;
602 hashcpy(oid1
.hash
, hash1
);
604 hashcpy(oid2
.hash
, hash2
);
607 diff_tree_oid(&oid1
, &oid2
, "", &p_Rev
->diffopt
);
611 diffcore_std(&p_Rev
->diffopt
);
612 memset(&p_Rev
->diffstat
, 0, sizeof(struct diffstat_t
));
613 for (int i
= 0; i
< q
->nr
; ++i
) {
614 struct diff_filepair
*p
= q
->queue
[i
];
615 //if (check_pair_status(p))
616 diff_flush_stat(p
, &p_Rev
->diffopt
, &p_Rev
->diffstat
);
627 int git_get_diff_file(GIT_DIFF diff
, GIT_FILE file
, int i
, char** newname
, char** oldname
, int* IsDir
, char* status
, int* IsBin
, int* inc
, int* dec
)
629 struct diff_queue_struct
*q
= &diff_queued_diff
;
630 struct rev_info
*p_Rev
;
631 p_Rev
= (struct rev_info
*)diff
;
633 q
= (struct diff_queue_struct
*)file
;
639 assert(newname
&& oldname
&& status
&& IsDir
);
641 *newname
= q
->queue
[i
]->two
->path
;
642 *oldname
= q
->queue
[i
]->one
->path
;
643 *status
= q
->queue
[i
]->status
;
645 *IsDir
= (q
->queue
[i
]->one
->mode
& S_IFDIR
) == S_IFDIR
;
647 *IsDir
= (q
->queue
[i
]->two
->mode
& S_IFDIR
) == S_IFDIR
;
649 if (q
->queue
[i
]->one
->mode
&& q
->queue
[i
]->two
->mode
&& DIFF_PAIR_TYPE_CHANGED(q
->queue
[i
]))
652 if(p_Rev
->diffstat
.files
)
655 for (j
= 0; j
< p_Rev
->diffstat
.nr
; ++j
)
657 if(strcmp(*newname
,p_Rev
->diffstat
.files
[j
]->name
)==0)
660 if( j
== p_Rev
->diffstat
.nr
)
668 *IsBin
= p_Rev
->diffstat
.files
[j
]->is_binary
;
670 *inc
= (int)p_Rev
->diffstat
.files
[j
]->added
;
672 *dec
= (int)p_Rev
->diffstat
.files
[j
]->deleted
;
683 int git_add_exclude(const char *string
, const char *base
,
684 int baselen
, EXCLUDE_LIST which
, int lineno
)
686 add_pattern(string
, base
, baselen
, which
, lineno
);
690 int git_create_exclude_list(EXCLUDE_LIST
*which
)
692 *which
= malloc(sizeof(struct pattern_list
));
695 memset(*which
, 0, sizeof(struct pattern_list
));
699 int git_free_exclude_list(EXCLUDE_LIST which
)
701 struct pattern_list
* p
= (struct pattern_list
*)which
;
703 for (int i
= 0; i
< p
->nr
; ++i
)
705 free(p
->patterns
[i
]);
712 int git_check_excluded_1(const char *pathname
,
713 int pathlen
, const char *basename
, int *dtype
,
714 EXCLUDE_LIST el
, int ignorecase
)
716 ignore_case
= ignorecase
;
717 return path_matches_pattern_list(pathname
, pathlen
, basename
, dtype
, el
, NULL
);
720 int git_get_notes(const GIT_HASH hash
, char** p_note
)
722 struct object_id oid
;
726 hashcpy(oid
.hash
, hash
);
728 format_display_notes(&oid
, &sb
, "utf-8", 1);
729 *p_note
= strbuf_detach(&sb
,&size
);
734 int git_update_index(void)
740 argv
= strtoargv("-q --refresh", &argc
);
744 cleanup_chdir_notify();
745 drop_all_attr_stacks();
747 ret
= cmd_update_index(argc
, argv
, NULL
);
750 discard_index(the_repository
->index
);
756 void git_exit_cleanup(void)
758 git_atexit_dispatch();
759 // do not clear the atexit list, as lots of methods register it just once (and have a local static int flag)
762 int git_for_each_reflog_ent(const char *ref
, each_reflog_ent_fn fn
, void *cb_data
)
764 return for_each_reflog_ent(ref
,fn
,cb_data
);
767 static int update_some(const struct object_id
* sha1
, struct strbuf
* base
, const char* pathname
, unsigned mode
, void* context
)
769 struct cache_entry
* ce
= (struct cache_entry
*)context
;
772 return READ_TREE_RECURSIVE
;
774 oidcpy(&ce
->oid
, sha1
);
775 memcpy(ce
->name
, base
->buf
, base
->len
);
776 memcpy(ce
->name
+ base
->len
, pathname
, strlen(pathname
));
777 ce
->ce_flags
= create_ce_flags((unsigned int)(strlen(pathname
) + base
->len
));
778 ce
->ce_mode
= create_ce_mode(mode
);
783 int git_checkout_file(const char* ref
, const char* path
, char* outputpath
)
785 struct cache_entry
*ce
;
787 struct object_id oid
;
789 struct checkout state
= CHECKOUT_INIT
;
790 struct pathspec pathspec
;
791 struct conv_attrs ca
;
792 const char *matchbuf
[1];
793 ret
= repo_get_oid(the_repository
, ref
, &oid
);
797 reprepare_packed_git(the_repository
);
798 root
= parse_tree_indirect(&oid
);
806 ce
= xcalloc(1, cache_entry_size(strlen(path
)));
809 parse_pathspec(&pathspec
, PATHSPEC_ALL_MAGIC
, PATHSPEC_PREFER_CWD
, path
, matchbuf
);
810 pathspec
.items
[0].nowildcard_len
= pathspec
.items
[0].len
;
811 ret
= read_tree(the_repository
, root
, &pathspec
, update_some
, ce
);
812 clear_pathspec(&pathspec
);
821 state
.refresh_cache
= 0;
822 state
.istate
= the_repository
->index
;
824 reset_parsed_attributes();
825 convert_attrs(state
.istate
, &ca
, path
);
827 ret
= write_entry(ce
, outputpath
, &ca
, &state
, 0, NULL
);
840 static int get_config(const char* key_
, const char* value_
, const struct config_context
* ctx
, void* cb
)
842 UNREFERENCED_PARAMETER(ctx
);
843 struct config_buf
*buf
= (struct config_buf
*)cb
;
844 if(strcmp(key_
, buf
->key
))
848 strlcpy(buf
->buf
, value_
, buf
->size
);
851 assert(buf
->size
>= 5);
863 // wchar_t wrapper for git_etc_gitconfig()
864 const wchar_t *wget_msysgit_etc(const LPWSTR
* env
)
866 static const wchar_t *etc_gitconfig
= NULL
;
867 wchar_t wpointer
[MAX_PATH
];
870 return etc_gitconfig
;
872 build_libgit_environment(env
);
873 char* systemconfig
= git_system_config();
874 if (xutftowcs_path(wpointer
, systemconfig
) < 0)
881 etc_gitconfig
= _wcsdup(wpointer
);
883 return etc_gitconfig
;
886 int git_get_config(const char *key
, char *buffer
, int size
)
890 char* globalxdg
= NULL
;
891 struct config_buf buf
;
892 struct git_config_source config_source
= { 0 };
894 struct config_options opts
= { 0 };
895 opts
.respect_includes
= 1;
904 opts
.git_dir
= get_git_dir();
905 char* local
= git_pathdup("config");
906 config_source
.file
= local
;
907 config_with_options(get_config
, &buf
, &config_source
, the_repository
, &opts
);
913 git_global_config(&global
, &globalxdg
);
916 config_source
.file
= globalxdg
;
917 config_with_options(get_config
, &buf
, &config_source
, the_repository
, &opts
);
928 config_source
.file
= global
;
929 config_with_options(get_config
, &buf
, &config_source
, the_repository
, &opts
);
936 system
= git_system_config();
939 config_source
.file
= system
;
940 config_with_options(get_config
, &buf
, &config_source
, the_repository
, &opts
);
950 const char* git_default_notes_ref(void)
952 return default_notes_ref();
955 int git_set_config(const char* key
, const char* value
, CONFIG_TYPE type
)
957 char * config_exclusive_filename
= NULL
;
963 if (!the_repository
|| !the_repository
->gitdir
)
964 die("repository not correctly initialized.");
965 config_exclusive_filename
= git_pathdup("config");
968 case CONFIG_XDGGLOBAL
:
971 char* globalxdg
= NULL
;
972 git_global_config(&global
, &globalxdg
);
973 if (type
== CONFIG_GLOBAL
)
975 config_exclusive_filename
= global
;
980 config_exclusive_filename
= globalxdg
;
989 if(!config_exclusive_filename
)
992 ret
= git_config_set_multivar_in_file_gently(config_exclusive_filename
, key
, value
, NULL
, 0);
993 free(config_exclusive_filename
);
997 struct mailmap_info
{
1002 struct mailmap_entry
{
1003 /* name and email for the simple mail-only case */
1007 /* name and email for the complex mail and name matching case */
1008 struct string_list namemap
;
1011 int git_read_mailmap(GIT_MAILMAP
*mailmap
)
1013 struct string_list
*map
;
1020 if ((map
= (struct string_list
*)calloc(1, sizeof(struct string_list
))) == NULL
)
1023 if ((result
= read_mailmap(map
)) != 0)
1042 int git_lookup_mailmap(GIT_MAILMAP mailmap
, const char** email1
, const char** name1
, const char* email2
, void* payload
, const char *(*author2_cb
)(void*))
1044 struct string_list
*map
;
1045 struct string_list_item
* si
;
1046 struct mailmap_entry
* me
;
1051 map
= (struct string_list
*)mailmap
;
1052 si
= string_list_lookup(map
, email2
);
1056 me
= (struct mailmap_entry
*)si
->util
;
1059 /* The item has multiple items */
1060 const char* author2
= author2_cb(payload
);
1061 struct string_list_item
* subitem
= string_list_lookup(&me
->namemap
, author2
);
1063 me
= (struct mailmap_entry
*)subitem
->util
;
1067 *email1
= me
->email
;
1073 void git_free_mailmap(GIT_MAILMAP mailmap
)
1078 clear_mailmap((struct string_list
*)mailmap
);
1082 // just for regression tests
1083 int git_mkdir(const char* path
)
1085 return mkdir(path
, 0);