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/index.h"
17 #include "config_file.h"
19 #include "repository.h"
20 #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
},
33 {GIT_CVAR_FALSE
, NULL
, GIT_SUBMODULE_UPDATE_NONE
},
34 {GIT_CVAR_TRUE
, NULL
, GIT_SUBMODULE_UPDATE_CHECKOUT
},
37 static git_cvar_map _sm_ignore_map
[] = {
38 {GIT_CVAR_STRING
, "none", GIT_SUBMODULE_IGNORE_NONE
},
39 {GIT_CVAR_STRING
, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED
},
40 {GIT_CVAR_STRING
, "dirty", GIT_SUBMODULE_IGNORE_DIRTY
},
41 {GIT_CVAR_STRING
, "all", GIT_SUBMODULE_IGNORE_ALL
},
42 {GIT_CVAR_FALSE
, NULL
, GIT_SUBMODULE_IGNORE_NONE
},
43 {GIT_CVAR_TRUE
, NULL
, GIT_SUBMODULE_IGNORE_ALL
},
46 static kh_inline khint_t
str_hash_no_trailing_slash(const char *s
)
51 if (s
[1] != '\0' || *s
!= '/')
52 h
= (h
<< 5) - h
+ *s
;
57 static kh_inline
int str_equal_no_trailing_slash(const char *a
, const char *b
)
59 size_t alen
= a
? strlen(a
) : 0;
60 size_t blen
= b
? strlen(b
) : 0;
62 if (alen
> 0 && a
[alen
- 1] == '/')
64 if (blen
> 0 && b
[blen
- 1] == '/')
67 return (alen
== blen
&& strncmp(a
, b
, alen
) == 0);
71 str
, static kh_inline
, const char *, void *, 1,
72 str_hash_no_trailing_slash
, str_equal_no_trailing_slash
);
74 static int load_submodule_config(git_repository
*repo
);
75 static git_config_backend
*open_gitmodules(git_repository
*, bool, const git_oid
*);
76 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
);
77 static int submodule_get(git_submodule
**, git_repository
*, const char *, const char *);
78 static int submodule_load_from_config(const git_config_entry
*, void *);
79 static int submodule_load_from_wd_lite(git_submodule
*, const char *, void *);
80 static int submodule_update_config(git_submodule
*, const char *, const char *, bool, bool);
81 static void submodule_get_index_status(unsigned int *, git_submodule
*);
82 static void submodule_get_wd_status(unsigned int *, git_submodule
*, git_repository
*, git_submodule_ignore_t
);
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
))
131 giterr_set(GITERR_SUBMODULE
, (error
== GIT_ENOTFOUND
) ?
132 "No submodule named '%s'" :
133 "Submodule '%s' has not been added yet", name
);
139 *sm_ptr
= git_strmap_value_at(repo
->submodules
, pos
);
144 int git_submodule_foreach(
145 git_repository
*repo
,
146 int (*callback
)(git_submodule
*sm
, const char *name
, void *payload
),
151 git_vector seen
= GIT_VECTOR_INIT
;
152 git_vector_set_cmp(&seen
, submodule_cmp
);
154 assert(repo
&& callback
);
156 if ((error
= load_submodule_config(repo
)) < 0)
159 git_strmap_foreach_value(repo
->submodules
, sm
, {
160 /* Usually the following will not come into play - it just prevents
161 * us from issuing a callback twice for a submodule where the name
162 * and path are not the same.
164 if (GIT_REFCOUNT_VAL(sm
) > 1) {
165 if (git_vector_bsearch(NULL
, &seen
, sm
) != GIT_ENOTFOUND
)
167 if ((error
= git_vector_insert(&seen
, sm
)) < 0)
171 if (callback(sm
, sm
->name
, payload
)) {
178 git_vector_free(&seen
);
183 void git_submodule_config_free(git_repository
*repo
)
190 smcfg
= repo
->submodules
;
191 repo
->submodules
= NULL
;
196 git_strmap_foreach_value(smcfg
, sm
, { git_submodule_free(sm
); });
197 git_strmap_free(smcfg
);
200 int git_submodule_add_setup(
201 git_submodule
**submodule
,
202 git_repository
*repo
,
208 git_config_backend
*mods
= NULL
;
210 git_buf name
= GIT_BUF_INIT
, real_url
= GIT_BUF_INIT
;
211 git_repository_init_options initopt
= GIT_REPOSITORY_INIT_OPTIONS_INIT
;
212 git_repository
*subrepo
= NULL
;
214 assert(repo
&& url
&& path
);
216 /* see if there is already an entry for this submodule */
218 if (git_submodule_lookup(&sm
, repo
, path
) < 0)
221 giterr_set(GITERR_SUBMODULE
,
222 "Attempt to add a submodule that already exists");
226 /* resolve parameters */
228 if (url
[0] == '.' && (url
[1] == '/' || (url
[1] == '.' && url
[2] == '/'))) {
229 if (!(error
= lookup_head_remote(&real_url
, repo
)))
230 error
= git_path_apply_relative(&real_url
, url
);
231 } else if (strchr(url
, ':') != NULL
|| url
[0] == '/') {
232 error
= git_buf_sets(&real_url
, url
);
234 giterr_set(GITERR_SUBMODULE
, "Invalid format for submodule URL");
240 /* validate and normalize path */
242 if (git__prefixcmp(path
, git_repository_workdir(repo
)) == 0)
243 path
+= strlen(git_repository_workdir(repo
));
245 if (git_path_root(path
) >= 0) {
246 giterr_set(GITERR_SUBMODULE
, "Submodule path must be a relative path");
251 /* update .gitmodules */
253 if ((mods
= open_gitmodules(repo
, true, NULL
)) == NULL
) {
254 giterr_set(GITERR_SUBMODULE
,
255 "Adding submodules to a bare repository is not supported (for now)");
259 if ((error
= git_buf_printf(&name
, "submodule.%s.path", path
)) < 0 ||
260 (error
= git_config_file_set_string(mods
, name
.ptr
, path
)) < 0)
263 if ((error
= submodule_config_key_trunc_puts(&name
, "url")) < 0 ||
264 (error
= git_config_file_set_string(mods
, name
.ptr
, real_url
.ptr
)) < 0)
267 git_buf_clear(&name
);
269 /* init submodule repository and add origin remote as needed */
271 error
= git_buf_joinpath(&name
, git_repository_workdir(repo
), path
);
275 /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
276 * gitlink in the sub-repo workdir directory to that repository
278 * Old style: sub-repo goes directly into repo/<name>/.git/
281 initopt
.flags
= GIT_REPOSITORY_INIT_MKPATH
|
282 GIT_REPOSITORY_INIT_NO_REINIT
;
283 initopt
.origin_url
= real_url
.ptr
;
285 if (git_path_exists(name
.ptr
) &&
286 git_path_contains(&name
, DOT_GIT
))
288 /* repo appears to already exist - reinit? */
290 else if (use_gitlink
) {
291 git_buf repodir
= GIT_BUF_INIT
;
293 error
= git_buf_join_n(
294 &repodir
, '/', 3, git_repository_path(repo
), "modules", path
);
298 initopt
.workdir_path
= name
.ptr
;
299 initopt
.flags
|= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR
;
301 error
= git_repository_init_ext(&subrepo
, repodir
.ptr
, &initopt
);
303 git_buf_free(&repodir
);
306 error
= git_repository_init_ext(&subrepo
, name
.ptr
, &initopt
);
311 /* add submodule to hash and "reload" it */
313 if (!(error
= submodule_get(&sm
, repo
, path
, NULL
)) &&
314 !(error
= git_submodule_reload(sm
)))
315 error
= git_submodule_init(sm
, false);
318 if (submodule
!= NULL
)
319 *submodule
= !error
? sm
: NULL
;
322 git_config_file_free(mods
);
323 git_repository_free(subrepo
);
324 git_buf_free(&real_url
);
330 int git_submodule_add_finalize(git_submodule
*sm
)
337 if ((error
= git_repository_index__weakptr(&index
, sm
->repo
)) < 0 ||
338 (error
= git_index_add_bypath(index
, GIT_MODULES_FILE
)) < 0)
341 return git_submodule_add_to_index(sm
, true);
344 int git_submodule_add_to_index(git_submodule
*sm
, int write_index
)
347 git_repository
*sm_repo
= NULL
;
349 git_buf path
= GIT_BUF_INIT
;
351 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
, sm
->repo
)) < 0 ||
360 (error
= git_buf_joinpath(
361 &path
, git_repository_workdir(sm
->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 const char *git_submodule_ignore_to_str(git_submodule_ignore_t ignore
)
416 for (i
= 0; i
< (int)ARRAY_SIZE(_sm_ignore_map
); ++i
)
417 if (_sm_ignore_map
[i
].map_value
== ignore
)
418 return _sm_ignore_map
[i
].str_match
;
422 const char *git_submodule_update_to_str(git_submodule_update_t update
)
425 for (i
= 0; i
< (int)ARRAY_SIZE(_sm_update_map
); ++i
)
426 if (_sm_update_map
[i
].map_value
== update
)
427 return _sm_update_map
[i
].str_match
;
431 int git_submodule_save(git_submodule
*submodule
)
434 git_config_backend
*mods
;
435 git_buf key
= GIT_BUF_INIT
;
440 mods
= open_gitmodules(submodule
->repo
, true, NULL
);
442 giterr_set(GITERR_SUBMODULE
,
443 "Adding submodules to a bare repository is not supported (for now)");
447 if ((error
= git_buf_printf(&key
, "submodule.%s.", submodule
->name
)) < 0)
450 /* save values for path, url, update, ignore, fetchRecurseSubmodules */
452 if ((error
= submodule_config_key_trunc_puts(&key
, "path")) < 0 ||
453 (error
= git_config_file_set_string(mods
, key
.ptr
, submodule
->path
)) < 0)
456 if ((error
= submodule_config_key_trunc_puts(&key
, "url")) < 0 ||
457 (error
= git_config_file_set_string(mods
, key
.ptr
, submodule
->url
)) < 0)
460 if (!(error
= submodule_config_key_trunc_puts(&key
, "update")) &&
461 (val
= git_submodule_update_to_str(submodule
->update
)) != NULL
)
462 error
= git_config_file_set_string(mods
, key
.ptr
, val
);
466 if (!(error
= submodule_config_key_trunc_puts(&key
, "ignore")) &&
467 (val
= git_submodule_ignore_to_str(submodule
->ignore
)) != NULL
)
468 error
= git_config_file_set_string(mods
, key
.ptr
, val
);
472 if ((error
= submodule_config_key_trunc_puts(
473 &key
, "fetchRecurseSubmodules")) < 0 ||
474 (error
= git_config_file_set_string(
475 mods
, key
.ptr
, submodule
->fetch_recurse
? "true" : "false")) < 0)
478 /* update internal defaults */
480 submodule
->ignore_default
= submodule
->ignore
;
481 submodule
->update_default
= submodule
->update
;
482 submodule
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
486 git_config_file_free(mods
);
492 git_repository
*git_submodule_owner(git_submodule
*submodule
)
495 return submodule
->repo
;
498 const char *git_submodule_name(git_submodule
*submodule
)
501 return submodule
->name
;
504 const char *git_submodule_path(git_submodule
*submodule
)
507 return submodule
->path
;
510 const char *git_submodule_url(git_submodule
*submodule
)
513 return submodule
->url
;
516 int git_submodule_set_url(git_submodule
*submodule
, const char *url
)
518 assert(submodule
&& url
);
520 git__free(submodule
->url
);
522 submodule
->url
= git__strdup(url
);
523 GITERR_CHECK_ALLOC(submodule
->url
);
528 const git_oid
*git_submodule_index_id(git_submodule
*submodule
)
532 if (submodule
->flags
& GIT_SUBMODULE_STATUS__INDEX_OID_VALID
)
533 return &submodule
->index_oid
;
538 const git_oid
*git_submodule_head_id(git_submodule
*submodule
)
542 if (submodule
->flags
& GIT_SUBMODULE_STATUS__HEAD_OID_VALID
)
543 return &submodule
->head_oid
;
548 const git_oid
*git_submodule_wd_id(git_submodule
*submodule
)
552 /* load unless we think we have a valid oid */
553 if (!(submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)) {
554 git_repository
*subrepo
;
556 /* calling submodule open grabs the HEAD OID if possible */
557 if (!git_submodule_open_bare(&subrepo
, submodule
))
558 git_repository_free(subrepo
);
563 if (submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)
564 return &submodule
->wd_oid
;
569 git_submodule_ignore_t
git_submodule_ignore(git_submodule
*submodule
)
572 return (submodule
->ignore
< GIT_SUBMODULE_IGNORE_NONE
) ?
573 GIT_SUBMODULE_IGNORE_NONE
: submodule
->ignore
;
576 git_submodule_ignore_t
git_submodule_set_ignore(
577 git_submodule
*submodule
, git_submodule_ignore_t ignore
)
579 git_submodule_ignore_t old
;
583 if (ignore
== GIT_SUBMODULE_IGNORE_RESET
)
584 ignore
= submodule
->ignore_default
;
586 old
= submodule
->ignore
;
587 submodule
->ignore
= ignore
;
591 git_submodule_update_t
git_submodule_update(git_submodule
*submodule
)
594 return (submodule
->update
< GIT_SUBMODULE_UPDATE_CHECKOUT
) ?
595 GIT_SUBMODULE_UPDATE_CHECKOUT
: submodule
->update
;
598 git_submodule_update_t
git_submodule_set_update(
599 git_submodule
*submodule
, git_submodule_update_t update
)
601 git_submodule_update_t old
;
605 if (update
== GIT_SUBMODULE_UPDATE_RESET
)
606 update
= submodule
->update_default
;
608 old
= submodule
->update
;
609 submodule
->update
= update
;
613 int git_submodule_fetch_recurse_submodules(
614 git_submodule
*submodule
)
617 return submodule
->fetch_recurse
;
620 int git_submodule_set_fetch_recurse_submodules(
621 git_submodule
*submodule
,
622 int fetch_recurse_submodules
)
628 old
= submodule
->fetch_recurse
;
629 submodule
->fetch_recurse
= (fetch_recurse_submodules
!= 0);
633 int git_submodule_init(git_submodule
*submodule
, int overwrite
)
638 /* write "submodule.NAME.url" */
640 if (!submodule
->url
) {
641 giterr_set(GITERR_SUBMODULE
,
642 "No URL configured for submodule '%s'", submodule
->name
);
646 error
= submodule_update_config(
647 submodule
, "url", submodule
->url
, overwrite
!= 0, false);
651 /* write "submodule.NAME.update" if not default */
653 val
= (submodule
->update
== GIT_SUBMODULE_UPDATE_CHECKOUT
) ?
654 NULL
: git_submodule_update_to_str(submodule
->update
);
655 error
= submodule_update_config(
656 submodule
, "update", val
, (overwrite
!= 0), false);
661 int git_submodule_sync(git_submodule
*submodule
)
663 if (!submodule
->url
) {
664 giterr_set(GITERR_SUBMODULE
,
665 "No URL configured for submodule '%s'", submodule
->name
);
669 /* copy URL over to config only if it already exists */
671 return submodule_update_config(
672 submodule
, "url", submodule
->url
, true, true);
675 static int git_submodule__open(
676 git_repository
**subrepo
, git_submodule
*sm
, bool bare
)
679 git_buf path
= GIT_BUF_INIT
;
680 unsigned int flags
= GIT_REPOSITORY_OPEN_NO_SEARCH
;
683 assert(sm
&& subrepo
);
685 if (git_repository__ensure_not_bare(
686 sm
->repo
, "open submodule repository") < 0)
687 return GIT_EBAREREPO
;
689 wd
= git_repository_workdir(sm
->repo
);
691 if (git_buf_joinpath(&path
, wd
, sm
->path
) < 0 ||
692 git_buf_joinpath(&path
, path
.ptr
, DOT_GIT
) < 0)
695 sm
->flags
= sm
->flags
&
696 ~(GIT_SUBMODULE_STATUS_IN_WD
|
697 GIT_SUBMODULE_STATUS__WD_OID_VALID
|
698 GIT_SUBMODULE_STATUS__WD_SCANNED
);
701 flags
|= GIT_REPOSITORY_OPEN_BARE
;
703 error
= git_repository_open_ext(subrepo
, path
.ptr
, flags
, wd
);
705 /* if we opened the submodule successfully, grab HEAD OID, etc. */
707 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
|
708 GIT_SUBMODULE_STATUS__WD_SCANNED
;
710 if (!git_reference_name_to_id(&sm
->wd_oid
, *subrepo
, GIT_HEAD_FILE
))
711 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_OID_VALID
;
714 } else if (git_path_exists(path
.ptr
)) {
715 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
|
716 GIT_SUBMODULE_STATUS_IN_WD
;
718 git_buf_rtruncate_at_char(&path
, '/'); /* remove "/.git" */
720 if (git_path_isdir(path
.ptr
))
721 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
729 int git_submodule_open_bare(git_repository
**subrepo
, git_submodule
*sm
)
731 return git_submodule__open(subrepo
, sm
, true);
734 int git_submodule_open(git_repository
**subrepo
, git_submodule
*sm
)
736 return git_submodule__open(subrepo
, sm
, false);
739 int git_submodule_reload_all(git_repository
*repo
)
742 git_submodule_config_free(repo
);
743 return load_submodule_config(repo
);
746 static void submodule_update_from_index_entry(
747 git_submodule
*sm
, const git_index_entry
*ie
)
749 bool already_found
= (sm
->flags
& GIT_SUBMODULE_STATUS_IN_INDEX
) != 0;
751 if (!S_ISGITLINK(ie
->mode
)) {
753 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
;
756 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES
;
758 git_oid_cpy(&sm
->index_oid
, &ie
->oid
);
760 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_INDEX
|
761 GIT_SUBMODULE_STATUS__INDEX_OID_VALID
;
765 static int submodule_update_index(git_submodule
*sm
)
768 const git_index_entry
*ie
;
770 if (git_repository_index__weakptr(&index
, sm
->repo
) < 0)
773 sm
->flags
= sm
->flags
&
774 ~(GIT_SUBMODULE_STATUS_IN_INDEX
|
775 GIT_SUBMODULE_STATUS__INDEX_OID_VALID
);
777 if (!(ie
= git_index_get_bypath(index
, sm
->path
, 0)))
780 submodule_update_from_index_entry(sm
, ie
);
785 static void submodule_update_from_head_data(
786 git_submodule
*sm
, mode_t mode
, const git_oid
*id
)
788 if (!S_ISGITLINK(mode
))
789 sm
->flags
|= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
;
791 git_oid_cpy(&sm
->head_oid
, id
);
793 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_HEAD
|
794 GIT_SUBMODULE_STATUS__HEAD_OID_VALID
;
798 static int submodule_update_head(git_submodule
*submodule
)
800 git_tree
*head
= NULL
;
801 git_tree_entry
*te
= NULL
;
803 submodule
->flags
= submodule
->flags
&
804 ~(GIT_SUBMODULE_STATUS_IN_HEAD
|
805 GIT_SUBMODULE_STATUS__HEAD_OID_VALID
);
807 /* if we can't look up file in current head, then done */
808 if (git_repository_head_tree(&head
, submodule
->repo
) < 0 ||
809 git_tree_entry_bypath(&te
, head
, submodule
->path
) < 0)
812 submodule_update_from_head_data(submodule
, te
->attr
, &te
->oid
);
814 git_tree_entry_free(te
);
819 int git_submodule_reload(git_submodule
*submodule
)
822 git_config_backend
*mods
;
826 /* refresh index data */
828 if (submodule_update_index(submodule
) < 0)
831 /* refresh HEAD tree data */
833 if (submodule_update_head(submodule
) < 0)
836 /* refresh config data */
838 mods
= open_gitmodules(submodule
->repo
, false, NULL
);
840 git_buf path
= GIT_BUF_INIT
;
842 git_buf_sets(&path
, "submodule\\.");
843 git_buf_text_puts_escape_regex(&path
, submodule
->name
);
844 git_buf_puts(&path
, ".*");
846 if (git_buf_oom(&path
))
849 error
= git_config_file_foreach_match(
850 mods
, path
.ptr
, submodule_load_from_config
, submodule
->repo
);
853 git_config_file_free(mods
);
859 /* refresh wd data */
861 submodule
->flags
= submodule
->flags
&
862 ~(GIT_SUBMODULE_STATUS_IN_WD
| GIT_SUBMODULE_STATUS__WD_OID_VALID
);
864 error
= submodule_load_from_wd_lite(submodule
, submodule
->path
, NULL
);
869 static void submodule_copy_oid_maybe(
870 git_oid
*tgt
, const git_oid
*src
, bool valid
)
874 memcpy(tgt
, src
, sizeof(*tgt
));
876 memset(tgt
, 0, sizeof(*tgt
));
880 int git_submodule__status(
881 unsigned int *out_status
,
882 git_oid
*out_head_id
,
883 git_oid
*out_index_id
,
886 git_submodule_ignore_t ign
)
889 git_repository
*smrepo
= NULL
;
891 if (ign
< GIT_SUBMODULE_IGNORE_NONE
)
894 /* only return location info if ignore == all */
895 if (ign
== GIT_SUBMODULE_IGNORE_ALL
) {
896 *out_status
= (sm
->flags
& GIT_SUBMODULE_STATUS__IN_FLAGS
);
900 /* refresh the index OID */
901 if (submodule_update_index(sm
) < 0)
904 /* refresh the HEAD OID */
905 if (submodule_update_head(sm
) < 0)
908 /* for ignore == dirty, don't scan the working directory */
909 if (ign
== GIT_SUBMODULE_IGNORE_DIRTY
) {
910 /* git_submodule_open_bare will load WD OID data */
911 if (git_submodule_open_bare(&smrepo
, sm
) < 0)
914 git_repository_free(smrepo
);
916 } else if (git_submodule_open(&smrepo
, sm
) < 0) {
921 status
= GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(sm
->flags
);
923 submodule_get_index_status(&status
, sm
);
924 submodule_get_wd_status(&status
, sm
, smrepo
, ign
);
926 git_repository_free(smrepo
);
928 *out_status
= status
;
930 submodule_copy_oid_maybe(out_head_id
, &sm
->head_oid
,
931 (sm
->flags
& GIT_SUBMODULE_STATUS__HEAD_OID_VALID
) != 0);
932 submodule_copy_oid_maybe(out_index_id
, &sm
->index_oid
,
933 (sm
->flags
& GIT_SUBMODULE_STATUS__INDEX_OID_VALID
) != 0);
934 submodule_copy_oid_maybe(out_wd_id
, &sm
->wd_oid
,
935 (sm
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
) != 0);
940 int git_submodule_status(unsigned int *status
, git_submodule
*sm
)
942 assert(status
&& sm
);
944 return git_submodule__status(status
, NULL
, NULL
, NULL
, sm
, 0);
947 int git_submodule_location(unsigned int *location
, git_submodule
*sm
)
949 assert(location
&& sm
);
951 return git_submodule__status(
952 location
, NULL
, NULL
, NULL
, sm
, GIT_SUBMODULE_IGNORE_ALL
);
960 static git_submodule
*submodule_alloc(git_repository
*repo
, const char *name
)
965 if (!name
|| !(namelen
= strlen(name
))) {
966 giterr_set(GITERR_SUBMODULE
, "Invalid submodule name");
970 sm
= git__calloc(1, sizeof(git_submodule
));
974 sm
->name
= sm
->path
= git__strdup(name
);
980 GIT_REFCOUNT_INC(sm
);
981 sm
->ignore
= sm
->ignore_default
= GIT_SUBMODULE_IGNORE_NONE
;
982 sm
->update
= sm
->update_default
= GIT_SUBMODULE_UPDATE_CHECKOUT
;
988 static void submodule_release(git_submodule
*sm
)
993 if (sm
->path
!= sm
->name
)
997 git__memzero(sm
, sizeof(*sm
));
1001 void git_submodule_free(git_submodule
*sm
)
1005 GIT_REFCOUNT_DEC(sm
, submodule_release
);
1008 static int submodule_get(
1009 git_submodule
**sm_ptr
,
1010 git_repository
*repo
,
1012 const char *alternate
)
1014 git_strmap
*smcfg
= repo
->submodules
;
1019 assert(repo
&& name
);
1021 pos
= git_strmap_lookup_index(smcfg
, name
);
1023 if (!git_strmap_valid_index(smcfg
, pos
) && alternate
)
1024 pos
= git_strmap_lookup_index(smcfg
, alternate
);
1026 if (!git_strmap_valid_index(smcfg
, pos
)) {
1027 sm
= submodule_alloc(repo
, name
);
1028 GITERR_CHECK_ALLOC(sm
);
1030 /* insert value at name - if another thread beats us to it, then use
1031 * their record and release our own.
1033 pos
= kh_put(str
, smcfg
, sm
->name
, &error
);
1036 git_submodule_free(sm
);
1038 } else if (error
== 0) {
1039 git_submodule_free(sm
);
1040 sm
= git_strmap_value_at(smcfg
, pos
);
1042 git_strmap_set_value_at(smcfg
, pos
, sm
);
1045 sm
= git_strmap_value_at(smcfg
, pos
);
1050 return (sm
!= NULL
) ? 0 : -1;
1053 static int submodule_config_error(const char *property
, const char *value
)
1055 giterr_set(GITERR_INVALID
,
1056 "Invalid value for submodule '%s' property: '%s'", property
, value
);
1060 int git_submodule_parse_ignore(git_submodule_ignore_t
*out
, const char *value
)
1064 if (git_config_lookup_map_value(
1065 &val
, _sm_ignore_map
, ARRAY_SIZE(_sm_ignore_map
), value
) < 0) {
1066 *out
= GIT_SUBMODULE_IGNORE_NONE
;
1067 return submodule_config_error("ignore", value
);
1070 *out
= (git_submodule_ignore_t
)val
;
1074 int git_submodule_parse_update(git_submodule_update_t
*out
, const char *value
)
1078 if (git_config_lookup_map_value(
1079 &val
, _sm_update_map
, ARRAY_SIZE(_sm_update_map
), value
) < 0) {
1080 *out
= GIT_SUBMODULE_UPDATE_CHECKOUT
;
1081 return submodule_config_error("update", value
);
1084 *out
= (git_submodule_update_t
)val
;
1088 static int submodule_load_from_config(
1089 const git_config_entry
*entry
, void *data
)
1091 git_repository
*repo
= data
;
1092 git_strmap
*smcfg
= repo
->submodules
;
1093 const char *namestart
, *property
, *alternate
= NULL
;
1094 const char *key
= entry
->name
, *value
= entry
->value
;
1095 git_buf name
= GIT_BUF_INIT
;
1100 if (git__prefixcmp(key
, "submodule.") != 0)
1103 namestart
= key
+ strlen("submodule.");
1104 property
= strrchr(namestart
, '.');
1106 if (!property
|| (property
== namestart
))
1110 is_path
= (strcasecmp(property
, "path") == 0);
1112 if (git_buf_set(&name
, namestart
, property
- namestart
- 1) < 0)
1115 if (submodule_get(&sm
, repo
, name
.ptr
, is_path
? value
: NULL
) < 0) {
1116 git_buf_free(&name
);
1120 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
1122 /* Only from config might we get differing names & paths. If so, then
1123 * update the submodule and insert under the alternative key.
1126 /* TODO: if case insensitive filesystem, then the following strcmps
1127 * should be strcasecmp
1130 if (strcmp(sm
->name
, name
.ptr
) != 0) {
1131 alternate
= sm
->name
= git_buf_detach(&name
);
1132 } else if (is_path
&& value
&& strcmp(sm
->path
, value
) != 0) {
1133 alternate
= sm
->path
= git__strdup(value
);
1138 void *old_sm
= NULL
;
1139 git_strmap_insert2(smcfg
, alternate
, sm
, old_sm
, error
);
1142 GIT_REFCOUNT_INC(sm
); /* inserted under a new key */
1144 /* if we replaced an old module under this key, release the old one */
1145 if (old_sm
&& ((git_submodule
*)old_sm
) != sm
) {
1146 git_submodule_free(old_sm
);
1147 /* TODO: log warning about multiple submodules with same path */
1151 git_buf_free(&name
);
1155 /* TODO: Look up path in index and if it is present but not a GITLINK
1156 * then this should be deleted (at least to match git's behavior)
1162 /* copy other properties into submodule entry */
1163 if (strcasecmp(property
, "url") == 0) {
1167 if (value
!= NULL
&& (sm
->url
= git__strdup(value
)) == NULL
)
1170 else if (strcasecmp(property
, "update") == 0) {
1171 if (git_submodule_parse_update(&sm
->update
, value
) < 0)
1173 sm
->update_default
= sm
->update
;
1175 else if (strcasecmp(property
, "fetchRecurseSubmodules") == 0) {
1176 if (git__parse_bool(&sm
->fetch_recurse
, value
) < 0)
1177 return submodule_config_error("fetchRecurseSubmodules", value
);
1179 else if (strcasecmp(property
, "ignore") == 0) {
1180 if (git_submodule_parse_ignore(&sm
->ignore
, value
) < 0)
1182 sm
->ignore_default
= sm
->ignore
;
1184 /* ignore other unknown submodule properties */
1189 static int submodule_load_from_wd_lite(
1190 git_submodule
*sm
, const char *name
, void *payload
)
1192 git_buf path
= GIT_BUF_INIT
;
1195 GIT_UNUSED(payload
);
1197 if (git_repository_is_bare(sm
->repo
))
1200 if (git_buf_joinpath(&path
, git_repository_workdir(sm
->repo
), sm
->path
) < 0)
1203 if (git_path_isdir(path
.ptr
))
1204 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
1206 if (git_path_contains(&path
, DOT_GIT
))
1207 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
;
1209 git_buf_free(&path
);
1214 static int load_submodule_config_from_index(
1215 git_repository
*repo
, git_oid
*gitmodules_oid
)
1220 const git_index_entry
*entry
;
1222 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0 ||
1223 (error
= git_iterator_for_index(&i
, index
, 0, NULL
, NULL
)) < 0)
1226 while (!(error
= git_iterator_advance(&entry
, i
))) {
1227 khiter_t pos
= git_strmap_lookup_index(repo
->submodules
, entry
->path
);
1230 if (git_strmap_valid_index(repo
->submodules
, pos
)) {
1231 sm
= git_strmap_value_at(repo
->submodules
, pos
);
1233 if (S_ISGITLINK(entry
->mode
))
1234 submodule_update_from_index_entry(sm
, entry
);
1236 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
;
1237 } else if (S_ISGITLINK(entry
->mode
)) {
1238 if (!submodule_get(&sm
, repo
, entry
->path
, NULL
))
1239 submodule_update_from_index_entry(sm
, entry
);
1240 } else if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0)
1241 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1244 if (error
== GIT_ITEROVER
)
1247 git_iterator_free(i
);
1252 static int load_submodule_config_from_head(
1253 git_repository
*repo
, git_oid
*gitmodules_oid
)
1258 const git_index_entry
*entry
;
1260 /* if we can't look up current head, then there's no submodule in it */
1261 if (git_repository_head_tree(&head
, repo
) < 0) {
1266 if ((error
= git_iterator_for_tree(&i
, head
, 0, NULL
, NULL
)) < 0) {
1267 git_tree_free(head
);
1271 while (!(error
= git_iterator_advance(&entry
, i
))) {
1272 khiter_t pos
= git_strmap_lookup_index(repo
->submodules
, entry
->path
);
1275 if (git_strmap_valid_index(repo
->submodules
, pos
)) {
1276 sm
= git_strmap_value_at(repo
->submodules
, pos
);
1278 if (S_ISGITLINK(entry
->mode
))
1279 submodule_update_from_head_data(
1280 sm
, entry
->mode
, &entry
->oid
);
1282 sm
->flags
|= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
;
1283 } else if (S_ISGITLINK(entry
->mode
)) {
1284 if (!submodule_get(&sm
, repo
, entry
->path
, NULL
))
1285 submodule_update_from_head_data(
1286 sm
, entry
->mode
, &entry
->oid
);
1287 } else if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0 &&
1288 git_oid_iszero(gitmodules_oid
)) {
1289 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1293 if (error
== GIT_ITEROVER
)
1296 git_iterator_free(i
);
1297 git_tree_free(head
);
1302 static git_config_backend
*open_gitmodules(
1303 git_repository
*repo
,
1304 bool okay_to_create
,
1305 const git_oid
*gitmodules_oid
)
1307 const char *workdir
= git_repository_workdir(repo
);
1308 git_buf path
= GIT_BUF_INIT
;
1309 git_config_backend
*mods
= NULL
;
1311 if (workdir
!= NULL
) {
1312 if (git_buf_joinpath(&path
, workdir
, GIT_MODULES_FILE
) != 0)
1315 if (okay_to_create
|| git_path_isfile(path
.ptr
)) {
1316 /* git_config_file__ondisk should only fail if OOM */
1317 if (git_config_file__ondisk(&mods
, path
.ptr
) < 0)
1319 /* open should only fail here if the file is malformed */
1320 else if (git_config_file_open(mods
, GIT_CONFIG_LEVEL_LOCAL
) < 0) {
1321 git_config_file_free(mods
);
1327 if (!mods
&& gitmodules_oid
&& !git_oid_iszero(gitmodules_oid
)) {
1328 /* TODO: Retrieve .gitmodules content from ODB */
1330 /* Should we actually do this? Core git does not, but it means you
1331 * can't really get much information about submodules on bare repos.
1335 git_buf_free(&path
);
1340 static int load_submodule_config(git_repository
*repo
)
1343 git_oid gitmodules_oid
;
1344 git_buf path
= GIT_BUF_INIT
;
1345 git_config_backend
*mods
= NULL
;
1347 if (repo
->submodules
)
1350 memset(&gitmodules_oid
, 0, sizeof(gitmodules_oid
));
1352 /* Submodule data is kept in a hashtable keyed by both name and path.
1353 * These are usually the same, but that is not guaranteed.
1355 if (!repo
->submodules
) {
1356 repo
->submodules
= git_strmap_alloc();
1357 GITERR_CHECK_ALLOC(repo
->submodules
);
1360 /* add submodule information from index */
1362 if ((error
= load_submodule_config_from_index(repo
, &gitmodules_oid
)) < 0)
1365 /* add submodule information from HEAD */
1367 if ((error
= load_submodule_config_from_head(repo
, &gitmodules_oid
)) < 0)
1370 /* add submodule information from .gitmodules */
1372 if ((mods
= open_gitmodules(repo
, false, &gitmodules_oid
)) != NULL
)
1373 error
= git_config_file_foreach(mods
, submodule_load_from_config
, repo
);
1378 /* shallow scan submodules in work tree */
1380 if (!git_repository_is_bare(repo
))
1381 error
= git_submodule_foreach(repo
, submodule_load_from_wd_lite
, NULL
);
1384 git_buf_free(&path
);
1387 git_config_file_free(mods
);
1390 git_submodule_config_free(repo
);
1395 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
)
1399 git_reference
*head
= NULL
, *remote
= NULL
;
1400 const char *tgt
, *scan
;
1401 git_buf key
= GIT_BUF_INIT
;
1403 /* 1. resolve HEAD -> refs/heads/BRANCH
1404 * 2. lookup config branch.BRANCH.remote -> ORIGIN
1405 * 3. lookup remote.ORIGIN.url
1408 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
1411 if (git_reference_lookup(&head
, repo
, GIT_HEAD_FILE
) < 0) {
1412 giterr_set(GITERR_SUBMODULE
,
1413 "Cannot resolve relative URL when HEAD cannot be resolved");
1414 error
= GIT_ENOTFOUND
;
1418 if (git_reference_type(head
) != GIT_REF_SYMBOLIC
) {
1419 giterr_set(GITERR_SUBMODULE
,
1420 "Cannot resolve relative URL when HEAD is not symbolic");
1421 error
= GIT_ENOTFOUND
;
1425 if ((error
= git_branch_upstream(&remote
, head
)) < 0)
1428 /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
1430 if (git_reference_type(remote
) != GIT_REF_SYMBOLIC
||
1431 git__prefixcmp(git_reference_symbolic_target(remote
), GIT_REFS_REMOTES_DIR
) != 0)
1433 giterr_set(GITERR_SUBMODULE
,
1434 "Cannot resolve relative URL when HEAD is not symbolic");
1435 error
= GIT_ENOTFOUND
;
1439 scan
= tgt
= git_reference_symbolic_target(remote
) + strlen(GIT_REFS_REMOTES_DIR
);
1440 while (*scan
&& (*scan
!= '/' || (scan
> tgt
&& scan
[-1] != '\\')))
1441 scan
++; /* find non-escaped slash to end ORIGIN name */
1443 error
= git_buf_printf(&key
, "remote.%.*s.url", (int)(scan
- tgt
), tgt
);
1447 if ((error
= git_config_get_string(&tgt
, cfg
, key
.ptr
)) < 0)
1450 error
= git_buf_sets(url
, tgt
);
1454 git_reference_free(head
);
1455 git_reference_free(remote
);
1460 static int submodule_update_config(
1461 git_submodule
*submodule
,
1469 git_buf key
= GIT_BUF_INIT
;
1470 const char *old
= NULL
;
1474 error
= git_repository_config__weakptr(&config
, submodule
->repo
);
1478 error
= git_buf_printf(&key
, "submodule.%s.%s", submodule
->name
, attr
);
1482 if (git_config_get_string(&old
, config
, key
.ptr
) < 0)
1485 if (!old
&& only_existing
)
1487 if (old
&& !overwrite
)
1489 if ((!old
&& !value
) || (old
&& value
&& strcmp(old
, value
) == 0))
1493 error
= git_config_delete_entry(config
, key
.ptr
);
1495 error
= git_config_set_string(config
, key
.ptr
, value
);
1502 static void submodule_get_index_status(unsigned int *status
, git_submodule
*sm
)
1504 const git_oid
*head_oid
= git_submodule_head_id(sm
);
1505 const git_oid
*index_oid
= git_submodule_index_id(sm
);
1507 *status
= *status
& ~GIT_SUBMODULE_STATUS__INDEX_FLAGS
;
1511 *status
|= GIT_SUBMODULE_STATUS_INDEX_ADDED
;
1513 else if (!index_oid
)
1514 *status
|= GIT_SUBMODULE_STATUS_INDEX_DELETED
;
1515 else if (!git_oid_equal(head_oid
, index_oid
))
1516 *status
|= GIT_SUBMODULE_STATUS_INDEX_MODIFIED
;
1519 static void submodule_get_wd_status(
1520 unsigned int *status
,
1522 git_repository
*sm_repo
,
1523 git_submodule_ignore_t ign
)
1525 const git_oid
*index_oid
= git_submodule_index_id(sm
);
1526 const git_oid
*wd_oid
=
1527 (sm
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
) ? &sm
->wd_oid
: NULL
;
1528 git_tree
*sm_head
= NULL
;
1529 git_diff_options opt
= GIT_DIFF_OPTIONS_INIT
;
1530 git_diff_list
*diff
;
1532 *status
= *status
& ~GIT_SUBMODULE_STATUS__WD_FLAGS
;
1536 *status
|= GIT_SUBMODULE_STATUS_WD_ADDED
;
1539 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_SCANNED
) != 0 &&
1540 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0)
1541 *status
|= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
;
1543 *status
|= GIT_SUBMODULE_STATUS_WD_DELETED
;
1545 else if (!git_oid_equal(index_oid
, wd_oid
))
1546 *status
|= GIT_SUBMODULE_STATUS_WD_MODIFIED
;
1548 /* if we have no repo, then we're done */
1552 /* the diffs below could be optimized with an early termination
1553 * option to the git_diff functions, but for now this is sufficient
1554 * (and certainly no worse that what core git does).
1557 if (ign
== GIT_SUBMODULE_IGNORE_NONE
)
1558 opt
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
;
1560 /* if we don't have an unborn head, check diff with index */
1561 if (git_repository_head_tree(&sm_head
, sm_repo
) < 0)
1564 /* perform head to index diff on submodule */
1565 if (git_diff_tree_to_index(&diff
, sm_repo
, sm_head
, NULL
, &opt
) < 0)
1568 if (git_diff_num_deltas(diff
) > 0)
1569 *status
|= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
;
1570 git_diff_list_free(diff
);
1574 git_tree_free(sm_head
);
1577 /* perform index-to-workdir diff on submodule */
1578 if (git_diff_index_to_workdir(&diff
, sm_repo
, NULL
, &opt
) < 0)
1582 git_diff_num_deltas_of_type(diff
, GIT_DELTA_UNTRACKED
);
1585 *status
|= GIT_SUBMODULE_STATUS_WD_UNTRACKED
;
1587 if (git_diff_num_deltas(diff
) != untracked
)
1588 *status
|= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
;
1590 git_diff_list_free(diff
);