1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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 4018 4127 4244 4267)
26 #include "git-compat-util.h"
38 #include "run-command.h"
42 extern char g_last_error
[];
43 const char * g_prefix
;
45 extern void die_dll(const char *err
, va_list params
);
46 extern int die_is_recursing_dll(void);
48 extern void free_all_pack();
49 extern void reset_git_env();
50 extern void invalidate_ref_cache(const char* submodule
);
51 extern void cmd_log_init(int argc
, const char** argv
, const char* prefix
, struct rev_info
* rev
, struct setup_revision_opt
* opt
);
52 extern int estimate_commit_count(struct rev_info
* rev
, struct commit_list
* list
);
53 extern int log_tree_commit(struct rev_info
*, struct commit
*);
54 extern int write_entry(struct cache_entry
* ce
, char* path
, const struct checkout
* state
, int to_tempfile
);
55 extern struct object
* deref_tag(struct object
* o
, const char* warn
, int warnlen
);
56 extern void diff_flush_stat(struct diff_filepair
* p
, struct diff_options
* o
, struct diffstat_t
* diffstat
);
57 extern void free_diffstat_info(struct diffstat_t
* diffstat
);
58 extern int for_each_reflog_ent(const char* refname
, each_reflog_ent_fn fn
, void* cb_data
);
59 extern int for_each_ref_in(const char* prefix
, each_ref_fn fn
, void* cb_data
);
63 set_die_routine(die_dll
);
64 set_die_is_recursing_routine(die_is_recursing_dll
);
67 int git_get_sha1(const char *name
, GIT_HASH sha1
)
69 return get_sha1(name
,sha1
);
72 static int convert_slash(char * path
)
85 char path
[MAX_PATH
+1];
90 _setmode(_fileno(stdin
), _O_BINARY
);
91 _setmode(_fileno(stdout
), _O_BINARY
);
92 _setmode(_fileno(stderr
), _O_BINARY
);
94 // set HOME if not set already
95 getenv_s(&homesize
, NULL
, 0, "HOME");
98 _wputenv_s(L
"HOME", wget_windows_home_directory());
100 GetModuleFileName(NULL
, path
, MAX_PATH
);
103 git_extract_argv0_path(path
);
105 g_prefix
= setup_git_directory();
106 ret
= git_config(git_default_config
, NULL
);
110 _putenv_s("HOME","");/* clear home evironment to avoid affact third part software*/
116 static int git_parse_commit_author(struct GIT_COMMIT_AUTHOR
*author
, char *pbuff
)
121 end
=strchr(pbuff
,'<');
126 author
->NameSize
= (int)(end
- pbuff
- 1);
129 end
= strchr(pbuff
, '>');
133 author
->Email
= pbuff
;
134 author
->EmailSize
= (int)(end
- pbuff
);
138 author
->Date
= atol(pbuff
);
139 end
= strchr(pbuff
, ' ');
144 author
->TimeZone
= atol(pbuff
);
149 int git_parse_commit(GIT_COMMIT
*commit
)
156 p
= (struct commit
*)commit
->m_pGitCommit
;
158 memcpy(commit
->m_hash
,p
->object
.sha1
,GIT_HASH_SIZE
);
160 commit
->m_Encode
= NULL
;
161 commit
->m_EncodeSize
= 0;
163 if(p
->buffer
== NULL
)
169 if (strncmp(pbuf
, "author", 6) == 0)
171 ret
= git_parse_commit_author(&commit
->m_Author
,pbuf
+ 7);
175 else if (strncmp(pbuf
, "committer", 9) == 0)
177 ret
= git_parse_commit_author(&commit
->m_Committer
,pbuf
+ 10);
181 pbuf
= strchr(pbuf
,'\n');
185 else if (strncmp(pbuf
, "encoding", 8) == 0)
188 commit
->m_Encode
=pbuf
;
189 end
= strchr(pbuf
,'\n');
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');
201 commit
->m_SubjectSize
= (int)strlen(pbuf
);
204 commit
->m_SubjectSize
= (int)(end
- pbuf
);
206 commit
->m_Body
= pbuf
;
207 commit
->m_BodySize
= (int)strlen(pbuf
);
212 pbuf
= strchr(pbuf
,'\n');
219 int git_get_commit_from_hash(GIT_COMMIT
*commit
, GIT_HASH hash
)
228 memset(commit
,0,sizeof(GIT_COMMIT
));
230 commit
->m_pGitCommit
= p
= lookup_commit(hash
);
235 ret
= parse_commit(p
);
239 return git_parse_commit(commit
);
242 int git_get_commit_first_parent(GIT_COMMIT
*commit
,GIT_COMMIT_LIST
*list
)
244 struct commit
*p
= commit
->m_pGitCommit
;
249 *list
= (GIT_COMMIT_LIST
*)p
->parents
;
252 int git_get_commit_next_parent(GIT_COMMIT_LIST
*list
, GIT_HASH hash
)
254 struct commit_list
*l
;
258 l
= *(struct commit_list
**)list
;
263 memcpy(hash
, l
->item
->object
.sha1
, GIT_HASH_SIZE
);
265 *list
= (GIT_COMMIT_LIST
*)l
->next
;
271 int git_free_commit(GIT_COMMIT
*commit
)
273 struct commit
*p
= commit
->m_pGitCommit
;
276 free_commit_list(p
->parents
);
286 memset(commit
,0,sizeof(GIT_COMMIT
));
290 char **strtoargv(char *arg
, int *size
)
312 argv
=malloc(strlen(arg
)+1 + (count
+2)*sizeof(void*));
313 p
=(char*)(argv
+count
+2);
332 if((*arg
== space
) || (*arg
== 0))
348 int git_open_log(GIT_LOG
* handle
, char * arg
)
350 struct rev_info
*p_Rev
;
354 struct setup_revision_opt opt
;
357 unsigned int obj_size
= get_max_object_index();
358 for(i
=0; i
<obj_size
; i
++)
360 struct object
*ob
= get_indexed_object(i
);
364 if (ob
->parsed
&& ob
->type
== OBJ_COMMIT
)
366 struct commit
* commit
= (struct commit
*)ob
;
367 free_commit_list(commit
->parents
);
368 commit
->parents
= NULL
;
370 free(commit
->buffer
);
371 commit
->buffer
= NULL
;
378 argv
= strtoargv(arg
,&argc
);
383 p_Rev
= malloc(sizeof(struct rev_info
));
390 memset(p_Rev
,0,sizeof(struct rev_info
));
392 invalidate_ref_cache(NULL
);
394 init_revisions(p_Rev
, g_prefix
);
397 memset(&opt
, 0, sizeof(opt
));
400 cmd_log_init(argc
, argv
, g_prefix
,p_Rev
,&opt
);
402 p_Rev
->pPrivate
= argv
;
407 int git_get_log_firstcommit(GIT_LOG handle
)
409 return prepare_revision_walk(handle
);
412 int git_get_log_estimate_commit_count(GIT_LOG handle
)
414 struct rev_info
*p_Rev
;
415 p_Rev
=(struct rev_info
*)handle
;
417 return estimate_commit_count(p_Rev
, p_Rev
->commits
);
420 int git_get_log_nextcommit(GIT_LOG handle
, GIT_COMMIT
*commit
, int follow
)
427 memset(commit
, 0, sizeof(GIT_COMMIT
));
429 commit
->m_pGitCommit
= get_revision(handle
);
430 if( commit
->m_pGitCommit
== NULL
)
433 if (follow
&& !log_tree_commit(handle
, commit
->m_pGitCommit
))
435 commit
->m_ignore
= 1;
438 commit
->m_ignore
= 0;
440 ret
=git_parse_commit(commit
);
447 struct notes_tree
**display_notes_trees
;
448 int git_close_log(GIT_LOG handle
)
452 struct rev_info
*p_Rev
;
453 p_Rev
=(struct rev_info
*)handle
;
455 free(p_Rev
->pPrivate
);
460 if (display_notes_trees
)
461 free_notes(*display_notes_trees
);
462 display_notes_trees
= 0;
466 int git_open_diff(GIT_DIFF
*diff
, char * arg
)
468 struct rev_info
*p_Rev
;
473 argv
= strtoargv(arg
,&argc
);
475 p_Rev
= malloc(sizeof(struct rev_info
));
476 memset(p_Rev
,0,sizeof(struct rev_info
));
478 p_Rev
->pPrivate
= argv
;
479 *diff
= (GIT_DIFF
)p_Rev
;
481 init_revisions(p_Rev
, g_prefix
);
482 git_config(git_diff_basic_config
, NULL
); /* no "diff" UI options */
485 argc
= setup_revisions(argc
, argv
, p_Rev
, NULL
);
489 int git_close_diff(GIT_DIFF handle
)
491 git_diff_flush(handle
);
494 struct rev_info
*p_Rev
;
495 p_Rev
=(struct rev_info
*)handle
;
497 free(p_Rev
->pPrivate
);
502 int git_diff_flush(GIT_DIFF diff
)
504 struct diff_queue_struct
*q
= &diff_queued_diff
;
505 struct rev_info
*p_Rev
;
507 p_Rev
= (struct rev_info
*)diff
;
512 for (i
= 0; i
< q
->nr
; i
++)
513 diff_free_filepair(q
->queue
[i
]);
519 q
->nr
= q
->alloc
= 0;
522 if (p_Rev
->diffopt
.close_file
)
523 fclose(p_Rev
->diffopt
.file
);
525 free_diffstat_info(&p_Rev
->diffstat
);
529 int git_root_diff(GIT_DIFF diff
, GIT_HASH hash
,GIT_FILE
*file
, int *count
, int isstat
)
532 struct rev_info
*p_Rev
;
534 struct diff_queue_struct
*q
= &diff_queued_diff
;
536 p_Rev
= (struct rev_info
*)diff
;
538 ret
=diff_root_tree_sha1(hash
, "", &p_Rev
->diffopt
);
545 diffcore_std(&p_Rev
->diffopt
);
547 memset(&p_Rev
->diffstat
, 0, sizeof(struct diffstat_t
));
548 for (i
= 0; i
< q
->nr
; i
++) {
549 struct diff_filepair
*p
= q
->queue
[i
];
550 //if (check_pair_status(p))
551 diff_flush_stat(p
, &p_Rev
->diffopt
, &p_Rev
->diffstat
);
562 int git_do_diff(GIT_DIFF diff
, GIT_HASH hash1
, GIT_HASH hash2
, GIT_FILE
* file
, int *count
,int isstat
)
564 struct rev_info
*p_Rev
;
567 struct diff_queue_struct
*q
= &diff_queued_diff
;
569 p_Rev
= (struct rev_info
*)diff
;
571 ret
= diff_tree_sha1(hash1
,hash2
,"",&p_Rev
->diffopt
);
580 diffcore_std(&p_Rev
->diffopt
);
581 memset(&p_Rev
->diffstat
, 0, sizeof(struct diffstat_t
));
582 for (i
= 0; i
< q
->nr
; i
++) {
583 struct diff_filepair
*p
= q
->queue
[i
];
584 //if (check_pair_status(p))
585 diff_flush_stat(p
, &p_Rev
->diffopt
, &p_Rev
->diffstat
);
596 int git_get_diff_file(GIT_DIFF diff
,GIT_FILE file
,int i
, char **newname
, char ** oldname
, int *status
, int *IsBin
, int *inc
, int *dec
)
598 struct diff_queue_struct
*q
= &diff_queued_diff
;
599 struct rev_info
*p_Rev
;
600 p_Rev
= (struct rev_info
*)diff
;
602 q
= (struct diff_queue_struct
*)file
;
608 assert(newname
&& oldname
&& status
);
610 *newname
= q
->queue
[i
]->two
->path
;
611 *oldname
= q
->queue
[i
]->one
->path
;
612 *status
= q
->queue
[i
]->status
;
614 if(p_Rev
->diffstat
.files
)
617 for(j
=0;j
<p_Rev
->diffstat
.nr
;j
++)
619 if(strcmp(*newname
,p_Rev
->diffstat
.files
[j
]->name
)==0)
622 if( j
== p_Rev
->diffstat
.nr
)
630 *IsBin
= p_Rev
->diffstat
.files
[j
]->is_binary
;
632 *inc
= (int)p_Rev
->diffstat
.files
[j
]->added
;
634 *dec
= (int)p_Rev
->diffstat
.files
[j
]->deleted
;
645 int git_read_tree(GIT_HASH hash
,read_tree_fn_t fn
, void *context
)
649 reprepare_packed_git();
650 root
= parse_tree_indirect(hash
);
657 ret
= read_tree_recursive(root
, NULL
, 0, 0, NULL
, fn
, context
);
662 int git_add_exclude(const char *string
, const char *base
,
663 int baselen
, struct exclude_list
*which
, int lineno
)
665 add_exclude(string
, base
, baselen
, which
, lineno
);
669 int git_create_exclude_list(EXCLUDE_LIST
*which
)
671 *which
= malloc(sizeof(struct exclude_list
));
672 memset(*which
,0,sizeof(struct exclude_list
));
676 int git_free_exclude_list(EXCLUDE_LIST which
)
679 struct exclude_list
*p
= (struct exclude_list
*) which
;
681 for(i
=0; i
<p
->nr
;i
++)
683 free(p
->excludes
[i
]);
690 int git_check_excluded_1(const char *pathname
,
691 int pathlen
, const char *basename
, int *dtype
,
694 return is_excluded_from_list(pathname
, pathlen
, basename
, dtype
, el
);
697 int git_get_notes(GIT_HASH hash
, char **p_note
)
702 format_display_notes(hash
, &sb
, "utf-8", 1);
703 *p_note
= strbuf_detach(&sb
,&size
);
710 int (*fn
)(int, const char **, const char *);
714 #define RUN_SETUP (1<<0)
715 #define USE_PAGER (1<<1)
717 * require working tree to be present -- anything uses this needs
718 * RUN_SETUP for reading from the configuration file.
720 #define NEED_WORK_TREE (1<<2)
722 const char git_usage_string
[] =
723 "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
724 " [-p|--paginate|--no-pager] [--no-replace-objects]\n"
725 " [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n"
726 " [-c name=value] [--help]\n"
729 const char git_more_info_string
[] =
730 "See 'git help COMMAND' for more information on a specific command.";
732 static struct cmd_struct commands
[] = {
733 { "add", cmd_add
, RUN_SETUP
| NEED_WORK_TREE
},
734 { "stage", cmd_add
, RUN_SETUP
| NEED_WORK_TREE
},
735 { "annotate", cmd_annotate
, RUN_SETUP
},
736 { "apply", cmd_apply
},
737 { "archive", cmd_archive
},
738 { "bisect--helper", cmd_bisect__helper
, RUN_SETUP
| NEED_WORK_TREE
},
739 { "blame", cmd_blame
, RUN_SETUP
},
740 { "branch", cmd_branch
, RUN_SETUP
},
741 { "bundle", cmd_bundle
},
742 { "cat-file", cmd_cat_file
, RUN_SETUP
},
743 { "checkout", cmd_checkout
, RUN_SETUP
| NEED_WORK_TREE
},
744 { "checkout-index", cmd_checkout_index
,
745 RUN_SETUP
| NEED_WORK_TREE
},
746 { "check-ref-format", cmd_check_ref_format
},
747 { "check-attr", cmd_check_attr
, RUN_SETUP
},
748 { "cherry", cmd_cherry
, RUN_SETUP
},
749 { "cherry-pick", cmd_cherry_pick
, RUN_SETUP
| NEED_WORK_TREE
},
750 { "clone", cmd_clone
},
751 { "clean", cmd_clean
, RUN_SETUP
| NEED_WORK_TREE
},
752 { "commit", cmd_commit
, RUN_SETUP
| NEED_WORK_TREE
},
753 { "commit-tree", cmd_commit_tree
, RUN_SETUP
},
754 { "config", cmd_config
},
755 { "count-objects", cmd_count_objects
, RUN_SETUP
},
756 { "describe", cmd_describe
, RUN_SETUP
},
757 { "diff", cmd_diff
},
758 { "diff-files", cmd_diff_files
, RUN_SETUP
| NEED_WORK_TREE
},
759 { "diff-index", cmd_diff_index
, RUN_SETUP
},
760 { "diff-tree", cmd_diff_tree
, RUN_SETUP
},
761 { "fast-export", cmd_fast_export
, RUN_SETUP
},
762 { "fetch", cmd_fetch
, RUN_SETUP
},
763 { "fetch-pack", cmd_fetch_pack
, RUN_SETUP
},
764 { "fmt-merge-msg", cmd_fmt_merge_msg
, RUN_SETUP
},
765 { "for-each-ref", cmd_for_each_ref
, RUN_SETUP
},
766 { "format-patch", cmd_format_patch
, RUN_SETUP
},
767 { "fsck", cmd_fsck
, RUN_SETUP
},
768 { "fsck-objects", cmd_fsck
, RUN_SETUP
},
769 { "gc", cmd_gc
, RUN_SETUP
},
770 { "get-tar-commit-id", cmd_get_tar_commit_id
},
771 { "grep", cmd_grep
},
772 { "hash-object", cmd_hash_object
},
773 { "help", cmd_help
},
774 { "index-pack", cmd_index_pack
},
775 { "init", cmd_init_db
},
776 { "init-db", cmd_init_db
},
777 { "log", cmd_log
, RUN_SETUP
},
778 { "ls-files", cmd_ls_files
, RUN_SETUP
},
779 { "ls-tree", cmd_ls_tree
, RUN_SETUP
},
780 { "ls-remote", cmd_ls_remote
},
781 { "mailinfo", cmd_mailinfo
},
782 { "mailsplit", cmd_mailsplit
},
783 { "merge", cmd_merge
, RUN_SETUP
| NEED_WORK_TREE
},
784 { "merge-base", cmd_merge_base
, RUN_SETUP
},
785 { "merge-file", cmd_merge_file
},
786 { "merge-index", cmd_merge_index
, RUN_SETUP
},
787 { "merge-ours", cmd_merge_ours
, RUN_SETUP
},
788 { "merge-recursive", cmd_merge_recursive
, RUN_SETUP
| NEED_WORK_TREE
},
789 { "merge-recursive-ours", cmd_merge_recursive
, RUN_SETUP
| NEED_WORK_TREE
},
790 { "merge-recursive-theirs", cmd_merge_recursive
, RUN_SETUP
| NEED_WORK_TREE
},
791 { "merge-subtree", cmd_merge_recursive
, RUN_SETUP
| NEED_WORK_TREE
},
792 { "merge-tree", cmd_merge_tree
, RUN_SETUP
},
793 { "mktag", cmd_mktag
, RUN_SETUP
},
794 { "mktree", cmd_mktree
, RUN_SETUP
},
795 { "mv", cmd_mv
, RUN_SETUP
| NEED_WORK_TREE
},
796 { "name-rev", cmd_name_rev
, RUN_SETUP
},
797 { "notes", cmd_notes
, RUN_SETUP
},
798 { "pack-objects", cmd_pack_objects
, RUN_SETUP
},
799 { "pack-redundant", cmd_pack_redundant
, RUN_SETUP
},
800 { "patch-id", cmd_patch_id
},
801 { "pickaxe", cmd_blame
, RUN_SETUP
},
802 { "prune", cmd_prune
, RUN_SETUP
},
803 { "prune-packed", cmd_prune_packed
, RUN_SETUP
},
804 { "push", cmd_push
, RUN_SETUP
},
805 { "read-tree", cmd_read_tree
, RUN_SETUP
},
806 { "receive-pack", cmd_receive_pack
},
807 { "reflog", cmd_reflog
, RUN_SETUP
},
808 { "remote", cmd_remote
, RUN_SETUP
},
809 { "replace", cmd_replace
, RUN_SETUP
},
810 { "rerere", cmd_rerere
, RUN_SETUP
},
811 { "reset", cmd_reset
, RUN_SETUP
},
812 { "rev-list", cmd_rev_list
, RUN_SETUP
},
813 { "rev-parse", cmd_rev_parse
},
814 { "revert", cmd_revert
, RUN_SETUP
| NEED_WORK_TREE
},
815 { "rm", cmd_rm
, RUN_SETUP
},
816 { "send-pack", cmd_send_pack
, RUN_SETUP
},
817 { "shortlog", cmd_shortlog
, USE_PAGER
},
818 { "show-branch", cmd_show_branch
, RUN_SETUP
},
819 { "show", cmd_show
, RUN_SETUP
},
820 { "status", cmd_status
, RUN_SETUP
| NEED_WORK_TREE
},
821 { "stripspace", cmd_stripspace
},
822 { "symbolic-ref", cmd_symbolic_ref
, RUN_SETUP
},
823 { "tag", cmd_tag
, RUN_SETUP
},
824 { "unpack-file", cmd_unpack_file
, RUN_SETUP
},
825 { "unpack-objects", cmd_unpack_objects
, RUN_SETUP
},
826 { "update-index", cmd_update_index
, RUN_SETUP
},
827 { "update-ref", cmd_update_ref
, RUN_SETUP
},
828 { "update-server-info", cmd_update_server_info
, RUN_SETUP
},
829 { "upload-archive", cmd_upload_archive
},
831 { "verify-tag", cmd_verify_tag
, RUN_SETUP
},
832 { "version", cmd_version
},
833 { "whatchanged", cmd_whatchanged
, RUN_SETUP
},
834 { "write-tree", cmd_write_tree
, RUN_SETUP
},
835 { "verify-pack", cmd_verify_pack
},
836 { "show-ref", cmd_show_ref
, RUN_SETUP
},
837 { "pack-refs", cmd_pack_refs
, RUN_SETUP
},
840 int is_builtin(const char *s
)
843 for (i
= 0; i
< ARRAY_SIZE(commands
); i
++) {
844 struct cmd_struct
*p
= commands
+i
;
845 if (!strcmp(s
, p
->cmd
))
851 int git_run_cmd(char *cmd
, char *arg
)
860 for(i
=0;i
< sizeof(commands
) / sizeof(struct cmd_struct
);i
++)
862 if(strcmp(cmd
,commands
[i
].cmd
)==0)
866 argv
= strtoargv(arg
,&argc
);
868 ret
= commands
[i
].fn(argc
, argv
, NULL
);
884 int git_for_each_ref_in(const char * refname
, each_ref_fn fn
, void * data
)
887 invalidate_ref_cache(NULL
);
888 ret
= for_each_ref_in(refname
, fn
, data
);
893 const char *git_resolve_ref(const char *ref
, unsigned char *sha1
, int reading
, int *flag
)
895 invalidate_ref_cache(NULL
);
896 return resolve_ref_unsafe(ref
,sha1
,reading
, flag
);
898 int git_for_each_reflog_ent(const char *ref
, each_reflog_ent_fn fn
, void *cb_data
)
900 return for_each_reflog_ent(ref
,fn
,cb_data
);
903 int git_deref_tag(const unsigned char *tagsha1
, GIT_HASH refhash
)
905 struct object
*obj
= NULL
;
906 obj
= parse_object(tagsha1
);
910 if (obj
->type
== OBJ_TAG
)
912 obj
= deref_tag(obj
, "", 0);
916 memcpy(refhash
, obj
->sha1
, sizeof(GIT_HASH
));
923 static int update_some(const unsigned char *sha1
, const char *base
, int baselen
,
924 const char *pathname
, unsigned mode
, int stage
, void *context
)
926 struct cache_entry
*ce
;
927 UNREFERENCED_PARAMETER(stage
);
929 ce
= (struct cache_entry
*)context
;
932 return READ_TREE_RECURSIVE
;
934 hashcpy(ce
->sha1
, sha1
);
935 memcpy(ce
->name
, base
, baselen
);
936 memcpy(ce
->name
+ baselen
, pathname
, strlen(pathname
));
937 ce
->ce_flags
= create_ce_flags((unsigned int)strlen(pathname
) + baselen
);
938 ce
->ce_mode
= create_ce_mode(mode
);
943 int git_checkout_file(const char* ref
, const char* path
, char* outputpath
)
945 struct cache_entry
*ce
;
949 struct checkout state
;
950 struct pathspec pathspec
;
951 const char *matchbuf
[1];
952 ret
= get_sha1(ref
, sha1
);
956 reprepare_packed_git();
957 root
= parse_tree_indirect(sha1
);
965 ce
= xcalloc(1, cache_entry_size(strlen(path
)));
968 parse_pathspec(&pathspec
, PATHSPEC_ALL_MAGIC
, PATHSPEC_PREFER_CWD
, path
, matchbuf
);
969 pathspec
.items
[0].nowildcard_len
= pathspec
.items
[0].len
;
970 ret
= read_tree_recursive(root
, "", 0, 0, &pathspec
, update_some
, ce
);
971 free_pathspec(&pathspec
);
979 memset(&state
, 0, sizeof(state
));
981 state
.refresh_cache
= 0;
983 ret
= write_entry(ce
, outputpath
, &state
, 0);
996 static int get_config(const char *key_
, const char *value_
, void *cb
)
998 struct config_buf
*buf
;
999 buf
=(struct config_buf
*)cb
;
1000 if(strcmp(key_
, buf
->key
))
1004 strncpy(buf
->buf
,value_
,buf
->size
);
1018 // wchar_t wrapper for git_etc_gitconfig()
1019 const wchar_t *wget_msysgit_etc(void)
1021 static const wchar_t *etc_gitconfig
= NULL
;
1022 wchar_t wpointer
[MAX_PATH
];
1025 return etc_gitconfig
;
1027 if (xutftowcs_path(wpointer
, git_etc_gitconfig()) < 0)
1030 etc_gitconfig
= _wcsdup(wpointer
);
1032 return etc_gitconfig
;
1035 int git_get_config(const char *key
, char *buffer
, int size
)
1037 char *local
, *global
, *globalxdg
;
1038 const char *home
, *system
;
1039 struct config_buf buf
;
1046 home
= get_windows_home_directory();
1049 global
= xstrdup(mkpath("%s/.gitconfig", home
));
1050 globalxdg
= xstrdup(mkpath("%s/.config/git/config", home
));
1058 system
= git_etc_gitconfig();
1060 local
= git_pathdup("config");
1063 git_config_with_options(get_config
, &buf
, local
, NULL
, 1);
1064 if (!buf
.seen
&& global
)
1065 git_config_with_options(get_config
, &buf
, global
, NULL
, 1);
1066 if (!buf
.seen
&& globalxdg
)
1067 git_config_with_options(get_config
, &buf
, globalxdg
, NULL
, 1);
1068 if (!buf
.seen
&& system
)
1069 git_config_with_options(get_config
, &buf
, system
, NULL
, 1);
1081 // taken from msysgit: compat/mingw.c
1082 const char *get_windows_home_directory(void)
1084 static const char *home_directory
= NULL
;
1085 struct strbuf buf
= STRBUF_INIT
;
1088 return home_directory
;
1090 home_directory
= getenv("HOME");
1091 if (home_directory
&& *home_directory
)
1092 return home_directory
;
1094 strbuf_addf(&buf
, "%s%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
1095 home_directory
= strbuf_detach(&buf
, NULL
);
1097 return home_directory
;
1100 // wchar_t wrapper for get_windows_home_directory()
1101 const wchar_t *wget_windows_home_directory(void)
1103 static const wchar_t *home_directory
= NULL
;
1104 wchar_t wpointer
[MAX_PATH
];
1107 return home_directory
;
1109 if (xutftowcs_path(wpointer
, get_windows_home_directory()) < 0)
1112 home_directory
= _wcsdup(wpointer
);
1114 return home_directory
;
1117 int get_set_config(const char *key
, const char *value
, CONFIG_TYPE type
)
1119 char * config_exclusive_filename
= NULL
;
1124 config_exclusive_filename
= git_pathdup("config");
1127 case CONFIG_XDGGLOBAL
:
1129 const char *home
= get_windows_home_directory();
1132 if (type
== CONFIG_GLOBAL
)
1133 config_exclusive_filename
= xstrdup(mkpath("%s/.gitconfig", home
));
1135 config_exclusive_filename
= xstrdup(mkpath("%s/.config/git/config", home
));
1141 if(!config_exclusive_filename
)
1144 return git_config_set_multivar_in_file(config_exclusive_filename
, key
, value
, NULL
, 0);
1147 struct mailmap_info
{
1152 struct mailmap_entry
{
1153 /* name and email for the simple mail-only case */
1157 /* name and email for the complex mail and name matching case */
1158 struct string_list namemap
;
1161 int git_read_mailmap(GIT_MAILMAP
*mailmap
)
1163 struct string_list
*map
;
1170 if ((map
= (struct string_list
*)calloc(1, sizeof(struct string_list
))) == NULL
)
1173 if ((result
= read_mailmap(map
, NULL
)) != 0)
1180 const char * git_get_mailmap_author(GIT_MAILMAP mailmap
, const char *email2
, void *payload
, const char *(*author2_cb
)(void *))
1182 struct string_list
*map
;
1188 map
= (struct string_list
*)mailmap
;
1190 while (imax
>= imin
)
1192 int i
= imin
+ ((imax
- imin
) / 2);
1193 struct string_list_item
*si
= (struct string_list_item
*)&map
->items
[i
];
1194 struct mailmap_entry
*me
= (struct mailmap_entry
*)si
->util
;
1195 int comp
= strcmp(si
->string
, email2
);
1201 const char *author2
= author2_cb(payload
);
1203 for (j
= 0; j
< me
->namemap
.nr
; ++j
)
1205 struct string_list_item
*sj
= (struct string_list_item
*)&me
->namemap
.items
[j
];
1206 struct mailmap_info
*mi
= (struct mailmap_info
*)sj
->util
;
1208 if (!strcmp(sj
->string
, author2
))
1224 void git_free_mailmap(GIT_MAILMAP mailmap
)
1229 clear_mailmap((struct string_list
*)mailmap
);