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 char *, const char *, 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(index
, GIT_MODULES_FILE
, 0)) < 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_add2(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(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 char *key
, const char *value
, void *data
)
979 git_repository
*repo
= data
;
980 git_strmap
*smcfg
= repo
->submodules
;
981 const char *namestart
, *property
, *alternate
= NULL
;
982 git_buf name
= GIT_BUF_INIT
;
987 if (git__prefixcmp(key
, "submodule.") != 0)
990 namestart
= key
+ strlen("submodule.");
991 property
= strrchr(namestart
, '.');
992 if (property
== NULL
)
995 is_path
= (strcasecmp(property
, "path") == 0);
997 if (git_buf_set(&name
, namestart
, property
- namestart
- 1) < 0)
1000 if (submodule_get(&sm
, repo
, name
.ptr
, is_path
? value
: NULL
) < 0) {
1001 git_buf_free(&name
);
1005 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
1007 /* Only from config might we get differing names & paths. If so, then
1008 * update the submodule and insert under the alternative key.
1011 /* TODO: if case insensitive filesystem, then the following strcmps
1012 * should be strcasecmp
1015 if (strcmp(sm
->name
, name
.ptr
) != 0) {
1016 alternate
= sm
->name
= git_buf_detach(&name
);
1017 } else if (is_path
&& value
&& strcmp(sm
->path
, value
) != 0) {
1018 alternate
= sm
->path
= git__strdup(value
);
1023 void *old_sm
= NULL
;
1024 git_strmap_insert2(smcfg
, alternate
, sm
, old_sm
, error
);
1027 sm
->refcount
++; /* inserted under a new key */
1029 /* if we replaced an old module under this key, release the old one */
1030 if (old_sm
&& ((git_submodule
*)old_sm
) != sm
) {
1031 submodule_release(old_sm
, 1);
1032 /* TODO: log warning about multiple submodules with same path */
1036 git_buf_free(&name
);
1040 /* TODO: Look up path in index and if it is present but not a GITLINK
1041 * then this should be deleted (at least to match git's behavior)
1047 /* copy other properties into submodule entry */
1048 if (strcasecmp(property
, "url") == 0) {
1052 if (value
!= NULL
&& (sm
->url
= git__strdup(value
)) == NULL
)
1055 else if (strcasecmp(property
, "update") == 0) {
1057 if (git_config_lookup_map_value(
1058 _sm_update_map
, ARRAY_SIZE(_sm_update_map
), value
, &val
) < 0)
1059 return submodule_config_error("update", value
);
1060 sm
->update_default
= sm
->update
= (git_submodule_update_t
)val
;
1062 else if (strcasecmp(property
, "fetchRecurseSubmodules") == 0) {
1063 if (git__parse_bool(&sm
->fetch_recurse
, value
) < 0)
1064 return submodule_config_error("fetchRecurseSubmodules", value
);
1066 else if (strcasecmp(property
, "ignore") == 0) {
1068 if (git_config_lookup_map_value(
1069 _sm_ignore_map
, ARRAY_SIZE(_sm_ignore_map
), value
, &val
) < 0)
1070 return submodule_config_error("ignore", value
);
1071 sm
->ignore_default
= sm
->ignore
= (git_submodule_ignore_t
)val
;
1073 /* ignore other unknown submodule properties */
1078 static int submodule_load_from_wd_lite(
1079 git_submodule
*sm
, const char *name
, void *payload
)
1081 git_repository
*repo
= git_submodule_owner(sm
);
1082 git_buf path
= GIT_BUF_INIT
;
1085 GIT_UNUSED(payload
);
1087 if (git_buf_joinpath(&path
, git_repository_workdir(repo
), sm
->path
) < 0)
1090 if (git_path_isdir(path
.ptr
))
1091 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
1093 if (git_path_contains(&path
, DOT_GIT
))
1094 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
;
1096 git_buf_free(&path
);
1101 static void submodule_mode_mismatch(
1102 git_repository
*repo
, const char *path
, unsigned int flag
)
1104 khiter_t pos
= git_strmap_lookup_index(repo
->submodules
, path
);
1106 if (git_strmap_valid_index(repo
->submodules
, pos
)) {
1107 git_submodule
*sm
= git_strmap_value_at(repo
->submodules
, pos
);
1113 static int load_submodule_config_from_index(
1114 git_repository
*repo
, git_oid
*gitmodules_oid
)
1118 const git_index_entry
*entry
;
1120 if ((error
= git_iterator_for_index(&i
, repo
)) < 0)
1123 error
= git_iterator_current(i
, &entry
);
1125 while (!error
&& entry
!= NULL
) {
1127 if (S_ISGITLINK(entry
->mode
)) {
1128 error
= submodule_load_from_index(repo
, entry
);
1132 submodule_mode_mismatch(
1133 repo
, entry
->path
, GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
);
1135 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0)
1136 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1139 error
= git_iterator_advance(i
, &entry
);
1142 git_iterator_free(i
);
1147 static int load_submodule_config_from_head(
1148 git_repository
*repo
, git_oid
*gitmodules_oid
)
1153 const git_index_entry
*entry
;
1155 if ((error
= git_repository_head_tree(&head
, repo
)) < 0)
1158 if ((error
= git_iterator_for_tree(&i
, repo
, head
)) < 0) {
1159 git_tree_free(head
);
1163 error
= git_iterator_current(i
, &entry
);
1165 while (!error
&& entry
!= NULL
) {
1167 if (S_ISGITLINK(entry
->mode
)) {
1168 error
= submodule_load_from_head(repo
, entry
->path
, &entry
->oid
);
1172 submodule_mode_mismatch(
1173 repo
, entry
->path
, GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
);
1175 if (strcmp(entry
->path
, GIT_MODULES_FILE
) == 0 &&
1176 git_oid_iszero(gitmodules_oid
))
1177 git_oid_cpy(gitmodules_oid
, &entry
->oid
);
1180 error
= git_iterator_advance(i
, &entry
);
1183 git_iterator_free(i
);
1184 git_tree_free(head
);
1189 static git_config_file
*open_gitmodules(
1190 git_repository
*repo
,
1191 bool okay_to_create
,
1192 const git_oid
*gitmodules_oid
)
1194 const char *workdir
= git_repository_workdir(repo
);
1195 git_buf path
= GIT_BUF_INIT
;
1196 git_config_file
*mods
= NULL
;
1198 if (workdir
!= NULL
) {
1199 if (git_buf_joinpath(&path
, workdir
, GIT_MODULES_FILE
) != 0)
1202 if (okay_to_create
|| git_path_isfile(path
.ptr
)) {
1203 /* git_config_file__ondisk should only fail if OOM */
1204 if (git_config_file__ondisk(&mods
, path
.ptr
) < 0)
1206 /* open should only fail here if the file is malformed */
1207 else if (git_config_file_open(mods
) < 0) {
1208 git_config_file_free(mods
);
1214 if (!mods
&& gitmodules_oid
&& !git_oid_iszero(gitmodules_oid
)) {
1215 /* TODO: Retrieve .gitmodules content from ODB */
1217 /* Should we actually do this? Core git does not, but it means you
1218 * can't really get much information about submodules on bare repos.
1222 git_buf_free(&path
);
1227 static int load_submodule_config(git_repository
*repo
, bool force
)
1230 git_oid gitmodules_oid
;
1231 git_buf path
= GIT_BUF_INIT
;
1232 git_config_file
*mods
= NULL
;
1234 if (repo
->submodules
&& !force
)
1237 memset(&gitmodules_oid
, 0, sizeof(gitmodules_oid
));
1239 /* Submodule data is kept in a hashtable keyed by both name and path.
1240 * These are usually the same, but that is not guaranteed.
1242 if (!repo
->submodules
) {
1243 repo
->submodules
= git_strmap_alloc();
1244 GITERR_CHECK_ALLOC(repo
->submodules
);
1247 /* add submodule information from index */
1249 if ((error
= load_submodule_config_from_index(repo
, &gitmodules_oid
)) < 0)
1252 /* add submodule information from HEAD */
1254 if ((error
= load_submodule_config_from_head(repo
, &gitmodules_oid
)) < 0)
1257 /* add submodule information from .gitmodules */
1259 if ((mods
= open_gitmodules(repo
, false, &gitmodules_oid
)) != NULL
)
1260 error
= git_config_file_foreach(mods
, submodule_load_from_config
, repo
);
1265 /* shallow scan submodules in work tree */
1267 if (!git_repository_is_bare(repo
))
1268 error
= git_submodule_foreach(repo
, submodule_load_from_wd_lite
, NULL
);
1271 git_buf_free(&path
);
1274 git_config_file_free(mods
);
1277 git_submodule_config_free(repo
);
1282 static int lookup_head_remote(git_buf
*url
, git_repository
*repo
)
1286 git_reference
*head
= NULL
, *remote
= NULL
;
1287 const char *tgt
, *scan
;
1288 git_buf key
= GIT_BUF_INIT
;
1290 /* 1. resolve HEAD -> refs/heads/BRANCH
1291 * 2. lookup config branch.BRANCH.remote -> ORIGIN
1292 * 3. lookup remote.ORIGIN.url
1295 if ((error
= git_repository_config__weakptr(&cfg
, repo
)) < 0)
1298 if (git_reference_lookup(&head
, repo
, GIT_HEAD_FILE
) < 0) {
1299 giterr_set(GITERR_SUBMODULE
,
1300 "Cannot resolve relative URL when HEAD cannot be resolved");
1301 error
= GIT_ENOTFOUND
;
1305 if (git_reference_type(head
) != GIT_REF_SYMBOLIC
) {
1306 giterr_set(GITERR_SUBMODULE
,
1307 "Cannot resolve relative URL when HEAD is not symbolic");
1308 error
= GIT_ENOTFOUND
;
1312 if ((error
= git_branch_tracking(&remote
, head
)) < 0)
1315 /* remote should refer to something like refs/remotes/ORIGIN/BRANCH */
1317 if (git_reference_type(remote
) != GIT_REF_SYMBOLIC
||
1318 git__prefixcmp(git_reference_target(remote
), "refs/remotes/") != 0)
1320 giterr_set(GITERR_SUBMODULE
,
1321 "Cannot resolve relative URL when HEAD is not symbolic");
1322 error
= GIT_ENOTFOUND
;
1326 scan
= tgt
= git_reference_target(remote
) + strlen("refs/remotes/");
1327 while (*scan
&& (*scan
!= '/' || (scan
> tgt
&& scan
[-1] != '\\')))
1328 scan
++; /* find non-escaped slash to end ORIGIN name */
1330 error
= git_buf_printf(&key
, "remote.%.*s.url", (int)(scan
- tgt
), tgt
);
1334 if ((error
= git_config_get_string(&tgt
, cfg
, key
.ptr
)) < 0)
1337 error
= git_buf_sets(url
, tgt
);
1341 git_reference_free(head
);
1342 git_reference_free(remote
);
1347 static int submodule_update_config(
1348 git_submodule
*submodule
,
1356 git_buf key
= GIT_BUF_INIT
;
1357 const char *old
= NULL
;
1361 error
= git_repository_config__weakptr(&config
, submodule
->owner
);
1365 error
= git_buf_printf(&key
, "submodule.%s.%s", submodule
->name
, attr
);
1369 if (git_config_get_string(&old
, config
, key
.ptr
) < 0)
1372 if (!old
&& only_existing
)
1374 if (old
&& !overwrite
)
1376 if ((!old
&& !value
) || (old
&& value
&& strcmp(old
, value
) == 0))
1380 error
= git_config_delete(config
, key
.ptr
);
1382 error
= git_config_set_string(config
, key
.ptr
, value
);
1389 static int submodule_index_status(unsigned int *status
, git_submodule
*sm
)
1391 const git_oid
*head_oid
= git_submodule_head_oid(sm
);
1392 const git_oid
*index_oid
= git_submodule_index_oid(sm
);
1396 *status
|= GIT_SUBMODULE_STATUS_INDEX_ADDED
;
1398 else if (!index_oid
)
1399 *status
|= GIT_SUBMODULE_STATUS_INDEX_DELETED
;
1400 else if (!git_oid_equal(head_oid
, index_oid
))
1401 *status
|= GIT_SUBMODULE_STATUS_INDEX_MODIFIED
;
1406 static int submodule_wd_status(unsigned int *status
, git_submodule
*sm
)
1409 const git_oid
*wd_oid
, *index_oid
;
1410 git_repository
*sm_repo
= NULL
;
1412 /* open repo now if we need it (so wd_oid() call won't reopen) */
1413 if ((sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
||
1414 sm
->ignore
== GIT_SUBMODULE_IGNORE_UNTRACKED
) &&
1415 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) != 0)
1417 if ((error
= git_submodule_open(&sm_repo
, sm
)) < 0)
1421 index_oid
= git_submodule_index_oid(sm
);
1422 wd_oid
= git_submodule_wd_oid(sm
);
1426 *status
|= GIT_SUBMODULE_STATUS_WD_ADDED
;
1429 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_SCANNED
) != 0 &&
1430 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0)
1431 *status
|= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
;
1433 *status
|= GIT_SUBMODULE_STATUS_WD_DELETED
;
1435 else if (!git_oid_equal(index_oid
, wd_oid
))
1436 *status
|= GIT_SUBMODULE_STATUS_WD_MODIFIED
;
1438 if (sm_repo
!= NULL
) {
1440 git_diff_options opt
;
1441 git_diff_list
*diff
;
1443 /* the diffs below could be optimized with an early termination
1444 * option to the git_diff functions, but for now this is sufficient
1445 * (and certainly no worse that what core git does).
1448 /* perform head-to-index diff on submodule */
1450 if ((error
= git_repository_head_tree(&sm_head
, sm_repo
)) < 0)
1453 memset(&opt
, 0, sizeof(opt
));
1454 if (sm
->ignore
== GIT_SUBMODULE_IGNORE_NONE
)
1455 opt
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
;
1457 error
= git_diff_index_to_tree(sm_repo
, &opt
, sm_head
, &diff
);
1460 if (git_diff_entrycount(diff
, -1) > 0)
1461 *status
|= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
;
1463 git_diff_list_free(diff
);
1467 git_tree_free(sm_head
);
1472 /* perform index-to-workdir diff on submodule */
1474 error
= git_diff_workdir_to_index(sm_repo
, &opt
, &diff
);
1477 int untracked
= git_diff_entrycount(diff
, GIT_DELTA_UNTRACKED
);
1480 *status
|= GIT_SUBMODULE_STATUS_WD_UNTRACKED
;
1482 if (git_diff_entrycount(diff
, -1) - untracked
> 0)
1483 *status
|= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
;
1485 git_diff_list_free(diff
);
1489 git_repository_free(sm_repo
);