2 * Copyright (C) 2012 the libgit2 contributors
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/types.h"
11 #include "git2/repository.h"
12 #include "git2/index.h"
13 #include "git2/submodule.h"
17 #include "config_file.h"
19 #include "repository.h"
20 #include "submodule.h"
24 #define GIT_MODULES_FILE ".gitmodules"
26 static git_cvar_map _sm_update_map
[] = {
27 {GIT_CVAR_STRING
, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT
},
28 {GIT_CVAR_STRING
, "rebase", GIT_SUBMODULE_UPDATE_REBASE
},
29 {GIT_CVAR_STRING
, "merge", GIT_SUBMODULE_UPDATE_MERGE
},
30 {GIT_CVAR_STRING
, "none", GIT_SUBMODULE_UPDATE_NONE
},
33 static git_cvar_map _sm_ignore_map
[] = {
34 {GIT_CVAR_STRING
, "none", GIT_SUBMODULE_IGNORE_NONE
},
35 {GIT_CVAR_STRING
, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED
},
36 {GIT_CVAR_STRING
, "dirty", GIT_SUBMODULE_IGNORE_DIRTY
},
37 {GIT_CVAR_STRING
, "all", GIT_SUBMODULE_IGNORE_ALL
},
40 static kh_inline khint_t
str_hash_no_trailing_slash(const char *s
)
45 if (s
[1] != '\0' || *s
!= '/')
46 h
= (h
<< 5) - h
+ *s
;
51 static kh_inline
int str_equal_no_trailing_slash(const char *a
, const char *b
)
53 size_t alen
= a
? strlen(a
) : 0;
54 size_t blen
= b
? strlen(b
) : 0;
56 if (alen
> 0 && a
[alen
- 1] == '/')
58 if (blen
> 0 && b
[blen
- 1] == '/')
61 return (alen
== blen
&& strncmp(a
, b
, alen
) == 0);
65 str
, static kh_inline
, const char *, void *, 1,
66 str_hash_no_trailing_slash
, str_equal_no_trailing_slash
);
68 static int load_submodule_config(git_repository
*repo
, bool force
);
69 static git_config_file
*open_gitmodules(git_repository
*, bool, const git_oid
*);
70 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
);
71 static int submodule_get(git_submodule
**, git_repository
*, const char *, const char *);
72 static void submodule_release(git_submodule
*sm
, int decr
);
73 static int submodule_load_from_index(git_repository
*, const git_index_entry
*);
74 static int submodule_load_from_head(git_repository
*, const char*, const git_oid
*);
75 static int submodule_load_from_config(const git_config_entry
*, void *);
76 static int submodule_load_from_wd_lite(git_submodule
*, const char *, void *);
77 static int submodule_update_config(git_submodule
*, const char *, const char *, bool, bool);
78 static void submodule_mode_mismatch(git_repository
*, const char *, unsigned int);
79 static int submodule_index_status(unsigned int *status
, git_submodule
*sm
);
80 static int submodule_wd_status(unsigned int *status
, git_submodule
*sm
);
82 static int submodule_cmp(const void *a
, const void *b
)
84 return strcmp(((git_submodule
*)a
)->name
, ((git_submodule
*)b
)->name
);
87 static int submodule_config_key_trunc_puts(git_buf
*key
, const char *suffix
)
89 ssize_t idx
= git_buf_rfind(key
, '.');
90 git_buf_truncate(key
, (size_t)(idx
+ 1));
91 return git_buf_puts(key
, suffix
);
98 int git_submodule_lookup(
99 git_submodule
**sm_ptr
, /* NULL if user only wants to test existence */
100 git_repository
*repo
,
101 const char *name
) /* trailing slash is allowed */
106 assert(repo
&& name
);
108 if ((error
= load_submodule_config(repo
, false)) < 0)
111 pos
= git_strmap_lookup_index(repo
->submodules
, name
);
113 if (!git_strmap_valid_index(repo
->submodules
, pos
)) {
114 error
= GIT_ENOTFOUND
;
116 /* check if a plausible submodule exists at path */
117 if (git_repository_workdir(repo
)) {
118 git_buf path
= GIT_BUF_INIT
;
120 if (git_buf_joinpath(&path
, git_repository_workdir(repo
), name
) < 0)
123 if (git_path_contains_dir(&path
, DOT_GIT
))
133 *sm_ptr
= git_strmap_value_at(repo
->submodules
, pos
);
138 int git_submodule_foreach(
139 git_repository
*repo
,
140 int (*callback
)(git_submodule
*sm
, const char *name
, void *payload
),
145 git_vector seen
= GIT_VECTOR_INIT
;
146 seen
._cmp
= submodule_cmp
;
148 assert(repo
&& callback
);
150 if ((error
= load_submodule_config(repo
, false)) < 0)
153 git_strmap_foreach_value(repo
->submodules
, sm
, {
154 /* Usually the following will not come into play - it just prevents
155 * us from issuing a callback twice for a submodule where the name
156 * and path are not the same.
158 if (sm
->refcount
> 1) {
159 if (git_vector_bsearch(&seen
, sm
) != GIT_ENOTFOUND
)
161 if ((error
= git_vector_insert(&seen
, sm
)) < 0)
165 if (callback(sm
, sm
->name
, payload
)) {
172 git_vector_free(&seen
);
177 void git_submodule_config_free(git_repository
*repo
)
184 smcfg
= repo
->submodules
;
185 repo
->submodules
= NULL
;
190 git_strmap_foreach_value(smcfg
, sm
, {
191 submodule_release(sm
,1);
193 git_strmap_free(smcfg
);
196 int git_submodule_add_setup(
197 git_submodule
**submodule
,
198 git_repository
*repo
,
204 git_config_file
*mods
= NULL
;
206 git_buf name
= GIT_BUF_INIT
, real_url
= GIT_BUF_INIT
;
207 git_repository_init_options initopt
;
208 git_repository
*subrepo
= NULL
;
210 assert(repo
&& url
&& path
);
212 /* see if there is already an entry for this submodule */
214 if (git_submodule_lookup(&sm
, repo
, path
) < 0)
217 giterr_set(GITERR_SUBMODULE
,
218 "Attempt to add a submodule that already exists");
222 /* resolve parameters */
224 if (url
[0] == '.' && (url
[1] == '/' || (url
[1] == '.' && url
[2] == '/'))) {
225 if (!(error
= lookup_head_remote(&real_url
, repo
)))
226 error
= git_path_apply_relative(&real_url
, url
);
227 } else if (strchr(url
, ':') != NULL
|| url
[0] == '/') {
228 error
= git_buf_sets(&real_url
, url
);
230 giterr_set(GITERR_SUBMODULE
, "Invalid format for submodule URL");
236 /* validate and normalize path */
238 if (git__prefixcmp(path
, git_repository_workdir(repo
)) == 0)
239 path
+= strlen(git_repository_workdir(repo
));
241 if (git_path_root(path
) >= 0) {
242 giterr_set(GITERR_SUBMODULE
, "Submodule path must be a relative path");
247 /* update .gitmodules */
249 if ((mods
= open_gitmodules(repo
, true, NULL
)) == NULL
) {
250 giterr_set(GITERR_SUBMODULE
,
251 "Adding submodules to a bare repository is not supported (for now)");
255 if ((error
= git_buf_printf(&name
, "submodule.%s.path", path
)) < 0 ||
256 (error
= git_config_file_set_string(mods
, name
.ptr
, path
)) < 0)
259 if ((error
= submodule_config_key_trunc_puts(&name
, "url")) < 0 ||
260 (error
= git_config_file_set_string(mods
, name
.ptr
, real_url
.ptr
)) < 0)
263 git_buf_clear(&name
);
265 /* init submodule repository and add origin remote as needed */
267 error
= git_buf_joinpath(&name
, git_repository_workdir(repo
), path
);
271 /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
272 * gitlink in the sub-repo workdir directory to that repository
274 * Old style: sub-repo goes directly into repo/<name>/.git/
277 memset(&initopt
, 0, sizeof(initopt
));
278 initopt
.flags
= GIT_REPOSITORY_INIT_MKPATH
|
279 GIT_REPOSITORY_INIT_NO_REINIT
;
280 initopt
.origin_url
= real_url
.ptr
;
282 if (git_path_exists(name
.ptr
) &&
283 git_path_contains(&name
, DOT_GIT
))
285 /* repo appears to already exist - reinit? */
287 else if (use_gitlink
) {
288 git_buf repodir
= GIT_BUF_INIT
;
290 error
= git_buf_join_n(
291 &repodir
, '/', 3, git_repository_path(repo
), "modules", path
);
295 initopt
.workdir_path
= name
.ptr
;
296 initopt
.flags
|= GIT_REPOSITORY_INIT_NO_DOTGIT_DIR
;
298 error
= git_repository_init_ext(&subrepo
, repodir
.ptr
, &initopt
);
300 git_buf_free(&repodir
);
303 error
= git_repository_init_ext(&subrepo
, name
.ptr
, &initopt
);
308 /* add submodule to hash and "reload" it */
310 if (!(error
= submodule_get(&sm
, repo
, path
, NULL
)) &&
311 !(error
= git_submodule_reload(sm
)))
312 error
= git_submodule_init(sm
, false);
315 if (submodule
!= NULL
)
316 *submodule
= !error
? sm
: NULL
;
319 git_config_file_free(mods
);
320 git_repository_free(subrepo
);
321 git_buf_free(&real_url
);
327 int git_submodule_add_finalize(git_submodule
*sm
)
334 if ((error
= git_repository_index__weakptr(&index
, sm
->owner
)) < 0 ||
335 (error
= git_index_add_from_workdir(index
, GIT_MODULES_FILE
)) < 0)
338 return git_submodule_add_to_index(sm
, true);
341 int git_submodule_add_to_index(git_submodule
*sm
, int write_index
)
344 git_repository
*repo
, *sm_repo
;
346 git_buf path
= GIT_BUF_INIT
;
348 git_index_entry entry
;
355 /* force reload of wd OID by git_submodule_open */
356 sm
->flags
= sm
->flags
& ~GIT_SUBMODULE_STATUS__WD_OID_VALID
;
358 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0 ||
359 (error
= git_buf_joinpath(
360 &path
, git_repository_workdir(repo
), sm
->path
)) < 0 ||
361 (error
= git_submodule_open(&sm_repo
, sm
)) < 0)
364 /* read stat information for submodule working directory */
365 if (p_stat(path
.ptr
, &st
) < 0) {
366 giterr_set(GITERR_SUBMODULE
,
367 "Cannot add submodule without working directory");
372 memset(&entry
, 0, sizeof(entry
));
373 entry
.path
= sm
->path
;
374 git_index__init_entry_from_stat(&st
, &entry
);
376 /* calling git_submodule_open will have set sm->wd_oid if possible */
377 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
) == 0) {
378 giterr_set(GITERR_SUBMODULE
,
379 "Cannot add submodule without HEAD to index");
383 git_oid_cpy(&entry
.oid
, &sm
->wd_oid
);
385 if ((error
= git_commit_lookup(&head
, sm_repo
, &sm
->wd_oid
)) < 0)
388 entry
.ctime
.seconds
= git_commit_time(head
);
389 entry
.ctime
.nanoseconds
= 0;
390 entry
.mtime
.seconds
= git_commit_time(head
);
391 entry
.mtime
.nanoseconds
= 0;
393 git_commit_free(head
);
396 error
= git_index_add(index
, &entry
);
398 /* write it, if requested */
399 if (!error
&& write_index
) {
400 error
= git_index_write(index
);
403 git_oid_cpy(&sm
->index_oid
, &sm
->wd_oid
);
407 git_repository_free(sm_repo
);
412 int git_submodule_save(git_submodule
*submodule
)
415 git_config_file
*mods
;
416 git_buf key
= GIT_BUF_INIT
;
420 mods
= open_gitmodules(submodule
->owner
, true, NULL
);
422 giterr_set(GITERR_SUBMODULE
,
423 "Adding submodules to a bare repository is not supported (for now)");
427 if ((error
= git_buf_printf(&key
, "submodule.%s.", submodule
->name
)) < 0)
430 /* save values for path, url, update, ignore, fetchRecurseSubmodules */
432 if ((error
= submodule_config_key_trunc_puts(&key
, "path")) < 0 ||
433 (error
= git_config_file_set_string(mods
, key
.ptr
, submodule
->path
)) < 0)
436 if ((error
= submodule_config_key_trunc_puts(&key
, "url")) < 0 ||
437 (error
= git_config_file_set_string(mods
, key
.ptr
, submodule
->url
)) < 0)
440 if (!(error
= submodule_config_key_trunc_puts(&key
, "update")) &&
441 submodule
->update
!= GIT_SUBMODULE_UPDATE_DEFAULT
)
443 const char *val
= (submodule
->update
== GIT_SUBMODULE_UPDATE_CHECKOUT
) ?
444 NULL
: _sm_update_map
[submodule
->update
].str_match
;
445 error
= git_config_file_set_string(mods
, key
.ptr
, val
);
450 if (!(error
= submodule_config_key_trunc_puts(&key
, "ignore")) &&
451 submodule
->ignore
!= GIT_SUBMODULE_IGNORE_DEFAULT
)
453 const char *val
= (submodule
->ignore
== GIT_SUBMODULE_IGNORE_NONE
) ?
454 NULL
: _sm_ignore_map
[submodule
->ignore
].str_match
;
455 error
= git_config_file_set_string(mods
, key
.ptr
, val
);
460 if ((error
= submodule_config_key_trunc_puts(
461 &key
, "fetchRecurseSubmodules")) < 0 ||
462 (error
= git_config_file_set_string(
463 mods
, key
.ptr
, submodule
->fetch_recurse
? "true" : "false")) < 0)
466 /* update internal defaults */
468 submodule
->ignore_default
= submodule
->ignore
;
469 submodule
->update_default
= submodule
->update
;
470 submodule
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
474 git_config_file_free(mods
);
480 git_repository
*git_submodule_owner(git_submodule
*submodule
)
483 return submodule
->owner
;
486 const char *git_submodule_name(git_submodule
*submodule
)
489 return submodule
->name
;
492 const char *git_submodule_path(git_submodule
*submodule
)
495 return submodule
->path
;
498 const char *git_submodule_url(git_submodule
*submodule
)
501 return submodule
->url
;
504 int git_submodule_set_url(git_submodule
*submodule
, const char *url
)
506 assert(submodule
&& url
);
508 git__free(submodule
->url
);
510 submodule
->url
= git__strdup(url
);
511 GITERR_CHECK_ALLOC(submodule
->url
);
516 const git_oid
*git_submodule_index_oid(git_submodule
*submodule
)
520 if (submodule
->flags
& GIT_SUBMODULE_STATUS__INDEX_OID_VALID
)
521 return &submodule
->index_oid
;
526 const git_oid
*git_submodule_head_oid(git_submodule
*submodule
)
530 if (submodule
->flags
& GIT_SUBMODULE_STATUS__HEAD_OID_VALID
)
531 return &submodule
->head_oid
;
536 const git_oid
*git_submodule_wd_oid(git_submodule
*submodule
)
540 if (!(submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)) {
541 git_repository
*subrepo
;
543 /* calling submodule open grabs the HEAD OID if possible */
544 if (!git_submodule_open(&subrepo
, submodule
))
545 git_repository_free(subrepo
);
550 if (submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)
551 return &submodule
->wd_oid
;
556 git_submodule_ignore_t
git_submodule_ignore(git_submodule
*submodule
)
559 return submodule
->ignore
;
562 git_submodule_ignore_t
git_submodule_set_ignore(
563 git_submodule
*submodule
, git_submodule_ignore_t ignore
)
565 git_submodule_ignore_t old
;
569 if (ignore
== GIT_SUBMODULE_IGNORE_DEFAULT
)
570 ignore
= submodule
->ignore_default
;
572 old
= submodule
->ignore
;
573 submodule
->ignore
= ignore
;
577 git_submodule_update_t
git_submodule_update(git_submodule
*submodule
)
580 return submodule
->update
;
583 git_submodule_update_t
git_submodule_set_update(
584 git_submodule
*submodule
, git_submodule_update_t update
)
586 git_submodule_update_t old
;
590 if (update
== GIT_SUBMODULE_UPDATE_DEFAULT
)
591 update
= submodule
->update_default
;
593 old
= submodule
->update
;
594 submodule
->update
= update
;
598 int git_submodule_fetch_recurse_submodules(
599 git_submodule
*submodule
)
602 return submodule
->fetch_recurse
;
605 int git_submodule_set_fetch_recurse_submodules(
606 git_submodule
*submodule
,
607 int fetch_recurse_submodules
)
613 old
= submodule
->fetch_recurse
;
614 submodule
->fetch_recurse
= (fetch_recurse_submodules
!= 0);
618 int git_submodule_init(git_submodule
*submodule
, int overwrite
)
622 /* write "submodule.NAME.url" */
624 if (!submodule
->url
) {
625 giterr_set(GITERR_SUBMODULE
,
626 "No URL configured for submodule '%s'", submodule
->name
);
630 error
= submodule_update_config(
631 submodule
, "url", submodule
->url
, overwrite
!= 0, false);
635 /* write "submodule.NAME.update" if not default */
637 if (submodule
->update
== GIT_SUBMODULE_UPDATE_CHECKOUT
)
638 error
= submodule_update_config(
639 submodule
, "update", NULL
, (overwrite
!= 0), false);
640 else if (submodule
->update
!= GIT_SUBMODULE_UPDATE_DEFAULT
)
641 error
= submodule_update_config(
643 _sm_update_map
[submodule
->update
].str_match
,
644 (overwrite
!= 0), false);
649 int git_submodule_sync(git_submodule
*submodule
)
651 if (!submodule
->url
) {
652 giterr_set(GITERR_SUBMODULE
,
653 "No URL configured for submodule '%s'", submodule
->name
);
657 /* copy URL over to config only if it already exists */
659 return submodule_update_config(
660 submodule
, "url", submodule
->url
, true, true);
663 int git_submodule_open(
664 git_repository
**subrepo
,
665 git_submodule
*submodule
)
668 git_buf path
= GIT_BUF_INIT
;
669 git_repository
*repo
;
672 assert(submodule
&& subrepo
);
674 repo
= submodule
->owner
;
675 workdir
= git_repository_workdir(repo
);
678 giterr_set(GITERR_REPOSITORY
,
679 "Cannot open submodule repository in a bare repo");
680 return GIT_ENOTFOUND
;
683 if ((submodule
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0) {
684 giterr_set(GITERR_REPOSITORY
,
685 "Cannot open submodule repository that is not checked out");
686 return GIT_ENOTFOUND
;
689 if (git_buf_joinpath(&path
, workdir
, submodule
->path
) < 0)
692 error
= git_repository_open(subrepo
, path
.ptr
);
696 /* if we have opened the submodule successfully, let's grab the HEAD OID */
697 if (!error
&& !(submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)) {
698 if (!git_reference_name_to_oid(
699 &submodule
->wd_oid
, *subrepo
, GIT_HEAD_FILE
))
700 submodule
->flags
|= GIT_SUBMODULE_STATUS__WD_OID_VALID
;
708 int git_submodule_reload_all(git_repository
*repo
)
711 return load_submodule_config(repo
, true);
714 int git_submodule_reload(git_submodule
*submodule
)
716 git_repository
*repo
;
720 git_config_file
*mods
;
724 /* refresh index data */
726 repo
= submodule
->owner
;
727 if (git_repository_index__weakptr(&index
, repo
) < 0)
730 submodule
->flags
= submodule
->flags
&
731 ~(GIT_SUBMODULE_STATUS_IN_INDEX
|
732 GIT_SUBMODULE_STATUS__INDEX_OID_VALID
);
734 pos
= git_index_find(index
, submodule
->path
);
736 git_index_entry
*entry
= git_index_get_byindex(index
, pos
);
738 if (S_ISGITLINK(entry
->mode
)) {
739 if ((error
= submodule_load_from_index(repo
, entry
)) < 0)
742 submodule_mode_mismatch(
743 repo
, entry
->path
, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
);
747 /* refresh HEAD tree data */
749 if (!(error
= git_repository_head_tree(&head
, repo
))) {
752 submodule
->flags
= submodule
->flags
&
753 ~(GIT_SUBMODULE_STATUS_IN_HEAD
|
754 GIT_SUBMODULE_STATUS__HEAD_OID_VALID
);
756 if (!(error
= git_tree_entry_bypath(&te
, head
, submodule
->path
))) {
758 if (S_ISGITLINK(te
->attr
)) {
759 error
= submodule_load_from_head(repo
, submodule
->path
, &te
->oid
);
761 submodule_mode_mismatch(
762 repo
, submodule
->path
,
763 GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
);
766 git_tree_entry_free(te
);
768 else if (error
== GIT_ENOTFOUND
) {
779 /* refresh config data */
781 if ((mods
= open_gitmodules(repo
, false, NULL
)) != NULL
) {
782 git_buf path
= GIT_BUF_INIT
;
784 git_buf_sets(&path
, "submodule\\.");
785 git_buf_puts_escape_regex(&path
, submodule
->name
);
786 git_buf_puts(&path
, ".*");
788 if (git_buf_oom(&path
))
791 error
= git_config_file_foreach_match(
792 mods
, path
.ptr
, submodule_load_from_config
, repo
);
795 git_config_file_free(mods
);
801 /* refresh wd data */
803 submodule
->flags
= submodule
->flags
&
804 ~(GIT_SUBMODULE_STATUS_IN_WD
| GIT_SUBMODULE_STATUS__WD_OID_VALID
);
806 error
= submodule_load_from_wd_lite(submodule
, submodule
->path
, NULL
);
811 int git_submodule_status(
812 unsigned int *status
,
813 git_submodule
*submodule
)
816 unsigned int status_val
;
818 assert(status
&& submodule
);
820 status_val
= GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(submodule
->flags
);
822 if (submodule
->ignore
!= GIT_SUBMODULE_IGNORE_ALL
) {
823 if (!(error
= submodule_index_status(&status_val
, submodule
)))
824 error
= submodule_wd_status(&status_val
, submodule
);
827 *status
= status_val
;
836 static git_submodule
*submodule_alloc(git_repository
*repo
, const char *name
)
840 if (!name
|| !strlen(name
)) {
841 giterr_set(GITERR_SUBMODULE
, "Invalid submodule name");
845 sm
= git__calloc(1, sizeof(git_submodule
));
849 sm
->path
= sm
->name
= git__strdup(name
);
859 submodule_release(sm
, 0);
863 static void submodule_release(git_submodule
*sm
, int decr
)
868 sm
->refcount
-= decr
;
870 if (sm
->refcount
== 0) {
871 if (sm
->name
!= sm
->path
) {
888 static int submodule_get(
889 git_submodule
**sm_ptr
,
890 git_repository
*repo
,
892 const char *alternate
)
894 git_strmap
*smcfg
= repo
->submodules
;
899 assert(repo
&& name
);
901 pos
= git_strmap_lookup_index(smcfg
, name
);
903 if (!git_strmap_valid_index(smcfg
, pos
) && alternate
)
904 pos
= git_strmap_lookup_index(smcfg
, alternate
);
906 if (!git_strmap_valid_index(smcfg
, pos
)) {
907 sm
= submodule_alloc(repo
, name
);
909 /* insert value at name - if another thread beats us to it, then use
910 * their record and release our own.
912 pos
= kh_put(str
, smcfg
, sm
->name
, &error
);
915 submodule_release(sm
, 1);
917 } else if (error
== 0) {
918 submodule_release(sm
, 1);
919 sm
= git_strmap_value_at(smcfg
, pos
);
921 git_strmap_set_value_at(smcfg
, pos
, sm
);
924 sm
= git_strmap_value_at(smcfg
, pos
);
929 return (sm
!= NULL
) ? 0 : -1;
932 static int submodule_load_from_index(
933 git_repository
*repo
, const git_index_entry
*entry
)
937 if (submodule_get(&sm
, repo
, entry
->path
, NULL
) < 0)
940 if (sm
->flags
& GIT_SUBMODULE_STATUS_IN_INDEX
) {
941 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES
;
945 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_INDEX
;
947 git_oid_cpy(&sm
->index_oid
, &entry
->oid
);
948 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_OID_VALID
;
953 static int submodule_load_from_head(
954 git_repository
*repo
, const char *path
, const git_oid
*oid
)
958 if (submodule_get(&sm
, repo
, path
, NULL
) < 0)
961 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_HEAD
;
963 git_oid_cpy(&sm
->head_oid
, oid
);
964 sm
->flags
|= GIT_SUBMODULE_STATUS__HEAD_OID_VALID
;
969 static int submodule_config_error(const char *property
, const char *value
)
971 giterr_set(GITERR_INVALID
,
972 "Invalid value for submodule '%s' property: '%s'", property
, value
);
976 static int submodule_load_from_config(
977 const git_config_entry
*entry
, void *data
)
979 git_repository
*repo
= data
;
980 git_strmap
*smcfg
= repo
->submodules
;
981 const char *namestart
, *property
, *alternate
= NULL
;
982 const char *key
= entry
->name
, *value
= entry
->value
;
983 git_buf name
= GIT_BUF_INIT
;
988 if (git__prefixcmp(key
, "submodule.") != 0)
991 namestart
= key
+ strlen("submodule.");
992 property
= strrchr(namestart
, '.');
993 if (property
== NULL
)
996 is_path
= (strcasecmp(property
, "path") == 0);
998 if (git_buf_set(&name
, namestart
, property
- namestart
- 1) < 0)
1001 if (submodule_get(&sm
, repo
, name
.ptr
, is_path
? value
: NULL
) < 0) {
1002 git_buf_free(&name
);
1006 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
1008 /* Only from config might we get differing names & paths. If so, then
1009 * update the submodule and insert under the alternative key.
1012 /* TODO: if case insensitive filesystem, then the following strcmps
1013 * should be strcasecmp
1016 if (strcmp(sm
->name
, name
.ptr
) != 0) {
1017 alternate
= sm
->name
= git_buf_detach(&name
);
1018 } else if (is_path
&& value
&& strcmp(sm
->path
, value
) != 0) {
1019 alternate
= sm
->path
= git__strdup(value
);
1024 void *old_sm
= NULL
;
1025 git_strmap_insert2(smcfg
, alternate
, sm
, old_sm
, error
);
1028 sm
->refcount
++; /* inserted under a new key */
1030 /* if we replaced an old module under this key, release the old one */
1031 if (old_sm
&& ((git_submodule
*)old_sm
) != sm
) {
1032 submodule_release(old_sm
, 1);
1033 /* TODO: log warning about multiple submodules with same path */
1037 git_buf_free(&name
);
1041 /* TODO: Look up path in index and if it is present but not a GITLINK
1042 * then this should be deleted (at least to match git's behavior)
1048 /* copy other properties into submodule entry */
1049 if (strcasecmp(property
, "url") == 0) {
1053 if (value
!= NULL
&& (sm
->url
= git__strdup(value
)) == NULL
)
1056 else if (strcasecmp(property
, "update") == 0) {
1058 if (git_config_lookup_map_value(
1059 &val
, _sm_update_map
, ARRAY_SIZE(_sm_update_map
), value
) < 0)
1060 return submodule_config_error("update", value
);
1061 sm
->update_default
= sm
->update
= (git_submodule_update_t
)val
;
1063 else if (strcasecmp(property
, "fetchRecurseSubmodules") == 0) {
1064 if (git__parse_bool(&sm
->fetch_recurse
, value
) < 0)
1065 return submodule_config_error("fetchRecurseSubmodules", value
);
1067 else if (strcasecmp(property
, "ignore") == 0) {
1069 if (git_config_lookup_map_value(
1070 &val
, _sm_ignore_map
, ARRAY_SIZE(_sm_ignore_map
), value
) < 0)
1071 return submodule_config_error("ignore", value
);
1072 sm
->ignore_default
= sm
->ignore
= (git_submodule_ignore_t
)val
;
1074 /* ignore other unknown submodule properties */
1079 static int submodule_load_from_wd_lite(
1080 git_submodule
*sm
, const char *name
, void *payload
)
1082 git_repository
*repo
= git_submodule_owner(sm
);
1083 git_buf path
= GIT_BUF_INIT
;
1086 GIT_UNUSED(payload
);
1088 if (git_buf_joinpath(&path
, git_repository_workdir(repo
), sm
->path
) < 0)
1091 if (git_path_isdir(path
.ptr
))
1092 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
1094 if (git_path_contains(&path
, DOT_GIT
))
1095 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
;
1097 git_buf_free(&path
);
1102 static void submodule_mode_mismatch(
1103 git_repository
*repo
, const char *path
, unsigned int flag
)
1105 khiter_t pos
= git_strmap_lookup_index(repo
->submodules
, path
);
1107 if (git_strmap_valid_index(repo
->submodules
, pos
)) {
1108 git_submodule
*sm
= git_strmap_value_at(repo
->submodules
, pos
);
1114 static int load_submodule_config_from_index(
1115 git_repository
*repo
, git_oid
*gitmodules_oid
)
1119 const git_index_entry
*entry
;
1121 if ((error
= git_iterator_for_index(&i
, repo
)) < 0)
1124 error
= git_iterator_current(i
, &entry
);
1126 while (!error
&& entry
!= NULL
) {
1128 if (S_ISGITLINK(entry
->mode
)) {
1129 error
= submodule_load_from_index(repo
, entry
);
1133 submodule_mode_mismatch(
1134 repo
, entry
->path
, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
);
1136 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0)
1137 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1140 error
= git_iterator_advance(i
, &entry
);
1143 git_iterator_free(i
);
1148 static int load_submodule_config_from_head(
1149 git_repository
*repo
, git_oid
*gitmodules_oid
)
1154 const git_index_entry
*entry
;
1156 if ((error
= git_repository_head_tree(&head
, repo
)) < 0)
1159 if ((error
= git_iterator_for_tree(&i
, repo
, head
)) < 0) {
1160 git_tree_free(head
);
1164 error
= git_iterator_current(i
, &entry
);
1166 while (!error
&& entry
!= NULL
) {
1168 if (S_ISGITLINK(entry
->mode
)) {
1169 error
= submodule_load_from_head(repo
, entry
->path
, &entry
->oid
);
1173 submodule_mode_mismatch(
1174 repo
, entry
->path
, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
);
1176 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0 &&
1177 git_oid_iszero(gitmodules_oid
))
1178 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1181 error
= git_iterator_advance(i
, &entry
);
1184 git_iterator_free(i
);
1185 git_tree_free(head
);
1190 static git_config_file
*open_gitmodules(
1191 git_repository
*repo
,
1192 bool okay_to_create
,
1193 const git_oid
*gitmodules_oid
)
1195 const char *workdir
= git_repository_workdir(repo
);
1196 git_buf path
= GIT_BUF_INIT
;
1197 git_config_file
*mods
= NULL
;
1199 if (workdir
!= NULL
) {
1200 if (git_buf_joinpath(&path
, workdir
, GIT_MODULES_FILE
) != 0)
1203 if (okay_to_create
|| git_path_isfile(path
.ptr
)) {
1204 /* git_config_file__ondisk should only fail if OOM */
1205 if (git_config_file__ondisk(&mods
, path
.ptr
) < 0)
1207 /* open should only fail here if the file is malformed */
1208 else if (git_config_file_open(mods
, GIT_CONFIG_LEVEL_LOCAL
) < 0) {
1209 git_config_file_free(mods
);
1215 if (!mods
&& gitmodules_oid
&& !git_oid_iszero(gitmodules_oid
)) {
1216 /* TODO: Retrieve .gitmodules content from ODB */
1218 /* Should we actually do this? Core git does not, but it means you
1219 * can't really get much information about submodules on bare repos.
1223 git_buf_free(&path
);
1228 static int load_submodule_config(git_repository
*repo
, bool force
)
1231 git_oid gitmodules_oid
;
1232 git_buf path
= GIT_BUF_INIT
;
1233 git_config_file
*mods
= NULL
;
1235 if (repo
->submodules
&& !force
)
1238 memset(&gitmodules_oid
, 0, sizeof(gitmodules_oid
));
1240 /* Submodule data is kept in a hashtable keyed by both name and path.
1241 * These are usually the same, but that is not guaranteed.
1243 if (!repo
->submodules
) {
1244 repo
->submodules
= git_strmap_alloc();
1245 GITERR_CHECK_ALLOC(repo
->submodules
);
1248 /* add submodule information from index */
1250 if ((error
= load_submodule_config_from_index(repo
, &gitmodules_oid
)) < 0)
1253 /* add submodule information from HEAD */
1255 if ((error
= load_submodule_config_from_head(repo
, &gitmodules_oid
)) < 0)
1258 /* add submodule information from .gitmodules */
1260 if ((mods
= open_gitmodules(repo
, false, &gitmodules_oid
)) != NULL
)
1261 error
= git_config_file_foreach(mods
, submodule_load_from_config
, repo
);
1266 /* shallow scan submodules in work tree */
1268 if (!git_repository_is_bare(repo
))
1269 error
= git_submodule_foreach(repo
, submodule_load_from_wd_lite
, NULL
);
1272 git_buf_free(&path
);
1275 git_config_file_free(mods
);
1278 git_submodule_config_free(repo
);
1283 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
)
1287 git_reference
*head
= NULL
, *remote
= NULL
;
1288 const char *tgt
, *scan
;
1289 git_buf key
= GIT_BUF_INIT
;
1291 /* 1. resolve HEAD -> refs/heads/BRANCH
1292 * 2. lookup config branch.BRANCH.remote -> ORIGIN
1293 * 3. lookup remote.ORIGIN.url
1296 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
1299 if (git_reference_lookup(&head
, repo
, GIT_HEAD_FILE
) < 0) {
1300 giterr_set(GITERR_SUBMODULE
,
1301 "Cannot resolve relative URL when HEAD cannot be resolved");
1302 error
= GIT_ENOTFOUND
;
1306 if (git_reference_type(head
) != GIT_REF_SYMBOLIC
) {
1307 giterr_set(GITERR_SUBMODULE
,
1308 "Cannot resolve relative URL when HEAD is not symbolic");
1309 error
= GIT_ENOTFOUND
;
1313 if ((error
= git_branch_tracking(&remote
, head
)) < 0)
1316 /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
1318 if (git_reference_type(remote
) != GIT_REF_SYMBOLIC
||
1319 git__prefixcmp(git_reference_target(remote
), GIT_REFS_REMOTES_DIR
) != 0)
1321 giterr_set(GITERR_SUBMODULE
,
1322 "Cannot resolve relative URL when HEAD is not symbolic");
1323 error
= GIT_ENOTFOUND
;
1327 scan
= tgt
= git_reference_target(remote
) + strlen(GIT_REFS_REMOTES_DIR
);
1328 while (*scan
&& (*scan
!= '/' || (scan
> tgt
&& scan
[-1] != '\\')))
1329 scan
++; /* find non-escaped slash to end ORIGIN name */
1331 error
= git_buf_printf(&key
, "remote.%.*s.url", (int)(scan
- tgt
), tgt
);
1335 if ((error
= git_config_get_string(&tgt
, cfg
, key
.ptr
)) < 0)
1338 error
= git_buf_sets(url
, tgt
);
1342 git_reference_free(head
);
1343 git_reference_free(remote
);
1348 static int submodule_update_config(
1349 git_submodule
*submodule
,
1357 git_buf key
= GIT_BUF_INIT
;
1358 const char *old
= NULL
;
1362 error
= git_repository_config__weakptr(&config
, submodule
->owner
);
1366 error
= git_buf_printf(&key
, "submodule.%s.%s", submodule
->name
, attr
);
1370 if (git_config_get_string(&old
, config
, key
.ptr
) < 0)
1373 if (!old
&& only_existing
)
1375 if (old
&& !overwrite
)
1377 if ((!old
&& !value
) || (old
&& value
&& strcmp(old
, value
) == 0))
1381 error
= git_config_delete(config
, key
.ptr
);
1383 error
= git_config_set_string(config
, key
.ptr
, value
);
1390 static int submodule_index_status(unsigned int *status
, git_submodule
*sm
)
1392 const git_oid
*head_oid
= git_submodule_head_oid(sm
);
1393 const git_oid
*index_oid
= git_submodule_index_oid(sm
);
1397 *status
|= GIT_SUBMODULE_STATUS_INDEX_ADDED
;
1399 else if (!index_oid
)
1400 *status
|= GIT_SUBMODULE_STATUS_INDEX_DELETED
;
1401 else if (!git_oid_equal(head_oid
, index_oid
))
1402 *status
|= GIT_SUBMODULE_STATUS_INDEX_MODIFIED
;
1407 static int submodule_wd_status(unsigned int *status
, git_submodule
*sm
)
1410 const git_oid
*wd_oid
, *index_oid
;
1411 git_repository
*sm_repo
= NULL
;
1413 /* open repo now if we need it (so wd_oid() call won't reopen) */
1414 if ((sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
||
1415 sm
->ignore
== GIT_SUBMODULE_IGNORE_UNTRACKED
) &&
1416 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) != 0)
1418 if ((error
= git_submodule_open(&sm_repo
, sm
)) < 0)
1422 index_oid
= git_submodule_index_oid(sm
);
1423 wd_oid
= git_submodule_wd_oid(sm
);
1427 *status
|= GIT_SUBMODULE_STATUS_WD_ADDED
;
1430 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_SCANNED
) != 0 &&
1431 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0)
1432 *status
|= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
;
1434 *status
|= GIT_SUBMODULE_STATUS_WD_DELETED
;
1436 else if (!git_oid_equal(index_oid
, wd_oid
))
1437 *status
|= GIT_SUBMODULE_STATUS_WD_MODIFIED
;
1439 if (sm_repo
!= NULL
) {
1441 git_diff_options opt
;
1442 git_diff_list
*diff
;
1444 /* the diffs below could be optimized with an early termination
1445 * option to the git_diff functions, but for now this is sufficient
1446 * (and certainly no worse that what core git does).
1449 /* perform head-to-index diff on submodule */
1451 if ((error
= git_repository_head_tree(&sm_head
, sm_repo
)) < 0)
1454 memset(&opt
, 0, sizeof(opt
));
1455 if (sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
)
1456 opt
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
;
1458 error
= git_diff_index_to_tree(sm_repo
, &opt
, sm_head
, &diff
);
1461 if (git_diff_num_deltas(diff
) > 0)
1462 *status
|= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
;
1464 git_diff_list_free(diff
);
1468 git_tree_free(sm_head
);
1473 /* perform index-to-workdir diff on submodule */
1475 error
= git_diff_workdir_to_index(sm_repo
, &opt
, &diff
);
1479 git_diff_num_deltas_of_type(diff
, GIT_DELTA_UNTRACKED
);
1482 *status
|= GIT_SUBMODULE_STATUS_WD_UNTRACKED
;
1484 if ((git_diff_num_deltas(diff
) - untracked
) > 0)
1485 *status
|= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
;
1487 git_diff_list_free(diff
);
1491 git_repository_free(sm_repo
);