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"
18 #include "config_file.h"
20 #include "repository.h"
21 #include "submodule.h"
25 #define GIT_MODULES_FILE ".gitmodules"
27 static git_cvar_map _sm_update_map
[] = {
28 {GIT_CVAR_STRING
, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT
},
29 {GIT_CVAR_STRING
, "rebase", GIT_SUBMODULE_UPDATE_REBASE
},
30 {GIT_CVAR_STRING
, "merge", GIT_SUBMODULE_UPDATE_MERGE
},
31 {GIT_CVAR_STRING
, "none", GIT_SUBMODULE_UPDATE_NONE
},
34 static git_cvar_map _sm_ignore_map
[] = {
35 {GIT_CVAR_STRING
, "none", GIT_SUBMODULE_IGNORE_NONE
},
36 {GIT_CVAR_STRING
, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED
},
37 {GIT_CVAR_STRING
, "dirty", GIT_SUBMODULE_IGNORE_DIRTY
},
38 {GIT_CVAR_STRING
, "all", GIT_SUBMODULE_IGNORE_ALL
},
41 static kh_inline khint_t
str_hash_no_trailing_slash(const char *s
)
46 if (s
[1] != '\0' || *s
!= '/')
47 h
= (h
<< 5) - h
+ *s
;
52 static kh_inline
int str_equal_no_trailing_slash(const char *a
, const char *b
)
54 size_t alen
= a
? strlen(a
) : 0;
55 size_t blen
= b
? strlen(b
) : 0;
57 if (alen
> 0 && a
[alen
- 1] == '/')
59 if (blen
> 0 && b
[blen
- 1] == '/')
62 return (alen
== blen
&& strncmp(a
, b
, alen
) == 0);
66 str
, static kh_inline
, const char *, void *, 1,
67 str_hash_no_trailing_slash
, str_equal_no_trailing_slash
);
69 static int load_submodule_config(git_repository
*repo
);
70 static git_config_backend
*open_gitmodules(git_repository
*, bool, const git_oid
*);
71 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
);
72 static int submodule_get(git_submodule
**, git_repository
*, const char *, const char *);
73 static void submodule_release(git_submodule
*sm
, int decr
);
74 static int submodule_load_from_index(git_repository
*, const git_index_entry
*);
75 static int submodule_load_from_head(git_repository
*, const char*, const git_oid
*);
76 static int submodule_load_from_config(const git_config_entry
*, void *);
77 static int submodule_load_from_wd_lite(git_submodule
*, const char *, void *);
78 static int submodule_update_config(git_submodule
*, const char *, const char *, bool, bool);
79 static void submodule_mode_mismatch(git_repository
*, const char *, unsigned int);
80 static int submodule_index_status(unsigned int *status
, git_submodule
*sm
);
81 static int submodule_wd_status(unsigned int *status
, git_submodule
*sm
);
83 static int submodule_cmp(const void *a
, const void *b
)
85 return strcmp(((git_submodule
*)a
)->name
, ((git_submodule
*)b
)->name
);
88 static int submodule_config_key_trunc_puts(git_buf
*key
, const char *suffix
)
90 ssize_t idx
= git_buf_rfind(key
, '.');
91 git_buf_truncate(key
, (size_t)(idx
+ 1));
92 return git_buf_puts(key
, suffix
);
99 int git_submodule_lookup(
100 git_submodule
**sm_ptr
, /* NULL if user only wants to test existence */
101 git_repository
*repo
,
102 const char *name
) /* trailing slash is allowed */
107 assert(repo
&& name
);
109 if ((error
= load_submodule_config(repo
)) < 0)
112 pos
= git_strmap_lookup_index(repo
->submodules
, name
);
114 if (!git_strmap_valid_index(repo
->submodules
, pos
)) {
115 error
= GIT_ENOTFOUND
;
117 /* check if a plausible submodule exists at path */
118 if (git_repository_workdir(repo
)) {
119 git_buf path
= GIT_BUF_INIT
;
121 if (git_buf_joinpath(&path
, git_repository_workdir(repo
), name
) < 0)
124 if (git_path_contains_dir(&path
, DOT_GIT
))
134 *sm_ptr
= git_strmap_value_at(repo
->submodules
, pos
);
139 int git_submodule_foreach(
140 git_repository
*repo
,
141 int (*callback
)(git_submodule
*sm
, const char *name
, void *payload
),
146 git_vector seen
= GIT_VECTOR_INIT
;
147 seen
._cmp
= submodule_cmp
;
149 assert(repo
&& callback
);
151 if ((error
= load_submodule_config(repo
)) < 0)
154 git_strmap_foreach_value(repo
->submodules
, sm
, {
155 /* Usually the following will not come into play - it just prevents
156 * us from issuing a callback twice for a submodule where the name
157 * and path are not the same.
159 if (sm
->refcount
> 1) {
160 if (git_vector_bsearch(&seen
, sm
) != GIT_ENOTFOUND
)
162 if ((error
= git_vector_insert(&seen
, sm
)) < 0)
166 if (callback(sm
, sm
->name
, payload
)) {
173 git_vector_free(&seen
);
178 void git_submodule_config_free(git_repository
*repo
)
185 smcfg
= repo
->submodules
;
186 repo
->submodules
= NULL
;
191 git_strmap_foreach_value(smcfg
, sm
, {
192 submodule_release(sm
,1);
194 git_strmap_free(smcfg
);
197 int git_submodule_add_setup(
198 git_submodule
**submodule
,
199 git_repository
*repo
,
205 git_config_backend
*mods
= NULL
;
207 git_buf name
= GIT_BUF_INIT
, real_url
= GIT_BUF_INIT
;
208 git_repository_init_options initopt
= GIT_REPOSITORY_INIT_OPTIONS_INIT
;
209 git_repository
*subrepo
= NULL
;
211 assert(repo
&& url
&& path
);
213 /* see if there is already an entry for this submodule */
215 if (git_submodule_lookup(&sm
, repo
, path
) < 0)
218 giterr_set(GITERR_SUBMODULE
,
219 "Attempt to add a submodule that already exists");
223 /* resolve parameters */
225 if (url
[0] == '.' && (url
[1] == '/' || (url
[1] == '.' && url
[2] == '/'))) {
226 if (!(error
= lookup_head_remote(&real_url
, repo
)))
227 error
= git_path_apply_relative(&real_url
, url
);
228 } else if (strchr(url
, ':') != NULL
|| url
[0] == '/') {
229 error
= git_buf_sets(&real_url
, url
);
231 giterr_set(GITERR_SUBMODULE
, "Invalid format for submodule URL");
237 /* validate and normalize path */
239 if (git__prefixcmp(path
, git_repository_workdir(repo
)) == 0)
240 path
+= strlen(git_repository_workdir(repo
));
242 if (git_path_root(path
) >= 0) {
243 giterr_set(GITERR_SUBMODULE
, "Submodule path must be a relative path");
248 /* update .gitmodules */
250 if ((mods
= open_gitmodules(repo
, true, NULL
)) == NULL
) {
251 giterr_set(GITERR_SUBMODULE
,
252 "Adding submodules to a bare repository is not supported (for now)");
256 if ((error
= git_buf_printf(&name
, "submodule.%s.path", path
)) < 0 ||
257 (error
= git_config_file_set_string(mods
, name
.ptr
, path
)) < 0)
260 if ((error
= submodule_config_key_trunc_puts(&name
, "url")) < 0 ||
261 (error
= git_config_file_set_string(mods
, name
.ptr
, real_url
.ptr
)) < 0)
264 git_buf_clear(&name
);
266 /* init submodule repository and add origin remote as needed */
268 error
= git_buf_joinpath(&name
, git_repository_workdir(repo
), path
);
272 /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
273 * gitlink in the sub-repo workdir directory to that repository
275 * Old style: sub-repo goes directly into repo/<name>/.git/
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
= NULL
;
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_entry__init_from_stat(&entry
, &st
);
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_backend
*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_id(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_id(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_id(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_id(
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 git_submodule_config_free(repo
);
712 return load_submodule_config(repo
);
715 int git_submodule_reload(git_submodule
*submodule
)
717 git_repository
*repo
;
721 git_config_backend
*mods
;
725 /* refresh index data */
727 repo
= submodule
->owner
;
728 if (git_repository_index__weakptr(&index
, repo
) < 0)
731 submodule
->flags
= submodule
->flags
&
732 ~(GIT_SUBMODULE_STATUS_IN_INDEX
|
733 GIT_SUBMODULE_STATUS__INDEX_OID_VALID
);
735 pos
= git_index_find(index
, submodule
->path
);
737 const git_index_entry
*entry
= git_index_get_byindex(index
, pos
);
739 if (S_ISGITLINK(entry
->mode
)) {
740 if ((error
= submodule_load_from_index(repo
, entry
)) < 0)
743 submodule_mode_mismatch(
744 repo
, entry
->path
, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
);
748 /* refresh HEAD tree data */
750 if (!(error
= git_repository_head_tree(&head
, repo
))) {
753 submodule
->flags
= submodule
->flags
&
754 ~(GIT_SUBMODULE_STATUS_IN_HEAD
|
755 GIT_SUBMODULE_STATUS__HEAD_OID_VALID
);
757 if (!(error
= git_tree_entry_bypath(&te
, head
, submodule
->path
))) {
759 if (S_ISGITLINK(te
->attr
)) {
760 error
= submodule_load_from_head(repo
, submodule
->path
, &te
->oid
);
762 submodule_mode_mismatch(
763 repo
, submodule
->path
,
764 GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
);
767 git_tree_entry_free(te
);
769 else if (error
== GIT_ENOTFOUND
) {
780 /* refresh config data */
782 if ((mods
= open_gitmodules(repo
, false, NULL
)) != NULL
) {
783 git_buf path
= GIT_BUF_INIT
;
785 git_buf_sets(&path
, "submodule\\.");
786 git_buf_text_puts_escape_regex(&path
, submodule
->name
);
787 git_buf_puts(&path
, ".*");
789 if (git_buf_oom(&path
))
792 error
= git_config_file_foreach_match(
793 mods
, path
.ptr
, submodule_load_from_config
, repo
);
796 git_config_file_free(mods
);
802 /* refresh wd data */
804 submodule
->flags
= submodule
->flags
&
805 ~(GIT_SUBMODULE_STATUS_IN_WD
| GIT_SUBMODULE_STATUS__WD_OID_VALID
);
807 error
= submodule_load_from_wd_lite(submodule
, submodule
->path
, NULL
);
812 int git_submodule_status(
813 unsigned int *status
,
814 git_submodule
*submodule
)
817 unsigned int status_val
;
819 assert(status
&& submodule
);
821 status_val
= GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(submodule
->flags
);
823 if (submodule
->ignore
!= GIT_SUBMODULE_IGNORE_ALL
) {
824 if (!(error
= submodule_index_status(&status_val
, submodule
)))
825 error
= submodule_wd_status(&status_val
, submodule
);
828 *status
= status_val
;
833 int git_submodule_location(
834 unsigned int *location_status
,
835 git_submodule
*submodule
)
837 assert(location_status
&& submodule
);
839 *location_status
= submodule
->flags
&
840 (GIT_SUBMODULE_STATUS_IN_HEAD
| GIT_SUBMODULE_STATUS_IN_INDEX
|
841 GIT_SUBMODULE_STATUS_IN_CONFIG
| GIT_SUBMODULE_STATUS_IN_WD
);
851 static git_submodule
*submodule_alloc(git_repository
*repo
, const char *name
)
855 if (!name
|| !strlen(name
)) {
856 giterr_set(GITERR_SUBMODULE
, "Invalid submodule name");
860 sm
= git__calloc(1, sizeof(git_submodule
));
864 sm
->path
= sm
->name
= git__strdup(name
);
874 submodule_release(sm
, 0);
878 static void submodule_release(git_submodule
*sm
, int decr
)
883 sm
->refcount
-= decr
;
885 if (sm
->refcount
== 0) {
886 if (sm
->name
!= sm
->path
) {
903 static int submodule_get(
904 git_submodule
**sm_ptr
,
905 git_repository
*repo
,
907 const char *alternate
)
909 git_strmap
*smcfg
= repo
->submodules
;
914 assert(repo
&& name
);
916 pos
= git_strmap_lookup_index(smcfg
, name
);
918 if (!git_strmap_valid_index(smcfg
, pos
) && alternate
)
919 pos
= git_strmap_lookup_index(smcfg
, alternate
);
921 if (!git_strmap_valid_index(smcfg
, pos
)) {
922 sm
= submodule_alloc(repo
, name
);
924 /* insert value at name - if another thread beats us to it, then use
925 * their record and release our own.
927 pos
= kh_put(str
, smcfg
, sm
->name
, &error
);
930 submodule_release(sm
, 1);
932 } else if (error
== 0) {
933 submodule_release(sm
, 1);
934 sm
= git_strmap_value_at(smcfg
, pos
);
936 git_strmap_set_value_at(smcfg
, pos
, sm
);
939 sm
= git_strmap_value_at(smcfg
, pos
);
944 return (sm
!= NULL
) ? 0 : -1;
947 static int submodule_load_from_index(
948 git_repository
*repo
, const git_index_entry
*entry
)
952 if (submodule_get(&sm
, repo
, entry
->path
, NULL
) < 0)
955 if (sm
->flags
& GIT_SUBMODULE_STATUS_IN_INDEX
) {
956 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES
;
960 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_INDEX
;
962 git_oid_cpy(&sm
->index_oid
, &entry
->oid
);
963 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_OID_VALID
;
968 static int submodule_load_from_head(
969 git_repository
*repo
, const char *path
, const git_oid
*oid
)
973 if (submodule_get(&sm
, repo
, path
, NULL
) < 0)
976 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_HEAD
;
978 git_oid_cpy(&sm
->head_oid
, oid
);
979 sm
->flags
|= GIT_SUBMODULE_STATUS__HEAD_OID_VALID
;
984 static int submodule_config_error(const char *property
, const char *value
)
986 giterr_set(GITERR_INVALID
,
987 "Invalid value for submodule '%s' property: '%s'", property
, value
);
991 static int submodule_load_from_config(
992 const git_config_entry
*entry
, void *data
)
994 git_repository
*repo
= data
;
995 git_strmap
*smcfg
= repo
->submodules
;
996 const char *namestart
, *property
, *alternate
= NULL
;
997 const char *key
= entry
->name
, *value
= entry
->value
;
998 git_buf name
= GIT_BUF_INIT
;
1003 if (git__prefixcmp(key
, "submodule.") != 0)
1006 namestart
= key
+ strlen("submodule.");
1007 property
= strrchr(namestart
, '.');
1008 if (property
== NULL
)
1011 is_path
= (strcasecmp(property
, "path") == 0);
1013 if (git_buf_set(&name
, namestart
, property
- namestart
- 1) < 0)
1016 if (submodule_get(&sm
, repo
, name
.ptr
, is_path
? value
: NULL
) < 0) {
1017 git_buf_free(&name
);
1021 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
1023 /* Only from config might we get differing names & paths. If so, then
1024 * update the submodule and insert under the alternative key.
1027 /* TODO: if case insensitive filesystem, then the following strcmps
1028 * should be strcasecmp
1031 if (strcmp(sm
->name
, name
.ptr
) != 0) {
1032 alternate
= sm
->name
= git_buf_detach(&name
);
1033 } else if (is_path
&& value
&& strcmp(sm
->path
, value
) != 0) {
1034 alternate
= sm
->path
= git__strdup(value
);
1039 void *old_sm
= NULL
;
1040 git_strmap_insert2(smcfg
, alternate
, sm
, old_sm
, error
);
1043 sm
->refcount
++; /* inserted under a new key */
1045 /* if we replaced an old module under this key, release the old one */
1046 if (old_sm
&& ((git_submodule
*)old_sm
) != sm
) {
1047 submodule_release(old_sm
, 1);
1048 /* TODO: log warning about multiple submodules with same path */
1052 git_buf_free(&name
);
1056 /* TODO: Look up path in index and if it is present but not a GITLINK
1057 * then this should be deleted (at least to match git's behavior)
1063 /* copy other properties into submodule entry */
1064 if (strcasecmp(property
, "url") == 0) {
1068 if (value
!= NULL
&& (sm
->url
= git__strdup(value
)) == NULL
)
1071 else if (strcasecmp(property
, "update") == 0) {
1073 if (git_config_lookup_map_value(
1074 &val
, _sm_update_map
, ARRAY_SIZE(_sm_update_map
), value
) < 0)
1075 return submodule_config_error("update", value
);
1076 sm
->update_default
= sm
->update
= (git_submodule_update_t
)val
;
1078 else if (strcasecmp(property
, "fetchRecurseSubmodules") == 0) {
1079 if (git__parse_bool(&sm
->fetch_recurse
, value
) < 0)
1080 return submodule_config_error("fetchRecurseSubmodules", value
);
1082 else if (strcasecmp(property
, "ignore") == 0) {
1084 if (git_config_lookup_map_value(
1085 &val
, _sm_ignore_map
, ARRAY_SIZE(_sm_ignore_map
), value
) < 0)
1086 return submodule_config_error("ignore", value
);
1087 sm
->ignore_default
= sm
->ignore
= (git_submodule_ignore_t
)val
;
1089 /* ignore other unknown submodule properties */
1094 static int submodule_load_from_wd_lite(
1095 git_submodule
*sm
, const char *name
, void *payload
)
1097 git_repository
*repo
= git_submodule_owner(sm
);
1098 git_buf path
= GIT_BUF_INIT
;
1101 GIT_UNUSED(payload
);
1103 if (git_buf_joinpath(&path
, git_repository_workdir(repo
), sm
->path
) < 0)
1106 if (git_path_isdir(path
.ptr
))
1107 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
1109 if (git_path_contains(&path
, DOT_GIT
))
1110 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
;
1112 git_buf_free(&path
);
1117 static void submodule_mode_mismatch(
1118 git_repository
*repo
, const char *path
, unsigned int flag
)
1120 khiter_t pos
= git_strmap_lookup_index(repo
->submodules
, path
);
1122 if (git_strmap_valid_index(repo
->submodules
, pos
)) {
1123 git_submodule
*sm
= git_strmap_value_at(repo
->submodules
, pos
);
1129 static int load_submodule_config_from_index(
1130 git_repository
*repo
, git_oid
*gitmodules_oid
)
1134 const git_index_entry
*entry
;
1136 if ((error
= git_iterator_for_repo_index(&i
, repo
)) < 0)
1139 error
= git_iterator_current(i
, &entry
);
1141 while (!error
&& entry
!= NULL
) {
1143 if (S_ISGITLINK(entry
->mode
)) {
1144 error
= submodule_load_from_index(repo
, entry
);
1148 submodule_mode_mismatch(
1149 repo
, entry
->path
, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
);
1151 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0)
1152 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1155 error
= git_iterator_advance(i
, &entry
);
1158 git_iterator_free(i
);
1163 static int load_submodule_config_from_head(
1164 git_repository
*repo
, git_oid
*gitmodules_oid
)
1169 const git_index_entry
*entry
;
1171 if ((error
= git_repository_head_tree(&head
, repo
)) < 0)
1174 if ((error
= git_iterator_for_tree(&i
, head
)) < 0) {
1175 git_tree_free(head
);
1179 error
= git_iterator_current(i
, &entry
);
1181 while (!error
&& entry
!= NULL
) {
1183 if (S_ISGITLINK(entry
->mode
)) {
1184 error
= submodule_load_from_head(repo
, entry
->path
, &entry
->oid
);
1188 submodule_mode_mismatch(
1189 repo
, entry
->path
, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
);
1191 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0 &&
1192 git_oid_iszero(gitmodules_oid
))
1193 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1196 error
= git_iterator_advance(i
, &entry
);
1199 git_iterator_free(i
);
1200 git_tree_free(head
);
1205 static git_config_backend
*open_gitmodules(
1206 git_repository
*repo
,
1207 bool okay_to_create
,
1208 const git_oid
*gitmodules_oid
)
1210 const char *workdir
= git_repository_workdir(repo
);
1211 git_buf path
= GIT_BUF_INIT
;
1212 git_config_backend
*mods
= NULL
;
1214 if (workdir
!= NULL
) {
1215 if (git_buf_joinpath(&path
, workdir
, GIT_MODULES_FILE
) != 0)
1218 if (okay_to_create
|| git_path_isfile(path
.ptr
)) {
1219 /* git_config_file__ondisk should only fail if OOM */
1220 if (git_config_file__ondisk(&mods
, path
.ptr
) < 0)
1222 /* open should only fail here if the file is malformed */
1223 else if (git_config_file_open(mods
, GIT_CONFIG_LEVEL_LOCAL
) < 0) {
1224 git_config_file_free(mods
);
1230 if (!mods
&& gitmodules_oid
&& !git_oid_iszero(gitmodules_oid
)) {
1231 /* TODO: Retrieve .gitmodules content from ODB */
1233 /* Should we actually do this? Core git does not, but it means you
1234 * can't really get much information about submodules on bare repos.
1238 git_buf_free(&path
);
1243 static int load_submodule_config(git_repository
*repo
)
1246 git_oid gitmodules_oid
;
1247 git_buf path
= GIT_BUF_INIT
;
1248 git_config_backend
*mods
= NULL
;
1250 if (repo
->submodules
)
1253 memset(&gitmodules_oid
, 0, sizeof(gitmodules_oid
));
1255 /* Submodule data is kept in a hashtable keyed by both name and path.
1256 * These are usually the same, but that is not guaranteed.
1258 if (!repo
->submodules
) {
1259 repo
->submodules
= git_strmap_alloc();
1260 GITERR_CHECK_ALLOC(repo
->submodules
);
1263 /* add submodule information from index */
1265 if ((error
= load_submodule_config_from_index(repo
, &gitmodules_oid
)) < 0)
1268 /* add submodule information from HEAD */
1270 if ((error
= load_submodule_config_from_head(repo
, &gitmodules_oid
)) < 0)
1273 /* add submodule information from .gitmodules */
1275 if ((mods
= open_gitmodules(repo
, false, &gitmodules_oid
)) != NULL
)
1276 error
= git_config_file_foreach(mods
, submodule_load_from_config
, repo
);
1281 /* shallow scan submodules in work tree */
1283 if (!git_repository_is_bare(repo
))
1284 error
= git_submodule_foreach(repo
, submodule_load_from_wd_lite
, NULL
);
1287 git_buf_free(&path
);
1290 git_config_file_free(mods
);
1293 git_submodule_config_free(repo
);
1298 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
)
1302 git_reference
*head
= NULL
, *remote
= NULL
;
1303 const char *tgt
, *scan
;
1304 git_buf key
= GIT_BUF_INIT
;
1306 /* 1. resolve HEAD -> refs/heads/BRANCH
1307 * 2. lookup config branch.BRANCH.remote -> ORIGIN
1308 * 3. lookup remote.ORIGIN.url
1311 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
1314 if (git_reference_lookup(&head
, repo
, GIT_HEAD_FILE
) < 0) {
1315 giterr_set(GITERR_SUBMODULE
,
1316 "Cannot resolve relative URL when HEAD cannot be resolved");
1317 error
= GIT_ENOTFOUND
;
1321 if (git_reference_type(head
) != GIT_REF_SYMBOLIC
) {
1322 giterr_set(GITERR_SUBMODULE
,
1323 "Cannot resolve relative URL when HEAD is not symbolic");
1324 error
= GIT_ENOTFOUND
;
1328 if ((error
= git_branch_tracking(&remote
, head
)) < 0)
1331 /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
1333 if (git_reference_type(remote
) != GIT_REF_SYMBOLIC
||
1334 git__prefixcmp(git_reference_symbolic_target(remote
), GIT_REFS_REMOTES_DIR
) != 0)
1336 giterr_set(GITERR_SUBMODULE
,
1337 "Cannot resolve relative URL when HEAD is not symbolic");
1338 error
= GIT_ENOTFOUND
;
1342 scan
= tgt
= git_reference_symbolic_target(remote
) + strlen(GIT_REFS_REMOTES_DIR
);
1343 while (*scan
&& (*scan
!= '/' || (scan
> tgt
&& scan
[-1] != '\\')))
1344 scan
++; /* find non-escaped slash to end ORIGIN name */
1346 error
= git_buf_printf(&key
, "remote.%.*s.url", (int)(scan
- tgt
), tgt
);
1350 if ((error
= git_config_get_string(&tgt
, cfg
, key
.ptr
)) < 0)
1353 error
= git_buf_sets(url
, tgt
);
1357 git_reference_free(head
);
1358 git_reference_free(remote
);
1363 static int submodule_update_config(
1364 git_submodule
*submodule
,
1372 git_buf key
= GIT_BUF_INIT
;
1373 const char *old
= NULL
;
1377 error
= git_repository_config__weakptr(&config
, submodule
->owner
);
1381 error
= git_buf_printf(&key
, "submodule.%s.%s", submodule
->name
, attr
);
1385 if (git_config_get_string(&old
, config
, key
.ptr
) < 0)
1388 if (!old
&& only_existing
)
1390 if (old
&& !overwrite
)
1392 if ((!old
&& !value
) || (old
&& value
&& strcmp(old
, value
) == 0))
1396 error
= git_config_delete_entry(config
, key
.ptr
);
1398 error
= git_config_set_string(config
, key
.ptr
, value
);
1405 static int submodule_index_status(unsigned int *status
, git_submodule
*sm
)
1407 const git_oid
*head_oid
= git_submodule_head_id(sm
);
1408 const git_oid
*index_oid
= git_submodule_index_id(sm
);
1412 *status
|= GIT_SUBMODULE_STATUS_INDEX_ADDED
;
1414 else if (!index_oid
)
1415 *status
|= GIT_SUBMODULE_STATUS_INDEX_DELETED
;
1416 else if (!git_oid_equal(head_oid
, index_oid
))
1417 *status
|= GIT_SUBMODULE_STATUS_INDEX_MODIFIED
;
1422 static int submodule_wd_status(unsigned int *status
, git_submodule
*sm
)
1425 const git_oid
*wd_oid
, *index_oid
;
1426 git_repository
*sm_repo
= NULL
;
1428 /* open repo now if we need it (so wd_id() call won't reopen) */
1429 if ((sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
||
1430 sm
->ignore
== GIT_SUBMODULE_IGNORE_UNTRACKED
) &&
1431 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) != 0)
1433 if ((error
= git_submodule_open(&sm_repo
, sm
)) < 0)
1437 index_oid
= git_submodule_index_id(sm
);
1438 wd_oid
= git_submodule_wd_id(sm
);
1442 *status
|= GIT_SUBMODULE_STATUS_WD_ADDED
;
1445 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_SCANNED
) != 0 &&
1446 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0)
1447 *status
|= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
;
1449 *status
|= GIT_SUBMODULE_STATUS_WD_DELETED
;
1451 else if (!git_oid_equal(index_oid
, wd_oid
))
1452 *status
|= GIT_SUBMODULE_STATUS_WD_MODIFIED
;
1454 if (sm_repo
!= NULL
) {
1456 git_diff_options opt
= GIT_DIFF_OPTIONS_INIT
;
1457 git_diff_list
*diff
;
1459 /* the diffs below could be optimized with an early termination
1460 * option to the git_diff functions, but for now this is sufficient
1461 * (and certainly no worse that what core git does).
1464 /* perform head-to-index diff on submodule */
1466 if ((error
= git_repository_head_tree(&sm_head
, sm_repo
)) < 0)
1469 if (sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
)
1470 opt
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
;
1472 error
= git_diff_tree_to_index(&diff
, sm_repo
, sm_head
, NULL
, &opt
);
1475 if (git_diff_num_deltas(diff
) > 0)
1476 *status
|= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
;
1478 git_diff_list_free(diff
);
1482 git_tree_free(sm_head
);
1487 /* perform index-to-workdir diff on submodule */
1489 error
= git_diff_index_to_workdir(&diff
, sm_repo
, NULL
, &opt
);
1493 git_diff_num_deltas_of_type(diff
, GIT_DELTA_UNTRACKED
);
1496 *status
|= GIT_SUBMODULE_STATUS_WD_UNTRACKED
;
1498 if ((git_diff_num_deltas(diff
) - untracked
) > 0)
1499 *status
|= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
;
1501 git_diff_list_free(diff
);
1505 git_repository_free(sm_repo
);