2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
9 #include "git2/config.h"
10 #include "git2/sys/config.h"
11 #include "git2/types.h"
12 #include "git2/repository.h"
13 #include "git2/index.h"
14 #include "git2/submodule.h"
19 #include "config_file.h"
21 #include "repository.h"
22 #include "submodule.h"
26 #define GIT_MODULES_FILE ".gitmodules"
28 static git_cvar_map _sm_update_map
[] = {
29 {GIT_CVAR_STRING
, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT
},
30 {GIT_CVAR_STRING
, "rebase", GIT_SUBMODULE_UPDATE_REBASE
},
31 {GIT_CVAR_STRING
, "merge", GIT_SUBMODULE_UPDATE_MERGE
},
32 {GIT_CVAR_STRING
, "none", GIT_SUBMODULE_UPDATE_NONE
},
35 static git_cvar_map _sm_ignore_map
[] = {
36 {GIT_CVAR_STRING
, "none", GIT_SUBMODULE_IGNORE_NONE
},
37 {GIT_CVAR_STRING
, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED
},
38 {GIT_CVAR_STRING
, "dirty", GIT_SUBMODULE_IGNORE_DIRTY
},
39 {GIT_CVAR_STRING
, "all", GIT_SUBMODULE_IGNORE_ALL
},
42 static kh_inline khint_t
str_hash_no_trailing_slash(const char *s
)
47 if (s
[1] != '\0' || *s
!= '/')
48 h
= (h
<< 5) - h
+ *s
;
53 static kh_inline
int str_equal_no_trailing_slash(const char *a
, const char *b
)
55 size_t alen
= a
? strlen(a
) : 0;
56 size_t blen
= b
? strlen(b
) : 0;
58 if (alen
> 0 && a
[alen
- 1] == '/')
60 if (blen
> 0 && b
[blen
- 1] == '/')
63 return (alen
== blen
&& strncmp(a
, b
, alen
) == 0);
67 str
, static kh_inline
, const char *, void *, 1,
68 str_hash_no_trailing_slash
, str_equal_no_trailing_slash
);
70 static int load_submodule_config(git_repository
*repo
);
71 static git_config_backend
*open_gitmodules(git_repository
*, bool, const git_oid
*);
72 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
);
73 static int submodule_get(git_submodule
**, git_repository
*, const char *, const char *);
74 static void submodule_release(git_submodule
*sm
, int decr
);
75 static int submodule_load_from_index(git_repository
*, const git_index_entry
*);
76 static int submodule_load_from_head(git_repository
*, const char*, const git_oid
*);
77 static int submodule_load_from_config(const git_config_entry
*, void *);
78 static int submodule_load_from_wd_lite(git_submodule
*, const char *, void *);
79 static int submodule_update_config(git_submodule
*, const char *, const char *, bool, bool);
80 static void submodule_mode_mismatch(git_repository
*, const char *, unsigned int);
81 static int submodule_index_status(unsigned int *status
, git_submodule
*sm
);
82 static int submodule_wd_status(unsigned int *status
, git_submodule
*sm
);
84 static int submodule_cmp(const void *a
, const void *b
)
86 return strcmp(((git_submodule
*)a
)->name
, ((git_submodule
*)b
)->name
);
89 static int submodule_config_key_trunc_puts(git_buf
*key
, const char *suffix
)
91 ssize_t idx
= git_buf_rfind(key
, '.');
92 git_buf_truncate(key
, (size_t)(idx
+ 1));
93 return git_buf_puts(key
, suffix
);
100 int git_submodule_lookup(
101 git_submodule
**sm_ptr
, /* NULL if user only wants to test existence */
102 git_repository
*repo
,
103 const char *name
) /* trailing slash is allowed */
108 assert(repo
&& name
);
110 if ((error
= load_submodule_config(repo
)) < 0)
113 pos
= git_strmap_lookup_index(repo
->submodules
, name
);
115 if (!git_strmap_valid_index(repo
->submodules
, pos
)) {
116 error
= GIT_ENOTFOUND
;
118 /* check if a plausible submodule exists at path */
119 if (git_repository_workdir(repo
)) {
120 git_buf path
= GIT_BUF_INIT
;
122 if (git_buf_joinpath(&path
, git_repository_workdir(repo
), name
) < 0)
125 if (git_path_contains_dir(&path
, DOT_GIT
))
135 *sm_ptr
= git_strmap_value_at(repo
->submodules
, pos
);
140 int git_submodule_foreach(
141 git_repository
*repo
,
142 int (*callback
)(git_submodule
*sm
, const char *name
, void *payload
),
147 git_vector seen
= GIT_VECTOR_INIT
;
148 seen
._cmp
= submodule_cmp
;
150 assert(repo
&& callback
);
152 if ((error
= load_submodule_config(repo
)) < 0)
155 git_strmap_foreach_value(repo
->submodules
, sm
, {
156 /* Usually the following will not come into play - it just prevents
157 * us from issuing a callback twice for a submodule where the name
158 * and path are not the same.
160 if (sm
->refcount
> 1) {
161 if (git_vector_bsearch(NULL
, &seen
, sm
) != GIT_ENOTFOUND
)
163 if ((error
= git_vector_insert(&seen
, sm
)) < 0)
167 if (callback(sm
, sm
->name
, payload
)) {
174 git_vector_free(&seen
);
179 void git_submodule_config_free(git_repository
*repo
)
186 smcfg
= repo
->submodules
;
187 repo
->submodules
= NULL
;
192 git_strmap_foreach_value(smcfg
, sm
, {
193 submodule_release(sm
,1);
195 git_strmap_free(smcfg
);
198 int git_submodule_add_setup(
199 git_submodule
**submodule
,
200 git_repository
*repo
,
206 git_config_backend
*mods
= NULL
;
208 git_buf name
= GIT_BUF_INIT
, real_url
= GIT_BUF_INIT
;
209 git_repository_init_options initopt
= GIT_REPOSITORY_INIT_OPTIONS_INIT
;
210 git_repository
*subrepo
= NULL
;
212 assert(repo
&& url
&& path
);
214 /* see if there is already an entry for this submodule */
216 if (git_submodule_lookup(&sm
, repo
, path
) < 0)
219 giterr_set(GITERR_SUBMODULE
,
220 "Attempt to add a submodule that already exists");
224 /* resolve parameters */
226 if (url
[0] == '.' && (url
[1] == '/' || (url
[1] == '.' && url
[2] == '/'))) {
227 if (!(error
= lookup_head_remote(&real_url
, repo
)))
228 error
= git_path_apply_relative(&real_url
, url
);
229 } else if (strchr(url
, ':') != NULL
|| url
[0] == '/') {
230 error
= git_buf_sets(&real_url
, url
);
232 giterr_set(GITERR_SUBMODULE
, "Invalid format for submodule URL");
238 /* validate and normalize path */
240 if (git__prefixcmp(path
, git_repository_workdir(repo
)) == 0)
241 path
+= strlen(git_repository_workdir(repo
));
243 if (git_path_root(path
) >= 0) {
244 giterr_set(GITERR_SUBMODULE
, "Submodule path must be a relative path");
249 /* update .gitmodules */
251 if ((mods
= open_gitmodules(repo
, true, NULL
)) == NULL
) {
252 giterr_set(GITERR_SUBMODULE
,
253 "Adding submodules to a bare repository is not supported (for now)");
257 if ((error
= git_buf_printf(&name
, "submodule.%s.path", path
)) < 0 ||
258 (error
= git_config_file_set_string(mods
, name
.ptr
, path
)) < 0)
261 if ((error
= submodule_config_key_trunc_puts(&name
, "url")) < 0 ||
262 (error
= git_config_file_set_string(mods
, name
.ptr
, real_url
.ptr
)) < 0)
265 git_buf_clear(&name
);
267 /* init submodule repository and add origin remote as needed */
269 error
= git_buf_joinpath(&name
, git_repository_workdir(repo
), path
);
273 /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
274 * gitlink in the sub-repo workdir directory to that repository
276 * Old style: sub-repo goes directly into repo/<name>/.git/
279 initopt
.flags
= GIT_REPOSITORY_INIT_MKPATH
|
280 GIT_REPOSITORY_INIT_NO_REINIT
;
281 initopt
.origin_url
= real_url
.ptr
;
283 if (git_path_exists(name
.ptr
) &&
284 git_path_contains(&name
, DOT_GIT
))
286 /* repo appears to already exist - reinit? */
288 else if (use_gitlink
) {
289 git_buf repodir
= GIT_BUF_INIT
;
291 error
= git_buf_join_n(
292 &repodir
, '/', 3, git_repository_path(repo
), "modules", path
);
296 initopt
.workdir_path
= name
.ptr
;
297 initopt
.flags
|= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR
;
299 error
= git_repository_init_ext(&subrepo
, repodir
.ptr
, &initopt
);
301 git_buf_free(&repodir
);
304 error
= git_repository_init_ext(&subrepo
, name
.ptr
, &initopt
);
309 /* add submodule to hash and "reload" it */
311 if (!(error
= submodule_get(&sm
, repo
, path
, NULL
)) &&
312 !(error
= git_submodule_reload(sm
)))
313 error
= git_submodule_init(sm
, false);
316 if (submodule
!= NULL
)
317 *submodule
= !error
? sm
: NULL
;
320 git_config_file_free(mods
);
321 git_repository_free(subrepo
);
322 git_buf_free(&real_url
);
328 int git_submodule_add_finalize(git_submodule
*sm
)
335 if ((error
= git_repository_index__weakptr(&index
, sm
->owner
)) < 0 ||
336 (error
= git_index_add_bypath(index
, GIT_MODULES_FILE
)) < 0)
339 return git_submodule_add_to_index(sm
, true);
342 int git_submodule_add_to_index(git_submodule
*sm
, int write_index
)
345 git_repository
*repo
, *sm_repo
= NULL
;
347 git_buf path
= GIT_BUF_INIT
;
349 git_index_entry entry
;
356 /* force reload of wd OID by git_submodule_open */
357 sm
->flags
= sm
->flags
& ~GIT_SUBMODULE_STATUS__WD_OID_VALID
;
359 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0 ||
360 (error
= git_buf_joinpath(
361 &path
, git_repository_workdir(repo
), sm
->path
)) < 0 ||
362 (error
= git_submodule_open(&sm_repo
, sm
)) < 0)
365 /* read stat information for submodule working directory */
366 if (p_stat(path
.ptr
, &st
) < 0) {
367 giterr_set(GITERR_SUBMODULE
,
368 "Cannot add submodule without working directory");
373 memset(&entry
, 0, sizeof(entry
));
374 entry
.path
= sm
->path
;
375 git_index_entry__init_from_stat(&entry
, &st
);
377 /* calling git_submodule_open will have set sm->wd_oid if possible */
378 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
) == 0) {
379 giterr_set(GITERR_SUBMODULE
,
380 "Cannot add submodule without HEAD to index");
384 git_oid_cpy(&entry
.oid
, &sm
->wd_oid
);
386 if ((error
= git_commit_lookup(&head
, sm_repo
, &sm
->wd_oid
)) < 0)
389 entry
.ctime
.seconds
= git_commit_time(head
);
390 entry
.ctime
.nanoseconds
= 0;
391 entry
.mtime
.seconds
= git_commit_time(head
);
392 entry
.mtime
.nanoseconds
= 0;
394 git_commit_free(head
);
397 error
= git_index_add(index
, &entry
);
399 /* write it, if requested */
400 if (!error
&& write_index
) {
401 error
= git_index_write(index
);
404 git_oid_cpy(&sm
->index_oid
, &sm
->wd_oid
);
408 git_repository_free(sm_repo
);
413 int git_submodule_save(git_submodule
*submodule
)
416 git_config_backend
*mods
;
417 git_buf key
= GIT_BUF_INIT
;
421 mods
= open_gitmodules(submodule
->owner
, true, NULL
);
423 giterr_set(GITERR_SUBMODULE
,
424 "Adding submodules to a bare repository is not supported (for now)");
428 if ((error
= git_buf_printf(&key
, "submodule.%s.", submodule
->name
)) < 0)
431 /* save values for path, url, update, ignore, fetchRecurseSubmodules */
433 if ((error
= submodule_config_key_trunc_puts(&key
, "path")) < 0 ||
434 (error
= git_config_file_set_string(mods
, key
.ptr
, submodule
->path
)) < 0)
437 if ((error
= submodule_config_key_trunc_puts(&key
, "url")) < 0 ||
438 (error
= git_config_file_set_string(mods
, key
.ptr
, submodule
->url
)) < 0)
441 if (!(error
= submodule_config_key_trunc_puts(&key
, "update")) &&
442 submodule
->update
!= GIT_SUBMODULE_UPDATE_DEFAULT
)
444 const char *val
= (submodule
->update
== GIT_SUBMODULE_UPDATE_CHECKOUT
) ?
445 NULL
: _sm_update_map
[submodule
->update
].str_match
;
446 error
= git_config_file_set_string(mods
, key
.ptr
, val
);
451 if (!(error
= submodule_config_key_trunc_puts(&key
, "ignore")) &&
452 submodule
->ignore
!= GIT_SUBMODULE_IGNORE_DEFAULT
)
454 const char *val
= (submodule
->ignore
== GIT_SUBMODULE_IGNORE_NONE
) ?
455 NULL
: _sm_ignore_map
[submodule
->ignore
].str_match
;
456 error
= git_config_file_set_string(mods
, key
.ptr
, val
);
461 if ((error
= submodule_config_key_trunc_puts(
462 &key
, "fetchRecurseSubmodules")) < 0 ||
463 (error
= git_config_file_set_string(
464 mods
, key
.ptr
, submodule
->fetch_recurse
? "true" : "false")) < 0)
467 /* update internal defaults */
469 submodule
->ignore_default
= submodule
->ignore
;
470 submodule
->update_default
= submodule
->update
;
471 submodule
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
475 git_config_file_free(mods
);
481 git_repository
*git_submodule_owner(git_submodule
*submodule
)
484 return submodule
->owner
;
487 const char *git_submodule_name(git_submodule
*submodule
)
490 return submodule
->name
;
493 const char *git_submodule_path(git_submodule
*submodule
)
496 return submodule
->path
;
499 const char *git_submodule_url(git_submodule
*submodule
)
502 return submodule
->url
;
505 int git_submodule_set_url(git_submodule
*submodule
, const char *url
)
507 assert(submodule
&& url
);
509 git__free(submodule
->url
);
511 submodule
->url
= git__strdup(url
);
512 GITERR_CHECK_ALLOC(submodule
->url
);
517 const git_oid
*git_submodule_index_id(git_submodule
*submodule
)
521 if (submodule
->flags
& GIT_SUBMODULE_STATUS__INDEX_OID_VALID
)
522 return &submodule
->index_oid
;
527 const git_oid
*git_submodule_head_id(git_submodule
*submodule
)
531 if (submodule
->flags
& GIT_SUBMODULE_STATUS__HEAD_OID_VALID
)
532 return &submodule
->head_oid
;
537 const git_oid
*git_submodule_wd_id(git_submodule
*submodule
)
541 if (!(submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)) {
542 git_repository
*subrepo
;
544 /* calling submodule open grabs the HEAD OID if possible */
545 if (!git_submodule_open(&subrepo
, submodule
))
546 git_repository_free(subrepo
);
551 if (submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)
552 return &submodule
->wd_oid
;
557 git_submodule_ignore_t
git_submodule_ignore(git_submodule
*submodule
)
560 return submodule
->ignore
;
563 git_submodule_ignore_t
git_submodule_set_ignore(
564 git_submodule
*submodule
, git_submodule_ignore_t ignore
)
566 git_submodule_ignore_t old
;
570 if (ignore
== GIT_SUBMODULE_IGNORE_DEFAULT
)
571 ignore
= submodule
->ignore_default
;
573 old
= submodule
->ignore
;
574 submodule
->ignore
= ignore
;
578 git_submodule_update_t
git_submodule_update(git_submodule
*submodule
)
581 return submodule
->update
;
584 git_submodule_update_t
git_submodule_set_update(
585 git_submodule
*submodule
, git_submodule_update_t update
)
587 git_submodule_update_t old
;
591 if (update
== GIT_SUBMODULE_UPDATE_DEFAULT
)
592 update
= submodule
->update_default
;
594 old
= submodule
->update
;
595 submodule
->update
= update
;
599 int git_submodule_fetch_recurse_submodules(
600 git_submodule
*submodule
)
603 return submodule
->fetch_recurse
;
606 int git_submodule_set_fetch_recurse_submodules(
607 git_submodule
*submodule
,
608 int fetch_recurse_submodules
)
614 old
= submodule
->fetch_recurse
;
615 submodule
->fetch_recurse
= (fetch_recurse_submodules
!= 0);
619 int git_submodule_init(git_submodule
*submodule
, int overwrite
)
623 /* write "submodule.NAME.url" */
625 if (!submodule
->url
) {
626 giterr_set(GITERR_SUBMODULE
,
627 "No URL configured for submodule '%s'", submodule
->name
);
631 error
= submodule_update_config(
632 submodule
, "url", submodule
->url
, overwrite
!= 0, false);
636 /* write "submodule.NAME.update" if not default */
638 if (submodule
->update
== GIT_SUBMODULE_UPDATE_CHECKOUT
)
639 error
= submodule_update_config(
640 submodule
, "update", NULL
, (overwrite
!= 0), false);
641 else if (submodule
->update
!= GIT_SUBMODULE_UPDATE_DEFAULT
)
642 error
= submodule_update_config(
644 _sm_update_map
[submodule
->update
].str_match
,
645 (overwrite
!= 0), false);
650 int git_submodule_sync(git_submodule
*submodule
)
652 if (!submodule
->url
) {
653 giterr_set(GITERR_SUBMODULE
,
654 "No URL configured for submodule '%s'", submodule
->name
);
658 /* copy URL over to config only if it already exists */
660 return submodule_update_config(
661 submodule
, "url", submodule
->url
, true, true);
664 int git_submodule_open(
665 git_repository
**subrepo
,
666 git_submodule
*submodule
)
669 git_buf path
= GIT_BUF_INIT
;
670 git_repository
*repo
;
673 assert(submodule
&& subrepo
);
675 repo
= submodule
->owner
;
676 workdir
= git_repository_workdir(repo
);
679 giterr_set(GITERR_REPOSITORY
,
680 "Cannot open submodule repository in a bare repo");
681 return GIT_ENOTFOUND
;
684 if ((submodule
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0) {
685 giterr_set(GITERR_REPOSITORY
,
686 "Cannot open submodule repository that is not checked out");
687 return GIT_ENOTFOUND
;
690 if (git_buf_joinpath(&path
, workdir
, submodule
->path
) < 0)
693 error
= git_repository_open(subrepo
, path
.ptr
);
697 /* if we have opened the submodule successfully, let's grab the HEAD OID */
699 if (!git_reference_name_to_id(
700 &submodule
->wd_oid
, *subrepo
, GIT_HEAD_FILE
))
701 submodule
->flags
|= GIT_SUBMODULE_STATUS__WD_OID_VALID
;
709 int git_submodule_reload_all(git_repository
*repo
)
712 git_submodule_config_free(repo
);
713 return load_submodule_config(repo
);
716 int git_submodule_reload(git_submodule
*submodule
)
718 git_repository
*repo
;
723 git_config_backend
*mods
;
727 /* refresh index data */
729 repo
= submodule
->owner
;
730 if (git_repository_index__weakptr(&index
, repo
) < 0)
733 submodule
->flags
= submodule
->flags
&
734 ~(GIT_SUBMODULE_STATUS_IN_INDEX
|
735 GIT_SUBMODULE_STATUS__INDEX_OID_VALID
);
737 if (!git_index_find(&pos
, index
, submodule
->path
)) {
738 const git_index_entry
*entry
= git_index_get_byindex(index
, pos
);
740 if (S_ISGITLINK(entry
->mode
)) {
741 if ((error
= submodule_load_from_index(repo
, entry
)) < 0)
744 submodule_mode_mismatch(
745 repo
, entry
->path
, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
);
749 /* refresh HEAD tree data */
751 if (!(error
= git_repository_head_tree(&head
, repo
))) {
754 submodule
->flags
= submodule
->flags
&
755 ~(GIT_SUBMODULE_STATUS_IN_HEAD
|
756 GIT_SUBMODULE_STATUS__HEAD_OID_VALID
);
758 if (!(error
= git_tree_entry_bypath(&te
, head
, submodule
->path
))) {
760 if (S_ISGITLINK(te
->attr
)) {
761 error
= submodule_load_from_head(repo
, submodule
->path
, &te
->oid
);
763 submodule_mode_mismatch(
764 repo
, submodule
->path
,
765 GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
);
768 git_tree_entry_free(te
);
770 else if (error
== GIT_ENOTFOUND
) {
781 /* refresh config data */
783 if ((mods
= open_gitmodules(repo
, false, NULL
)) != NULL
) {
784 git_buf path
= GIT_BUF_INIT
;
786 git_buf_sets(&path
, "submodule\\.");
787 git_buf_text_puts_escape_regex(&path
, submodule
->name
);
788 git_buf_puts(&path
, ".*");
790 if (git_buf_oom(&path
))
793 error
= git_config_file_foreach_match(
794 mods
, path
.ptr
, submodule_load_from_config
, repo
);
797 git_config_file_free(mods
);
803 /* refresh wd data */
805 submodule
->flags
= submodule
->flags
&
806 ~(GIT_SUBMODULE_STATUS_IN_WD
| GIT_SUBMODULE_STATUS__WD_OID_VALID
);
808 error
= submodule_load_from_wd_lite(submodule
, submodule
->path
, NULL
);
813 int git_submodule_status(
814 unsigned int *status
,
815 git_submodule
*submodule
)
818 unsigned int status_val
;
820 assert(status
&& submodule
);
822 status_val
= GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(submodule
->flags
);
824 if (submodule
->ignore
!= GIT_SUBMODULE_IGNORE_ALL
) {
825 if (!(error
= submodule_index_status(&status_val
, submodule
)))
826 error
= submodule_wd_status(&status_val
, submodule
);
829 *status
= status_val
;
834 int git_submodule_location(
835 unsigned int *location_status
,
836 git_submodule
*submodule
)
838 assert(location_status
&& submodule
);
840 *location_status
= submodule
->flags
&
841 (GIT_SUBMODULE_STATUS_IN_HEAD
| GIT_SUBMODULE_STATUS_IN_INDEX
|
842 GIT_SUBMODULE_STATUS_IN_CONFIG
| GIT_SUBMODULE_STATUS_IN_WD
);
852 static git_submodule
*submodule_alloc(git_repository
*repo
, const char *name
)
856 if (!name
|| !strlen(name
)) {
857 giterr_set(GITERR_SUBMODULE
, "Invalid submodule name");
861 sm
= git__calloc(1, sizeof(git_submodule
));
865 sm
->path
= sm
->name
= git__strdup(name
);
875 submodule_release(sm
, 0);
879 static void submodule_release(git_submodule
*sm
, int decr
)
884 sm
->refcount
-= decr
;
886 if (sm
->refcount
== 0) {
887 if (sm
->name
!= sm
->path
) {
904 static int submodule_get(
905 git_submodule
**sm_ptr
,
906 git_repository
*repo
,
908 const char *alternate
)
910 git_strmap
*smcfg
= repo
->submodules
;
915 assert(repo
&& name
);
917 pos
= git_strmap_lookup_index(smcfg
, name
);
919 if (!git_strmap_valid_index(smcfg
, pos
) && alternate
)
920 pos
= git_strmap_lookup_index(smcfg
, alternate
);
922 if (!git_strmap_valid_index(smcfg
, pos
)) {
923 sm
= submodule_alloc(repo
, name
);
925 /* insert value at name - if another thread beats us to it, then use
926 * their record and release our own.
928 pos
= kh_put(str
, smcfg
, sm
->name
, &error
);
931 submodule_release(sm
, 1);
933 } else if (error
== 0) {
934 submodule_release(sm
, 1);
935 sm
= git_strmap_value_at(smcfg
, pos
);
937 git_strmap_set_value_at(smcfg
, pos
, sm
);
940 sm
= git_strmap_value_at(smcfg
, pos
);
945 return (sm
!= NULL
) ? 0 : -1;
948 static int submodule_load_from_index(
949 git_repository
*repo
, const git_index_entry
*entry
)
953 if (submodule_get(&sm
, repo
, entry
->path
, NULL
) < 0)
956 if (sm
->flags
& GIT_SUBMODULE_STATUS_IN_INDEX
) {
957 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES
;
961 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_INDEX
;
963 git_oid_cpy(&sm
->index_oid
, &entry
->oid
);
964 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_OID_VALID
;
969 static int submodule_load_from_head(
970 git_repository
*repo
, const char *path
, const git_oid
*oid
)
974 if (submodule_get(&sm
, repo
, path
, NULL
) < 0)
977 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_HEAD
;
979 git_oid_cpy(&sm
->head_oid
, oid
);
980 sm
->flags
|= GIT_SUBMODULE_STATUS__HEAD_OID_VALID
;
985 static int submodule_config_error(const char *property
, const char *value
)
987 giterr_set(GITERR_INVALID
,
988 "Invalid value for submodule '%s' property: '%s'", property
, value
);
992 static int submodule_load_from_config(
993 const git_config_entry
*entry
, void *data
)
995 git_repository
*repo
= data
;
996 git_strmap
*smcfg
= repo
->submodules
;
997 const char *namestart
, *property
, *alternate
= NULL
;
998 const char *key
= entry
->name
, *value
= entry
->value
;
999 git_buf name
= GIT_BUF_INIT
;
1004 if (git__prefixcmp(key
, "submodule.") != 0)
1007 namestart
= key
+ strlen("submodule.");
1008 property
= strrchr(namestart
, '.');
1009 if (property
== NULL
)
1012 is_path
= (strcasecmp(property
, "path") == 0);
1014 if (git_buf_set(&name
, namestart
, property
- namestart
- 1) < 0)
1017 if (submodule_get(&sm
, repo
, name
.ptr
, is_path
? value
: NULL
) < 0) {
1018 git_buf_free(&name
);
1022 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
1024 /* Only from config might we get differing names & paths. If so, then
1025 * update the submodule and insert under the alternative key.
1028 /* TODO: if case insensitive filesystem, then the following strcmps
1029 * should be strcasecmp
1032 if (strcmp(sm
->name
, name
.ptr
) != 0) {
1033 alternate
= sm
->name
= git_buf_detach(&name
);
1034 } else if (is_path
&& value
&& strcmp(sm
->path
, value
) != 0) {
1035 alternate
= sm
->path
= git__strdup(value
);
1040 void *old_sm
= NULL
;
1041 git_strmap_insert2(smcfg
, alternate
, sm
, old_sm
, error
);
1044 sm
->refcount
++; /* inserted under a new key */
1046 /* if we replaced an old module under this key, release the old one */
1047 if (old_sm
&& ((git_submodule
*)old_sm
) != sm
) {
1048 submodule_release(old_sm
, 1);
1049 /* TODO: log warning about multiple submodules with same path */
1053 git_buf_free(&name
);
1057 /* TODO: Look up path in index and if it is present but not a GITLINK
1058 * then this should be deleted (at least to match git's behavior)
1064 /* copy other properties into submodule entry */
1065 if (strcasecmp(property
, "url") == 0) {
1069 if (value
!= NULL
&& (sm
->url
= git__strdup(value
)) == NULL
)
1072 else if (strcasecmp(property
, "update") == 0) {
1074 if (git_config_lookup_map_value(
1075 &val
, _sm_update_map
, ARRAY_SIZE(_sm_update_map
), value
) < 0)
1076 return submodule_config_error("update", value
);
1077 sm
->update_default
= sm
->update
= (git_submodule_update_t
)val
;
1079 else if (strcasecmp(property
, "fetchRecurseSubmodules") == 0) {
1080 if (git__parse_bool(&sm
->fetch_recurse
, value
) < 0)
1081 return submodule_config_error("fetchRecurseSubmodules", value
);
1083 else if (strcasecmp(property
, "ignore") == 0) {
1085 if (git_config_lookup_map_value(
1086 &val
, _sm_ignore_map
, ARRAY_SIZE(_sm_ignore_map
), value
) < 0)
1087 return submodule_config_error("ignore", value
);
1088 sm
->ignore_default
= sm
->ignore
= (git_submodule_ignore_t
)val
;
1090 /* ignore other unknown submodule properties */
1095 static int submodule_load_from_wd_lite(
1096 git_submodule
*sm
, const char *name
, void *payload
)
1098 git_repository
*repo
= git_submodule_owner(sm
);
1099 git_buf path
= GIT_BUF_INIT
;
1102 GIT_UNUSED(payload
);
1104 if (git_buf_joinpath(&path
, git_repository_workdir(repo
), sm
->path
) < 0)
1107 if (git_path_isdir(path
.ptr
))
1108 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
1110 if (git_path_contains(&path
, DOT_GIT
))
1111 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
;
1113 git_buf_free(&path
);
1118 static void submodule_mode_mismatch(
1119 git_repository
*repo
, const char *path
, unsigned int flag
)
1121 khiter_t pos
= git_strmap_lookup_index(repo
->submodules
, path
);
1123 if (git_strmap_valid_index(repo
->submodules
, pos
)) {
1124 git_submodule
*sm
= git_strmap_value_at(repo
->submodules
, pos
);
1130 static int load_submodule_config_from_index(
1131 git_repository
*repo
, git_oid
*gitmodules_oid
)
1136 const git_index_entry
*entry
;
1138 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0 ||
1139 (error
= git_iterator_for_index(&i
, index
, 0, NULL
, NULL
)) < 0)
1142 error
= git_iterator_current(&entry
, i
);
1144 while (!error
&& entry
!= NULL
) {
1146 if (S_ISGITLINK(entry
->mode
)) {
1147 error
= submodule_load_from_index(repo
, entry
);
1151 submodule_mode_mismatch(
1152 repo
, entry
->path
, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
);
1154 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0)
1155 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1158 error
= git_iterator_advance(&entry
, i
);
1161 git_iterator_free(i
);
1166 static int load_submodule_config_from_head(
1167 git_repository
*repo
, git_oid
*gitmodules_oid
)
1172 const git_index_entry
*entry
;
1174 if ((error
= git_repository_head_tree(&head
, repo
)) < 0)
1177 if ((error
= git_iterator_for_tree(&i
, head
, 0, NULL
, NULL
)) < 0) {
1178 git_tree_free(head
);
1182 error
= git_iterator_current(&entry
, i
);
1184 while (!error
&& entry
!= NULL
) {
1186 if (S_ISGITLINK(entry
->mode
)) {
1187 error
= submodule_load_from_head(repo
, entry
->path
, &entry
->oid
);
1191 submodule_mode_mismatch(
1192 repo
, entry
->path
, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
);
1194 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0 &&
1195 git_oid_iszero(gitmodules_oid
))
1196 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1199 error
= git_iterator_advance(&entry
, i
);
1202 git_iterator_free(i
);
1203 git_tree_free(head
);
1208 static git_config_backend
*open_gitmodules(
1209 git_repository
*repo
,
1210 bool okay_to_create
,
1211 const git_oid
*gitmodules_oid
)
1213 const char *workdir
= git_repository_workdir(repo
);
1214 git_buf path
= GIT_BUF_INIT
;
1215 git_config_backend
*mods
= NULL
;
1217 if (workdir
!= NULL
) {
1218 if (git_buf_joinpath(&path
, workdir
, GIT_MODULES_FILE
) != 0)
1221 if (okay_to_create
|| git_path_isfile(path
.ptr
)) {
1222 /* git_config_file__ondisk should only fail if OOM */
1223 if (git_config_file__ondisk(&mods
, path
.ptr
) < 0)
1225 /* open should only fail here if the file is malformed */
1226 else if (git_config_file_open(mods
, GIT_CONFIG_LEVEL_LOCAL
) < 0) {
1227 git_config_file_free(mods
);
1233 if (!mods
&& gitmodules_oid
&& !git_oid_iszero(gitmodules_oid
)) {
1234 /* TODO: Retrieve .gitmodules content from ODB */
1236 /* Should we actually do this? Core git does not, but it means you
1237 * can't really get much information about submodules on bare repos.
1241 git_buf_free(&path
);
1246 static int load_submodule_config(git_repository
*repo
)
1249 git_oid gitmodules_oid
;
1250 git_buf path
= GIT_BUF_INIT
;
1251 git_config_backend
*mods
= NULL
;
1253 if (repo
->submodules
)
1256 memset(&gitmodules_oid
, 0, sizeof(gitmodules_oid
));
1258 /* Submodule data is kept in a hashtable keyed by both name and path.
1259 * These are usually the same, but that is not guaranteed.
1261 if (!repo
->submodules
) {
1262 repo
->submodules
= git_strmap_alloc();
1263 GITERR_CHECK_ALLOC(repo
->submodules
);
1266 /* add submodule information from index */
1268 if ((error
= load_submodule_config_from_index(repo
, &gitmodules_oid
)) < 0)
1271 /* add submodule information from HEAD */
1273 if ((error
= load_submodule_config_from_head(repo
, &gitmodules_oid
)) < 0)
1276 /* add submodule information from .gitmodules */
1278 if ((mods
= open_gitmodules(repo
, false, &gitmodules_oid
)) != NULL
)
1279 error
= git_config_file_foreach(mods
, submodule_load_from_config
, repo
);
1284 /* shallow scan submodules in work tree */
1286 if (!git_repository_is_bare(repo
))
1287 error
= git_submodule_foreach(repo
, submodule_load_from_wd_lite
, NULL
);
1290 git_buf_free(&path
);
1293 git_config_file_free(mods
);
1296 git_submodule_config_free(repo
);
1301 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
)
1305 git_reference
*head
= NULL
, *remote
= NULL
;
1306 const char *tgt
, *scan
;
1307 git_buf key
= GIT_BUF_INIT
;
1309 /* 1. resolve HEAD -> refs/heads/BRANCH
1310 * 2. lookup config branch.BRANCH.remote -> ORIGIN
1311 * 3. lookup remote.ORIGIN.url
1314 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
1317 if (git_reference_lookup(&head
, repo
, GIT_HEAD_FILE
) < 0) {
1318 giterr_set(GITERR_SUBMODULE
,
1319 "Cannot resolve relative URL when HEAD cannot be resolved");
1320 error
= GIT_ENOTFOUND
;
1324 if (git_reference_type(head
) != GIT_REF_SYMBOLIC
) {
1325 giterr_set(GITERR_SUBMODULE
,
1326 "Cannot resolve relative URL when HEAD is not symbolic");
1327 error
= GIT_ENOTFOUND
;
1331 if ((error
= git_branch_upstream(&remote
, head
)) < 0)
1334 /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
1336 if (git_reference_type(remote
) != GIT_REF_SYMBOLIC
||
1337 git__prefixcmp(git_reference_symbolic_target(remote
), GIT_REFS_REMOTES_DIR
) != 0)
1339 giterr_set(GITERR_SUBMODULE
,
1340 "Cannot resolve relative URL when HEAD is not symbolic");
1341 error
= GIT_ENOTFOUND
;
1345 scan
= tgt
= git_reference_symbolic_target(remote
) + strlen(GIT_REFS_REMOTES_DIR
);
1346 while (*scan
&& (*scan
!= '/' || (scan
> tgt
&& scan
[-1] != '\\')))
1347 scan
++; /* find non-escaped slash to end ORIGIN name */
1349 error
= git_buf_printf(&key
, "remote.%.*s.url", (int)(scan
- tgt
), tgt
);
1353 if ((error
= git_config_get_string(&tgt
, cfg
, key
.ptr
)) < 0)
1356 error
= git_buf_sets(url
, tgt
);
1360 git_reference_free(head
);
1361 git_reference_free(remote
);
1366 static int submodule_update_config(
1367 git_submodule
*submodule
,
1375 git_buf key
= GIT_BUF_INIT
;
1376 const char *old
= NULL
;
1380 error
= git_repository_config__weakptr(&config
, submodule
->owner
);
1384 error
= git_buf_printf(&key
, "submodule.%s.%s", submodule
->name
, attr
);
1388 if (git_config_get_string(&old
, config
, key
.ptr
) < 0)
1391 if (!old
&& only_existing
)
1393 if (old
&& !overwrite
)
1395 if ((!old
&& !value
) || (old
&& value
&& strcmp(old
, value
) == 0))
1399 error
= git_config_delete_entry(config
, key
.ptr
);
1401 error
= git_config_set_string(config
, key
.ptr
, value
);
1408 static int submodule_index_status(unsigned int *status
, git_submodule
*sm
)
1410 const git_oid
*head_oid
= git_submodule_head_id(sm
);
1411 const git_oid
*index_oid
= git_submodule_index_id(sm
);
1415 *status
|= GIT_SUBMODULE_STATUS_INDEX_ADDED
;
1417 else if (!index_oid
)
1418 *status
|= GIT_SUBMODULE_STATUS_INDEX_DELETED
;
1419 else if (!git_oid_equal(head_oid
, index_oid
))
1420 *status
|= GIT_SUBMODULE_STATUS_INDEX_MODIFIED
;
1425 static int submodule_wd_status(unsigned int *status
, git_submodule
*sm
)
1428 const git_oid
*wd_oid
, *index_oid
;
1429 git_repository
*sm_repo
= NULL
;
1431 /* open repo now if we need it (so wd_id() call won't reopen) */
1432 if ((sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
||
1433 sm
->ignore
== GIT_SUBMODULE_IGNORE_UNTRACKED
) &&
1434 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) != 0)
1436 if ((error
= git_submodule_open(&sm_repo
, sm
)) < 0)
1440 index_oid
= git_submodule_index_id(sm
);
1441 wd_oid
= git_submodule_wd_id(sm
);
1445 *status
|= GIT_SUBMODULE_STATUS_WD_ADDED
;
1448 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_SCANNED
) != 0 &&
1449 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0)
1450 *status
|= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
;
1452 *status
|= GIT_SUBMODULE_STATUS_WD_DELETED
;
1454 else if (!git_oid_equal(index_oid
, wd_oid
))
1455 *status
|= GIT_SUBMODULE_STATUS_WD_MODIFIED
;
1457 if (sm_repo
!= NULL
) {
1459 git_diff_options opt
= GIT_DIFF_OPTIONS_INIT
;
1460 git_diff_list
*diff
;
1462 /* the diffs below could be optimized with an early termination
1463 * option to the git_diff functions, but for now this is sufficient
1464 * (and certainly no worse that what core git does).
1467 /* perform head-to-index diff on submodule */
1469 if ((error
= git_repository_head_tree(&sm_head
, sm_repo
)) < 0)
1472 if (sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
)
1473 opt
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
;
1475 error
= git_diff_tree_to_index(&diff
, sm_repo
, sm_head
, NULL
, &opt
);
1478 if (git_diff_num_deltas(diff
) > 0)
1479 *status
|= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
;
1481 git_diff_list_free(diff
);
1485 git_tree_free(sm_head
);
1490 /* perform index-to-workdir diff on submodule */
1492 error
= git_diff_index_to_workdir(&diff
, sm_repo
, NULL
, &opt
);
1496 git_diff_num_deltas_of_type(diff
, GIT_DELTA_UNTRACKED
);
1499 *status
|= GIT_SUBMODULE_STATUS_WD_UNTRACKED
;
1501 if (git_diff_num_deltas(diff
) != untracked
)
1502 *status
|= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
;
1504 git_diff_list_free(diff
);
1508 git_repository_free(sm_repo
);