2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
10 #include "git2/config.h"
11 #include "git2/sys/config.h"
12 #include "git2/types.h"
13 #include "git2/index.h"
18 #include "config_backend.h"
20 #include "repository.h"
28 #define GIT_MODULES_FILE ".gitmodules"
30 static git_configmap _sm_update_map
[] = {
31 {GIT_CONFIGMAP_STRING
, "checkout", GIT_SUBMODULE_UPDATE_CHECKOUT
},
32 {GIT_CONFIGMAP_STRING
, "rebase", GIT_SUBMODULE_UPDATE_REBASE
},
33 {GIT_CONFIGMAP_STRING
, "merge", GIT_SUBMODULE_UPDATE_MERGE
},
34 {GIT_CONFIGMAP_STRING
, "none", GIT_SUBMODULE_UPDATE_NONE
},
35 {GIT_CONFIGMAP_FALSE
, NULL
, GIT_SUBMODULE_UPDATE_NONE
},
36 {GIT_CONFIGMAP_TRUE
, NULL
, GIT_SUBMODULE_UPDATE_CHECKOUT
},
39 static git_configmap _sm_ignore_map
[] = {
40 {GIT_CONFIGMAP_STRING
, "none", GIT_SUBMODULE_IGNORE_NONE
},
41 {GIT_CONFIGMAP_STRING
, "untracked", GIT_SUBMODULE_IGNORE_UNTRACKED
},
42 {GIT_CONFIGMAP_STRING
, "dirty", GIT_SUBMODULE_IGNORE_DIRTY
},
43 {GIT_CONFIGMAP_STRING
, "all", GIT_SUBMODULE_IGNORE_ALL
},
44 {GIT_CONFIGMAP_FALSE
, NULL
, GIT_SUBMODULE_IGNORE_NONE
},
45 {GIT_CONFIGMAP_TRUE
, NULL
, GIT_SUBMODULE_IGNORE_ALL
},
48 static git_configmap _sm_recurse_map
[] = {
49 {GIT_CONFIGMAP_STRING
, "on-demand", GIT_SUBMODULE_RECURSE_ONDEMAND
},
50 {GIT_CONFIGMAP_FALSE
, NULL
, GIT_SUBMODULE_RECURSE_NO
},
51 {GIT_CONFIGMAP_TRUE
, NULL
, GIT_SUBMODULE_RECURSE_YES
},
60 GITMODULES_EXISTING
= 0,
61 GITMODULES_CREATE
= 1,
64 static int submodule_alloc(git_submodule
**out
, git_repository
*repo
, const char *name
);
65 static git_config_backend
*open_gitmodules(git_repository
*repo
, int gitmod
);
66 static int gitmodules_snapshot(git_config
**snap
, git_repository
*repo
);
67 static int get_url_base(git_buf
*url
, git_repository
*repo
);
68 static int lookup_head_remote_key(git_buf
*remote_key
, git_repository
*repo
);
69 static int lookup_default_remote(git_remote
**remote
, git_repository
*repo
);
70 static int submodule_load_each(const git_config_entry
*entry
, void *payload
);
71 static int submodule_read_config(git_submodule
*sm
, git_config
*cfg
);
72 static int submodule_load_from_wd_lite(git_submodule
*);
73 static void submodule_get_index_status(unsigned int *, git_submodule
*);
74 static void submodule_get_wd_status(unsigned int *, git_submodule
*, git_repository
*, git_submodule_ignore_t
);
75 static void submodule_update_from_index_entry(git_submodule
*sm
, const git_index_entry
*ie
);
76 static void submodule_update_from_head_data(git_submodule
*sm
, mode_t mode
, const git_oid
*id
);
78 static int submodule_cmp(const void *a
, const void *b
)
80 return strcmp(((git_submodule
*)a
)->name
, ((git_submodule
*)b
)->name
);
83 static int submodule_config_key_trunc_puts(git_buf
*key
, const char *suffix
)
85 ssize_t idx
= git_buf_rfind(key
, '.');
86 git_buf_truncate(key
, (size_t)(idx
+ 1));
87 return git_buf_puts(key
, suffix
);
94 static void submodule_set_lookup_error(int error
, const char *name
)
99 git_error_set(GIT_ERROR_SUBMODULE
, (error
== GIT_ENOTFOUND
) ?
100 "no submodule named '%s'" :
101 "submodule '%s' has not been added yet", name
);
109 static int find_by_path(const git_config_entry
*entry
, void *payload
)
111 fbp_data
*data
= payload
;
113 if (!strcmp(entry
->value
, data
->path
)) {
114 const char *fdot
, *ldot
;
115 fdot
= strchr(entry
->name
, '.');
116 ldot
= strrchr(entry
->name
, '.');
117 data
->name
= git__strndup(fdot
+ 1, ldot
- fdot
- 1);
118 GIT_ERROR_CHECK_ALLOC(data
->name
);
125 * Checks to see if the submodule shares its name with a file or directory that
126 * already exists on the index. If so, the submodule cannot be added.
128 static int is_path_occupied(bool *occupied
, git_repository
*repo
, const char *path
)
132 git_buf dir
= GIT_BUF_INIT
;
135 if ((error
= git_repository_index__weakptr(&index
, repo
)) < 0)
138 if ((error
= git_index_find(NULL
, index
, path
)) != GIT_ENOTFOUND
) {
140 git_error_set(GIT_ERROR_SUBMODULE
,
141 "File '%s' already exists in the index", path
);
147 if ((error
= git_buf_sets(&dir
, path
)) < 0)
150 if ((error
= git_path_to_dir(&dir
)) < 0)
153 if ((error
= git_index_find_prefix(NULL
, index
, dir
.ptr
)) != GIT_ENOTFOUND
) {
155 git_error_set(GIT_ERROR_SUBMODULE
,
156 "Directory '%s' already exists in the index", path
);
165 git_buf_dispose(&dir
);
170 * Release the name map returned by 'load_submodule_names'.
172 static void free_submodule_names(git_strmap
*names
)
180 git_strmap_foreach(names
, key
, value
, {
181 git__free((char *) key
);
184 git_strmap_free(names
);
190 * Map submodule paths to names.
191 * TODO: for some use-cases, this might need case-folding on a
192 * case-insensitive filesystem
194 static int load_submodule_names(git_strmap
**out
, git_repository
*repo
, git_config
*cfg
)
196 const char *key
= "submodule\\..*\\.path";
197 git_config_iterator
*iter
= NULL
;
198 git_config_entry
*entry
;
199 git_buf buf
= GIT_BUF_INIT
;
205 if ((error
= git_strmap_new(&names
)) < 0)
208 if ((error
= git_config_iterator_glob_new(&iter
, cfg
, key
)) < 0)
211 while ((error
= git_config_next(&entry
, iter
)) == 0) {
212 const char *fdot
, *ldot
;
213 fdot
= strchr(entry
->name
, '.');
214 ldot
= strrchr(entry
->name
, '.');
216 if (git_strmap_exists(names
, entry
->value
)) {
217 git_error_set(GIT_ERROR_SUBMODULE
,
218 "duplicated submodule path '%s'", entry
->value
);
224 git_buf_put(&buf
, fdot
+ 1, ldot
- fdot
- 1);
225 isvalid
= git_submodule_name_is_valid(repo
, buf
.ptr
, 0);
233 if ((error
= git_strmap_set(names
, git__strdup(entry
->value
), git_buf_detach(&buf
))) < 0) {
234 git_error_set(GIT_ERROR_NOMEMORY
, "error inserting submodule into hash table");
239 if (error
== GIT_ITEROVER
)
246 free_submodule_names(names
);
247 git_buf_dispose(&buf
);
248 git_config_iterator_free(iter
);
252 int git_submodule_lookup(
253 git_submodule
**out
, /* NULL if user only wants to test existence */
254 git_repository
*repo
,
255 const char *name
) /* trailing slash is allowed */
258 unsigned int location
;
261 assert(repo
&& name
);
264 git_error_set(GIT_ERROR_SUBMODULE
, "cannot get submodules without a working tree");
268 if (repo
->submodule_cache
!= NULL
) {
269 if ((sm
= git_strmap_get(repo
->submodule_cache
, name
)) != NULL
) {
272 GIT_REFCOUNT_INC(*out
);
278 if ((error
= submodule_alloc(&sm
, repo
, name
)) < 0)
281 if ((error
= git_submodule_reload(sm
, false)) < 0) {
282 git_submodule_free(sm
);
286 if ((error
= git_submodule_location(&location
, sm
)) < 0) {
287 git_submodule_free(sm
);
291 /* If it's not configured or we're looking by path */
292 if (location
== 0 || location
== GIT_SUBMODULE_STATUS_IN_WD
) {
293 git_config_backend
*mods
;
294 const char *pattern
= "submodule\\..*\\.path";
295 git_buf path
= GIT_BUF_INIT
;
296 fbp_data data
= { NULL
, NULL
};
298 git_buf_puts(&path
, name
);
299 while (path
.ptr
[path
.size
-1] == '/') {
300 path
.ptr
[--path
.size
] = '\0';
302 data
.path
= path
.ptr
;
304 mods
= open_gitmodules(repo
, GITMODULES_EXISTING
);
307 error
= git_config_backend_foreach_match(mods
, pattern
, find_by_path
, &data
);
309 git_config_backend_free(mods
);
312 git_submodule_free(sm
);
313 git_buf_dispose(&path
);
319 sm
->name
= data
.name
;
320 sm
->path
= git_buf_detach(&path
);
322 /* Try to load again with the right name */
323 if ((error
= git_submodule_reload(sm
, false)) < 0) {
324 git_submodule_free(sm
);
329 git_buf_dispose(&path
);
332 if ((error
= git_submodule_location(&location
, sm
)) < 0) {
333 git_submodule_free(sm
);
337 /* If we still haven't found it, do the WD check */
338 if (location
== 0 || location
== GIT_SUBMODULE_STATUS_IN_WD
) {
339 git_submodule_free(sm
);
340 error
= GIT_ENOTFOUND
;
342 /* If it's not configured, we still check if there's a repo at the path */
343 if (git_repository_workdir(repo
)) {
344 git_buf path
= GIT_BUF_INIT
;
345 if (git_buf_join3(&path
,
346 '/', git_repository_workdir(repo
), name
, DOT_GIT
) < 0)
349 if (git_path_exists(path
.ptr
))
352 git_buf_dispose(&path
);
355 submodule_set_lookup_error(error
, name
);
362 git_submodule_free(sm
);
367 int git_submodule_name_is_valid(git_repository
*repo
, const char *name
, int flags
)
369 git_buf buf
= GIT_BUF_INIT
;
373 flags
= GIT_PATH_REJECT_FILESYSTEM_DEFAULTS
;
375 /* Avoid allocating a new string if we can avoid it */
376 if (strchr(name
, '\\') != NULL
) {
377 if ((error
= git_path_normalize_slashes(&buf
, name
)) < 0)
380 git_buf_attach_notowned(&buf
, name
, strlen(name
));
383 isvalid
= git_path_isvalid(repo
, buf
.ptr
, 0, flags
);
384 git_buf_dispose(&buf
);
389 static void submodule_free_dup(void *sm
)
391 git_submodule_free(sm
);
394 static int submodule_get_or_create(git_submodule
**out
, git_repository
*repo
, git_strmap
*map
, const char *name
)
396 git_submodule
*sm
= NULL
;
399 if ((sm
= git_strmap_get(map
, name
)) != NULL
)
402 /* if the submodule doesn't exist yet in the map, create it */
403 if ((error
= submodule_alloc(&sm
, repo
, name
)) < 0)
406 if ((error
= git_strmap_set(map
, sm
->name
, sm
)) < 0) {
407 git_submodule_free(sm
);
412 GIT_REFCOUNT_INC(sm
);
417 static int submodules_from_index(git_strmap
*map
, git_index
*idx
, git_config
*cfg
)
420 git_iterator
*i
= NULL
;
421 const git_index_entry
*entry
;
424 if ((error
= load_submodule_names(&names
, git_index_owner(idx
), cfg
)))
427 if ((error
= git_iterator_for_index(&i
, git_index_owner(idx
), idx
, NULL
)) < 0)
430 while (!(error
= git_iterator_advance(&entry
, i
))) {
433 if ((sm
= git_strmap_get(map
, entry
->path
)) != NULL
) {
434 if (S_ISGITLINK(entry
->mode
))
435 submodule_update_from_index_entry(sm
, entry
);
437 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
;
438 } else if (S_ISGITLINK(entry
->mode
)) {
441 if ((name
= git_strmap_get(names
, entry
->path
)) == NULL
)
444 if (!submodule_get_or_create(&sm
, git_index_owner(idx
), map
, name
)) {
445 submodule_update_from_index_entry(sm
, entry
);
446 git_submodule_free(sm
);
451 if (error
== GIT_ITEROVER
)
455 git_iterator_free(i
);
456 free_submodule_names(names
);
461 static int submodules_from_head(git_strmap
*map
, git_tree
*head
, git_config
*cfg
)
464 git_iterator
*i
= NULL
;
465 const git_index_entry
*entry
;
468 if ((error
= load_submodule_names(&names
, git_tree_owner(head
), cfg
)))
471 if ((error
= git_iterator_for_tree(&i
, head
, NULL
)) < 0)
474 while (!(error
= git_iterator_advance(&entry
, i
))) {
477 if ((sm
= git_strmap_get(map
, entry
->path
)) != NULL
) {
478 if (S_ISGITLINK(entry
->mode
))
479 submodule_update_from_head_data(sm
, entry
->mode
, &entry
->id
);
481 sm
->flags
|= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
;
482 } else if (S_ISGITLINK(entry
->mode
)) {
485 if ((name
= git_strmap_get(names
, entry
->path
)) == NULL
)
488 if (!submodule_get_or_create(&sm
, git_tree_owner(head
), map
, name
)) {
489 submodule_update_from_head_data(
490 sm
, entry
->mode
, &entry
->id
);
491 git_submodule_free(sm
);
496 if (error
== GIT_ITEROVER
)
500 git_iterator_free(i
);
501 free_submodule_names(names
);
506 /* If have_sm is true, sm is populated, otherwise map an repo are. */
510 git_repository
*repo
;
513 int git_submodule__map(git_repository
*repo
, git_strmap
*map
)
516 git_index
*idx
= NULL
;
517 git_tree
*head
= NULL
;
518 const char *wd
= NULL
;
519 git_buf path
= GIT_BUF_INIT
;
521 git_config
*mods
= NULL
;
525 /* get sources that we will need to check */
526 if (git_repository_index(&idx
, repo
) < 0)
528 if (git_repository_head_tree(&head
, repo
) < 0)
531 wd
= git_repository_workdir(repo
);
532 if (wd
&& (error
= git_buf_joinpath(&path
, wd
, GIT_MODULES_FILE
)) < 0)
535 /* add submodule information from .gitmodules */
537 lfc_data data
= { 0 };
541 if ((error
= gitmodules_snapshot(&mods
, repo
)) < 0) {
542 if (error
== GIT_ENOTFOUND
)
548 if ((error
= git_config_foreach(
549 mods
, submodule_load_each
, &data
)) < 0)
552 /* add back submodule information from index */
554 if ((error
= submodules_from_index(map
, idx
, mods
)) < 0)
557 /* add submodule information from HEAD */
559 if ((error
= submodules_from_head(map
, head
, mods
)) < 0)
562 /* shallow scan submodules in work tree as needed */
564 git_strmap_foreach_value(map
, sm
, {
565 submodule_load_from_wd_lite(sm
);
570 git_config_free(mods
);
571 /* TODO: if we got an error, mark submodule config as invalid? */
574 git_buf_dispose(&path
);
578 int git_submodule_foreach(
579 git_repository
*repo
,
580 git_submodule_cb callback
,
583 git_vector snapshot
= GIT_VECTOR_INIT
;
584 git_strmap
*submodules
;
590 git_error_set(GIT_ERROR_SUBMODULE
, "cannot get submodules without a working tree");
594 if ((error
= git_strmap_new(&submodules
)) < 0)
597 if ((error
= git_submodule__map(repo
, submodules
)) < 0)
600 if (!(error
= git_vector_init(
601 &snapshot
, git_strmap_size(submodules
), submodule_cmp
))) {
603 git_strmap_foreach_value(submodules
, sm
, {
604 if ((error
= git_vector_insert(&snapshot
, sm
)) < 0)
606 GIT_REFCOUNT_INC(sm
);
613 git_vector_uniq(&snapshot
, submodule_free_dup
);
615 git_vector_foreach(&snapshot
, i
, sm
) {
616 if ((error
= callback(sm
, sm
->name
, payload
)) != 0) {
617 git_error_set_after_callback(error
);
623 git_vector_foreach(&snapshot
, i
, sm
)
624 git_submodule_free(sm
);
625 git_vector_free(&snapshot
);
627 git_strmap_foreach_value(submodules
, sm
, {
628 git_submodule_free(sm
);
630 git_strmap_free(submodules
);
635 static int submodule_repo_init(
636 git_repository
**out
,
637 git_repository
*parent_repo
,
643 git_buf workdir
= GIT_BUF_INIT
, repodir
= GIT_BUF_INIT
;
644 git_repository_init_options initopt
= GIT_REPOSITORY_INIT_OPTIONS_INIT
;
645 git_repository
*subrepo
= NULL
;
647 error
= git_buf_joinpath(&workdir
, git_repository_workdir(parent_repo
), path
);
651 initopt
.flags
= GIT_REPOSITORY_INIT_MKPATH
| GIT_REPOSITORY_INIT_NO_REINIT
;
652 initopt
.origin_url
= url
;
654 /* init submodule repository and add origin remote as needed */
656 /* New style: sub-repo goes in <repo-dir>/modules/<name>/ with a
657 * gitlink in the sub-repo workdir directory to that repository
659 * Old style: sub-repo goes directly into repo/<name>/.git/
662 error
= git_repository_item_path(&repodir
, parent_repo
, GIT_REPOSITORY_ITEM_MODULES
);
665 error
= git_buf_joinpath(&repodir
, repodir
.ptr
, path
);
669 initopt
.workdir_path
= workdir
.ptr
;
671 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR
|
672 GIT_REPOSITORY_INIT_RELATIVE_GITLINK
;
674 error
= git_repository_init_ext(&subrepo
, repodir
.ptr
, &initopt
);
676 error
= git_repository_init_ext(&subrepo
, workdir
.ptr
, &initopt
);
679 git_buf_dispose(&workdir
);
680 git_buf_dispose(&repodir
);
687 int git_submodule_add_setup(
689 git_repository
*repo
,
695 git_config_backend
*mods
= NULL
;
696 git_submodule
*sm
= NULL
;
697 git_buf name
= GIT_BUF_INIT
, real_url
= GIT_BUF_INIT
;
698 git_repository
*subrepo
= NULL
;
701 assert(repo
&& url
&& path
);
703 /* see if there is already an entry for this submodule */
705 if (git_submodule_lookup(NULL
, repo
, path
) < 0)
708 git_error_set(GIT_ERROR_SUBMODULE
,
709 "attempt to add submodule '%s' that already exists", path
);
713 /* validate and normalize path */
715 if (git__prefixcmp(path
, git_repository_workdir(repo
)) == 0)
716 path
+= strlen(git_repository_workdir(repo
));
718 if (git_path_root(path
) >= 0) {
719 git_error_set(GIT_ERROR_SUBMODULE
, "submodule path must be a relative path");
724 if ((error
= is_path_occupied(&path_occupied
, repo
, path
)) < 0)
732 /* update .gitmodules */
734 if (!(mods
= open_gitmodules(repo
, GITMODULES_CREATE
))) {
735 git_error_set(GIT_ERROR_SUBMODULE
,
736 "adding submodules to a bare repository is not supported");
740 if ((error
= git_buf_printf(&name
, "submodule.%s.path", path
)) < 0 ||
741 (error
= git_config_backend_set_string(mods
, name
.ptr
, path
)) < 0)
744 if ((error
= submodule_config_key_trunc_puts(&name
, "url")) < 0 ||
745 (error
= git_config_backend_set_string(mods
, name
.ptr
, url
)) < 0)
748 git_buf_clear(&name
);
750 /* init submodule repository and add origin remote as needed */
752 error
= git_buf_joinpath(&name
, git_repository_workdir(repo
), path
);
756 /* if the repo does not already exist, then init a new repo and add it.
757 * Otherwise, just add the existing repo.
759 if (!(git_path_exists(name
.ptr
) &&
760 git_path_contains(&name
, DOT_GIT
))) {
762 /* resolve the actual URL to use */
763 if ((error
= git_submodule_resolve_url(&real_url
, repo
, url
)) < 0)
766 if ((error
= submodule_repo_init(&subrepo
, repo
, path
, real_url
.ptr
, use_gitlink
)) < 0)
770 if ((error
= git_submodule_lookup(&sm
, repo
, path
)) < 0)
773 error
= git_submodule_init(sm
, false);
777 git_submodule_free(sm
);
783 git_config_backend_free(mods
);
784 git_repository_free(subrepo
);
785 git_buf_dispose(&real_url
);
786 git_buf_dispose(&name
);
791 int git_submodule_repo_init(
792 git_repository
**out
,
793 const git_submodule
*sm
,
797 git_repository
*sub_repo
= NULL
;
798 const char *configured_url
;
799 git_config
*cfg
= NULL
;
800 git_buf buf
= GIT_BUF_INIT
;
804 /* get the configured remote url of the submodule */
805 if ((error
= git_buf_printf(&buf
, "submodule.%s.url", sm
->name
)) < 0 ||
806 (error
= git_repository_config_snapshot(&cfg
, sm
->repo
)) < 0 ||
807 (error
= git_config_get_string(&configured_url
, cfg
, buf
.ptr
)) < 0 ||
808 (error
= submodule_repo_init(&sub_repo
, sm
->repo
, sm
->path
, configured_url
, use_gitlink
)) < 0)
814 git_config_free(cfg
);
815 git_buf_dispose(&buf
);
819 static int clone_return_origin(git_remote
**out
, git_repository
*repo
, const char *name
, const char *url
, void *payload
)
823 return git_remote_lookup(out
, repo
, name
);
826 static int clone_return_repo(git_repository
**out
, const char *path
, int bare
, void *payload
)
828 git_submodule
*sm
= payload
;
832 return git_submodule_open(out
, sm
);
835 int git_submodule_clone(git_repository
**out
, git_submodule
*submodule
, const git_submodule_update_options
*given_opts
)
838 git_repository
*clone
;
839 git_buf rel_path
= GIT_BUF_INIT
;
840 git_submodule_update_options sub_opts
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
841 git_clone_options opts
= GIT_CLONE_OPTIONS_INIT
;
846 memcpy(&sub_opts
, given_opts
, sizeof(sub_opts
));
848 GIT_ERROR_CHECK_VERSION(&sub_opts
, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION
, "git_submodule_update_options");
850 memcpy(&opts
.checkout_opts
, &sub_opts
.checkout_opts
, sizeof(sub_opts
.checkout_opts
));
851 memcpy(&opts
.fetch_opts
, &sub_opts
.fetch_opts
, sizeof(sub_opts
.fetch_opts
));
852 opts
.repository_cb
= clone_return_repo
;
853 opts
.repository_cb_payload
= submodule
;
854 opts
.remote_cb
= clone_return_origin
;
855 opts
.remote_cb_payload
= submodule
;
857 git_buf_puts(&rel_path
, git_repository_workdir(git_submodule_owner(submodule
)));
858 git_buf_joinpath(&rel_path
, git_buf_cstr(&rel_path
), git_submodule_path(submodule
));
860 GIT_ERROR_CHECK_ALLOC_BUF(&rel_path
);
862 error
= git_clone__submodule(&clone
, git_submodule_url(submodule
), git_buf_cstr(&rel_path
), &opts
);
867 git_repository_free(clone
);
872 git_buf_dispose(&rel_path
);
877 int git_submodule_add_finalize(git_submodule
*sm
)
884 if ((error
= git_repository_index__weakptr(&index
, sm
->repo
)) < 0 ||
885 (error
= git_index_add_bypath(index
, GIT_MODULES_FILE
)) < 0)
888 return git_submodule_add_to_index(sm
, true);
891 int git_submodule_add_to_index(git_submodule
*sm
, int write_index
)
894 git_repository
*sm_repo
= NULL
;
896 git_buf path
= GIT_BUF_INIT
;
898 git_index_entry entry
;
903 /* force reload of wd OID by git_submodule_open */
904 sm
->flags
= sm
->flags
& ~GIT_SUBMODULE_STATUS__WD_OID_VALID
;
906 if ((error
= git_repository_index__weakptr(&index
, sm
->repo
)) < 0 ||
907 (error
= git_buf_joinpath(
908 &path
, git_repository_workdir(sm
->repo
), sm
->path
)) < 0 ||
909 (error
= git_submodule_open(&sm_repo
, sm
)) < 0)
912 /* read stat information for submodule working directory */
913 if (p_stat(path
.ptr
, &st
) < 0) {
914 git_error_set(GIT_ERROR_SUBMODULE
,
915 "cannot add submodule without working directory");
920 memset(&entry
, 0, sizeof(entry
));
921 entry
.path
= sm
->path
;
922 git_index_entry__init_from_stat(
923 &entry
, &st
, !(git_index_caps(index
) & GIT_INDEX_CAPABILITY_NO_FILEMODE
));
925 /* calling git_submodule_open will have set sm->wd_oid if possible */
926 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
) == 0) {
927 git_error_set(GIT_ERROR_SUBMODULE
,
928 "cannot add submodule without HEAD to index");
932 git_oid_cpy(&entry
.id
, &sm
->wd_oid
);
934 if ((error
= git_commit_lookup(&head
, sm_repo
, &sm
->wd_oid
)) < 0)
937 entry
.ctime
.seconds
= (int32_t)git_commit_time(head
);
938 entry
.ctime
.nanoseconds
= 0;
939 entry
.mtime
.seconds
= (int32_t)git_commit_time(head
);
940 entry
.mtime
.nanoseconds
= 0;
942 git_commit_free(head
);
945 error
= git_index_add(index
, &entry
);
947 /* write it, if requested */
948 if (!error
&& write_index
) {
949 error
= git_index_write(index
);
952 git_oid_cpy(&sm
->index_oid
, &sm
->wd_oid
);
956 git_repository_free(sm_repo
);
957 git_buf_dispose(&path
);
961 const char *git_submodule_update_to_str(git_submodule_update_t update
)
964 for (i
= 0; i
< (int)ARRAY_SIZE(_sm_update_map
); ++i
)
965 if (_sm_update_map
[i
].map_value
== (int)update
)
966 return _sm_update_map
[i
].str_match
;
970 git_repository
*git_submodule_owner(git_submodule
*submodule
)
973 return submodule
->repo
;
976 const char *git_submodule_name(git_submodule
*submodule
)
979 return submodule
->name
;
982 const char *git_submodule_path(git_submodule
*submodule
)
985 return submodule
->path
;
988 const char *git_submodule_url(git_submodule
*submodule
)
991 return submodule
->url
;
994 int git_submodule_resolve_url(git_buf
*out
, git_repository
*repo
, const char *url
)
997 git_buf normalized
= GIT_BUF_INIT
;
999 assert(out
&& repo
&& url
);
1001 git_buf_sanitize(out
);
1003 /* We do this in all platforms in case someone on Windows created the .gitmodules */
1004 if (strchr(url
, '\\')) {
1005 if ((error
= git_path_normalize_slashes(&normalized
, url
)) < 0)
1008 url
= normalized
.ptr
;
1012 if (git_path_is_relative(url
)) {
1013 if (!(error
= get_url_base(out
, repo
)))
1014 error
= git_path_apply_relative(out
, url
);
1015 } else if (strchr(url
, ':') != NULL
|| url
[0] == '/') {
1016 error
= git_buf_sets(out
, url
);
1018 git_error_set(GIT_ERROR_SUBMODULE
, "invalid format for submodule URL");
1022 git_buf_dispose(&normalized
);
1026 static int write_var(git_repository
*repo
, const char *name
, const char *var
, const char *val
)
1028 git_buf key
= GIT_BUF_INIT
;
1029 git_config_backend
*mods
;
1032 mods
= open_gitmodules(repo
, GITMODULES_CREATE
);
1036 if ((error
= git_buf_printf(&key
, "submodule.%s.%s", name
, var
)) < 0)
1040 error
= git_config_backend_set_string(mods
, key
.ptr
, val
);
1042 error
= git_config_backend_delete(mods
, key
.ptr
);
1044 git_buf_dispose(&key
);
1047 git_config_backend_free(mods
);
1051 static int write_mapped_var(git_repository
*repo
, const char *name
, git_configmap
*maps
, size_t nmaps
, const char *var
, int ival
)
1053 git_configmap_t type
;
1056 if (git_config_lookup_map_enum(&type
, &val
, maps
, nmaps
, ival
) < 0) {
1057 git_error_set(GIT_ERROR_SUBMODULE
, "invalid value for %s", var
);
1061 if (type
== GIT_CONFIGMAP_TRUE
)
1064 return write_var(repo
, name
, var
, val
);
1067 const char *git_submodule_branch(git_submodule
*submodule
)
1070 return submodule
->branch
;
1073 int git_submodule_set_branch(git_repository
*repo
, const char *name
, const char *branch
)
1076 assert(repo
&& name
);
1078 return write_var(repo
, name
, "branch", branch
);
1081 int git_submodule_set_url(git_repository
*repo
, const char *name
, const char *url
)
1083 assert(repo
&& name
&& url
);
1085 return write_var(repo
, name
, "url", url
);
1088 const git_oid
*git_submodule_index_id(git_submodule
*submodule
)
1092 if (submodule
->flags
& GIT_SUBMODULE_STATUS__INDEX_OID_VALID
)
1093 return &submodule
->index_oid
;
1098 const git_oid
*git_submodule_head_id(git_submodule
*submodule
)
1102 if (submodule
->flags
& GIT_SUBMODULE_STATUS__HEAD_OID_VALID
)
1103 return &submodule
->head_oid
;
1108 const git_oid
*git_submodule_wd_id(git_submodule
*submodule
)
1112 /* load unless we think we have a valid oid */
1113 if (!(submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)) {
1114 git_repository
*subrepo
;
1116 /* calling submodule open grabs the HEAD OID if possible */
1117 if (!git_submodule_open_bare(&subrepo
, submodule
))
1118 git_repository_free(subrepo
);
1123 if (submodule
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
)
1124 return &submodule
->wd_oid
;
1129 git_submodule_ignore_t
git_submodule_ignore(git_submodule
*submodule
)
1132 return (submodule
->ignore
< GIT_SUBMODULE_IGNORE_NONE
) ?
1133 GIT_SUBMODULE_IGNORE_NONE
: submodule
->ignore
;
1136 int git_submodule_set_ignore(git_repository
*repo
, const char *name
, git_submodule_ignore_t ignore
)
1138 assert(repo
&& name
);
1140 return write_mapped_var(repo
, name
, _sm_ignore_map
, ARRAY_SIZE(_sm_ignore_map
), "ignore", ignore
);
1143 git_submodule_update_t
git_submodule_update_strategy(git_submodule
*submodule
)
1146 return (submodule
->update
< GIT_SUBMODULE_UPDATE_CHECKOUT
) ?
1147 GIT_SUBMODULE_UPDATE_CHECKOUT
: submodule
->update
;
1150 int git_submodule_set_update(git_repository
*repo
, const char *name
, git_submodule_update_t update
)
1152 assert(repo
&& name
);
1154 return write_mapped_var(repo
, name
, _sm_update_map
, ARRAY_SIZE(_sm_update_map
), "update", update
);
1157 git_submodule_recurse_t
git_submodule_fetch_recurse_submodules(
1158 git_submodule
*submodule
)
1161 return submodule
->fetch_recurse
;
1164 int git_submodule_set_fetch_recurse_submodules(git_repository
*repo
, const char *name
, git_submodule_recurse_t recurse
)
1166 assert(repo
&& name
);
1168 return write_mapped_var(repo
, name
, _sm_recurse_map
, ARRAY_SIZE(_sm_recurse_map
), "fetchRecurseSubmodules", recurse
);
1171 static int submodule_repo_create(
1172 git_repository
**out
,
1173 git_repository
*parent_repo
,
1177 git_buf workdir
= GIT_BUF_INIT
, repodir
= GIT_BUF_INIT
;
1178 git_repository_init_options initopt
= GIT_REPOSITORY_INIT_OPTIONS_INIT
;
1179 git_repository
*subrepo
= NULL
;
1182 GIT_REPOSITORY_INIT_MKPATH
|
1183 GIT_REPOSITORY_INIT_NO_REINIT
|
1184 GIT_REPOSITORY_INIT_NO_DOTGIT_DIR
|
1185 GIT_REPOSITORY_INIT_RELATIVE_GITLINK
;
1187 /* Workdir: path to sub-repo working directory */
1188 error
= git_buf_joinpath(&workdir
, git_repository_workdir(parent_repo
), path
);
1192 initopt
.workdir_path
= workdir
.ptr
;
1195 * Repodir: path to the sub-repo. sub-repo goes in:
1196 * <repo-dir>/modules/<name>/ with a gitlink in the
1197 * sub-repo workdir directory to that repository.
1199 error
= git_repository_item_path(&repodir
, parent_repo
, GIT_REPOSITORY_ITEM_MODULES
);
1202 error
= git_buf_joinpath(&repodir
, repodir
.ptr
, path
);
1206 error
= git_repository_init_ext(&subrepo
, repodir
.ptr
, &initopt
);
1209 git_buf_dispose(&workdir
);
1210 git_buf_dispose(&repodir
);
1218 * Callback to override sub-repository creation when
1219 * cloning a sub-repository.
1221 static int git_submodule_update_repo_init_cb(
1222 git_repository
**out
,
1233 return submodule_repo_create(out
, sm
->repo
, path
);
1236 int git_submodule_update_options_init(git_submodule_update_options
*opts
, unsigned int version
)
1238 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
1239 opts
, version
, git_submodule_update_options
, GIT_SUBMODULE_UPDATE_OPTIONS_INIT
);
1243 int git_submodule_update_init_options(git_submodule_update_options
*opts
, unsigned int version
)
1245 return git_submodule_update_options_init(opts
, version
);
1248 int git_submodule_update(git_submodule
*sm
, int init
, git_submodule_update_options
*_update_options
)
1251 unsigned int submodule_status
;
1252 git_config
*config
= NULL
;
1253 const char *submodule_url
;
1254 git_repository
*sub_repo
= NULL
;
1255 git_remote
*remote
= NULL
;
1256 git_object
*target_commit
= NULL
;
1257 git_buf buf
= GIT_BUF_INIT
;
1258 git_submodule_update_options update_options
= GIT_SUBMODULE_UPDATE_OPTIONS_INIT
;
1259 git_clone_options clone_options
= GIT_CLONE_OPTIONS_INIT
;
1263 if (_update_options
)
1264 memcpy(&update_options
, _update_options
, sizeof(git_submodule_update_options
));
1266 GIT_ERROR_CHECK_VERSION(&update_options
, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION
, "git_submodule_update_options");
1268 /* Copy over the remote callbacks */
1269 memcpy(&clone_options
.fetch_opts
, &update_options
.fetch_opts
, sizeof(git_fetch_options
));
1271 /* Get the status of the submodule to determine if it is already initialized */
1272 if ((error
= git_submodule_status(&submodule_status
, sm
->repo
, sm
->name
, GIT_SUBMODULE_IGNORE_UNSPECIFIED
)) < 0)
1276 * If submodule work dir is not already initialized, check to see
1277 * what we need to do (initialize, clone, return error...)
1279 if (submodule_status
& GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
) {
1281 * Work dir is not initialized, check to see if the submodule
1282 * info has been copied into .git/config
1284 if ((error
= git_repository_config_snapshot(&config
, sm
->repo
)) < 0 ||
1285 (error
= git_buf_printf(&buf
, "submodule.%s.url", git_submodule_name(sm
))) < 0)
1288 if ((error
= git_config_get_string(&submodule_url
, config
, git_buf_cstr(&buf
))) < 0) {
1290 * If the error is not "not found" or if it is "not found" and we are not
1291 * initializing the submodule, then return error.
1293 if (error
!= GIT_ENOTFOUND
)
1297 git_error_set(GIT_ERROR_SUBMODULE
, "submodule is not initialized");
1302 /* The submodule has not been initialized yet - initialize it now.*/
1303 if ((error
= git_submodule_init(sm
, 0)) < 0)
1306 git_config_free(config
);
1309 if ((error
= git_repository_config_snapshot(&config
, sm
->repo
)) < 0 ||
1310 (error
= git_config_get_string(&submodule_url
, config
, git_buf_cstr(&buf
))) < 0)
1314 /** submodule is initialized - now clone it **/
1315 /* override repo creation */
1316 clone_options
.repository_cb
= git_submodule_update_repo_init_cb
;
1317 clone_options
.repository_cb_payload
= sm
;
1320 * Do not perform checkout as part of clone, instead we
1321 * will checkout the specific commit manually.
1323 clone_options
.checkout_opts
.checkout_strategy
= GIT_CHECKOUT_NONE
;
1325 if ((error
= git_clone(&sub_repo
, submodule_url
, sm
->path
, &clone_options
)) < 0 ||
1326 (error
= git_repository_set_head_detached(sub_repo
, git_submodule_index_id(sm
))) < 0 ||
1327 (error
= git_checkout_head(sub_repo
, &update_options
.checkout_opts
)) != 0)
1333 * Work dir is initialized - look up the commit in the parent repository's index,
1334 * update the workdir contents of the subrepository, and set the subrepository's
1335 * head to the new commit.
1337 if ((error
= git_submodule_open(&sub_repo
, sm
)) < 0)
1340 if ((oid
= git_submodule_index_id(sm
)) == NULL
) {
1341 git_error_set(GIT_ERROR_SUBMODULE
, "could not get ID of submodule in index");
1346 /* Look up the target commit in the submodule. */
1347 if ((error
= git_object_lookup(&target_commit
, sub_repo
, oid
, GIT_OBJECT_COMMIT
)) < 0) {
1348 /* If it isn't found then fetch and try again. */
1349 if (error
!= GIT_ENOTFOUND
|| !update_options
.allow_fetch
||
1350 (error
= lookup_default_remote(&remote
, sub_repo
)) < 0 ||
1351 (error
= git_remote_fetch(remote
, NULL
, &update_options
.fetch_opts
, NULL
)) < 0 ||
1352 (error
= git_object_lookup(&target_commit
, sub_repo
, git_submodule_index_id(sm
), GIT_OBJECT_COMMIT
)) < 0)
1356 if ((error
= git_checkout_tree(sub_repo
, target_commit
, &update_options
.checkout_opts
)) != 0 ||
1357 (error
= git_repository_set_head_detached(sub_repo
, git_submodule_index_id(sm
))) < 0)
1360 /* Invalidate the wd flags as the workdir has been updated. */
1361 sm
->flags
= sm
->flags
&
1362 ~(GIT_SUBMODULE_STATUS_IN_WD
|
1363 GIT_SUBMODULE_STATUS__WD_OID_VALID
|
1364 GIT_SUBMODULE_STATUS__WD_SCANNED
);
1368 git_buf_dispose(&buf
);
1369 git_config_free(config
);
1370 git_object_free(target_commit
);
1371 git_remote_free(remote
);
1372 git_repository_free(sub_repo
);
1377 int git_submodule_init(git_submodule
*sm
, int overwrite
)
1381 git_buf key
= GIT_BUF_INIT
, effective_submodule_url
= GIT_BUF_INIT
;
1382 git_config
*cfg
= NULL
;
1385 git_error_set(GIT_ERROR_SUBMODULE
,
1386 "no URL configured for submodule '%s'", sm
->name
);
1390 if ((error
= git_repository_config(&cfg
, sm
->repo
)) < 0)
1393 /* write "submodule.NAME.url" */
1395 if ((error
= git_submodule_resolve_url(&effective_submodule_url
, sm
->repo
, sm
->url
)) < 0 ||
1396 (error
= git_buf_printf(&key
, "submodule.%s.url", sm
->name
)) < 0 ||
1397 (error
= git_config__update_entry(
1398 cfg
, key
.ptr
, effective_submodule_url
.ptr
, overwrite
!= 0, false)) < 0)
1401 /* write "submodule.NAME.update" if not default */
1403 val
= (sm
->update
== GIT_SUBMODULE_UPDATE_CHECKOUT
) ?
1404 NULL
: git_submodule_update_to_str(sm
->update
);
1406 if ((error
= git_buf_printf(&key
, "submodule.%s.update", sm
->name
)) < 0 ||
1407 (error
= git_config__update_entry(
1408 cfg
, key
.ptr
, val
, overwrite
!= 0, false)) < 0)
1414 git_config_free(cfg
);
1415 git_buf_dispose(&key
);
1416 git_buf_dispose(&effective_submodule_url
);
1421 int git_submodule_sync(git_submodule
*sm
)
1423 git_buf key
= GIT_BUF_INIT
, url
= GIT_BUF_INIT
, remote_name
= GIT_BUF_INIT
;
1424 git_repository
*smrepo
= NULL
;
1425 git_config
*cfg
= NULL
;
1429 git_error_set(GIT_ERROR_SUBMODULE
, "no URL configured for submodule '%s'", sm
->name
);
1433 /* copy URL over to config only if it already exists */
1434 if ((error
= git_repository_config__weakptr(&cfg
, sm
->repo
)) < 0 ||
1435 (error
= git_buf_printf(&key
, "submodule.%s.url", sm
->name
)) < 0 ||
1436 (error
= git_submodule_resolve_url(&url
, sm
->repo
, sm
->url
)) < 0 ||
1437 (error
= git_config__update_entry(cfg
, key
.ptr
, url
.ptr
, true, true)) < 0)
1440 if (!(sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
))
1443 /* if submodule exists in the working directory, update remote url */
1444 if ((error
= git_submodule_open(&smrepo
, sm
)) < 0 ||
1445 (error
= git_repository_config__weakptr(&cfg
, smrepo
)) < 0)
1448 if (lookup_head_remote_key(&remote_name
, smrepo
) == 0) {
1449 if ((error
= git_buf_join3(&key
, '.', "remote", remote_name
.ptr
, "url")) < 0)
1451 } else if ((error
= git_buf_sets(&key
, "remote.origin.url")) < 0) {
1455 if ((error
= git_config__update_entry(cfg
, key
.ptr
, url
.ptr
, true, false)) < 0)
1459 git_repository_free(smrepo
);
1460 git_buf_dispose(&remote_name
);
1461 git_buf_dispose(&key
);
1462 git_buf_dispose(&url
);
1466 static int git_submodule__open(
1467 git_repository
**subrepo
, git_submodule
*sm
, bool bare
)
1470 git_buf path
= GIT_BUF_INIT
;
1471 unsigned int flags
= GIT_REPOSITORY_OPEN_NO_SEARCH
;
1474 assert(sm
&& subrepo
);
1476 if (git_repository__ensure_not_bare(
1477 sm
->repo
, "open submodule repository") < 0)
1478 return GIT_EBAREREPO
;
1480 wd
= git_repository_workdir(sm
->repo
);
1482 if (git_buf_joinpath(&path
, wd
, sm
->path
) < 0 ||
1483 git_buf_joinpath(&path
, path
.ptr
, DOT_GIT
) < 0)
1486 sm
->flags
= sm
->flags
&
1487 ~(GIT_SUBMODULE_STATUS_IN_WD
|
1488 GIT_SUBMODULE_STATUS__WD_OID_VALID
|
1489 GIT_SUBMODULE_STATUS__WD_SCANNED
);
1492 flags
|= GIT_REPOSITORY_OPEN_BARE
;
1494 error
= git_repository_open_ext(subrepo
, path
.ptr
, flags
, wd
);
1496 /* if we opened the submodule successfully, grab HEAD OID, etc. */
1498 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
|
1499 GIT_SUBMODULE_STATUS__WD_SCANNED
;
1501 if (!git_reference_name_to_id(&sm
->wd_oid
, *subrepo
, GIT_HEAD_FILE
))
1502 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_OID_VALID
;
1505 } else if (git_path_exists(path
.ptr
)) {
1506 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
|
1507 GIT_SUBMODULE_STATUS_IN_WD
;
1509 git_buf_rtruncate_at_char(&path
, '/'); /* remove "/.git" */
1511 if (git_path_isdir(path
.ptr
))
1512 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
1515 git_buf_dispose(&path
);
1520 int git_submodule_open_bare(git_repository
**subrepo
, git_submodule
*sm
)
1522 return git_submodule__open(subrepo
, sm
, true);
1525 int git_submodule_open(git_repository
**subrepo
, git_submodule
*sm
)
1527 return git_submodule__open(subrepo
, sm
, false);
1530 static void submodule_update_from_index_entry(
1531 git_submodule
*sm
, const git_index_entry
*ie
)
1533 bool already_found
= (sm
->flags
& GIT_SUBMODULE_STATUS_IN_INDEX
) != 0;
1535 if (!S_ISGITLINK(ie
->mode
)) {
1537 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_NOT_SUBMODULE
;
1540 sm
->flags
|= GIT_SUBMODULE_STATUS__INDEX_MULTIPLE_ENTRIES
;
1542 git_oid_cpy(&sm
->index_oid
, &ie
->id
);
1544 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_INDEX
|
1545 GIT_SUBMODULE_STATUS__INDEX_OID_VALID
;
1549 static int submodule_update_index(git_submodule
*sm
)
1552 const git_index_entry
*ie
;
1554 if (git_repository_index__weakptr(&index
, sm
->repo
) < 0)
1557 sm
->flags
= sm
->flags
&
1558 ~(GIT_SUBMODULE_STATUS_IN_INDEX
|
1559 GIT_SUBMODULE_STATUS__INDEX_OID_VALID
);
1561 if (!(ie
= git_index_get_bypath(index
, sm
->path
, 0)))
1564 submodule_update_from_index_entry(sm
, ie
);
1569 static void submodule_update_from_head_data(
1570 git_submodule
*sm
, mode_t mode
, const git_oid
*id
)
1572 if (!S_ISGITLINK(mode
))
1573 sm
->flags
|= GIT_SUBMODULE_STATUS__HEAD_NOT_SUBMODULE
;
1575 git_oid_cpy(&sm
->head_oid
, id
);
1577 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_HEAD
|
1578 GIT_SUBMODULE_STATUS__HEAD_OID_VALID
;
1582 static int submodule_update_head(git_submodule
*submodule
)
1584 git_tree
*head
= NULL
;
1585 git_tree_entry
*te
= NULL
;
1587 submodule
->flags
= submodule
->flags
&
1588 ~(GIT_SUBMODULE_STATUS_IN_HEAD
|
1589 GIT_SUBMODULE_STATUS__HEAD_OID_VALID
);
1591 /* if we can't look up file in current head, then done */
1592 if (git_repository_head_tree(&head
, submodule
->repo
) < 0 ||
1593 git_tree_entry_bypath(&te
, head
, submodule
->path
) < 0)
1596 submodule_update_from_head_data(submodule
, te
->attr
, git_tree_entry_id(te
));
1598 git_tree_entry_free(te
);
1599 git_tree_free(head
);
1603 int git_submodule_reload(git_submodule
*sm
, int force
)
1605 git_config
*mods
= NULL
;
1612 if ((error
= git_submodule_name_is_valid(sm
->repo
, sm
->name
, 0)) <= 0)
1613 /* This should come with a warning, but we've no API for that */
1616 if (git_repository_is_bare(sm
->repo
))
1619 /* refresh config data */
1620 if ((error
= gitmodules_snapshot(&mods
, sm
->repo
)) < 0 && error
!= GIT_ENOTFOUND
)
1623 if (mods
!= NULL
&& (error
= submodule_read_config(sm
, mods
)) < 0)
1626 /* refresh wd data */
1628 ~(GIT_SUBMODULE_STATUS_IN_WD
|
1629 GIT_SUBMODULE_STATUS__WD_OID_VALID
|
1630 GIT_SUBMODULE_STATUS__WD_FLAGS
);
1632 if ((error
= submodule_load_from_wd_lite(sm
)) < 0 ||
1633 (error
= submodule_update_index(sm
)) < 0 ||
1634 (error
= submodule_update_head(sm
)) < 0)
1638 git_config_free(mods
);
1642 static void submodule_copy_oid_maybe(
1643 git_oid
*tgt
, const git_oid
*src
, bool valid
)
1647 memcpy(tgt
, src
, sizeof(*tgt
));
1649 memset(tgt
, 0, sizeof(*tgt
));
1653 int git_submodule__status(
1654 unsigned int *out_status
,
1655 git_oid
*out_head_id
,
1656 git_oid
*out_index_id
,
1659 git_submodule_ignore_t ign
)
1661 unsigned int status
;
1662 git_repository
*smrepo
= NULL
;
1664 if (ign
== GIT_SUBMODULE_IGNORE_UNSPECIFIED
)
1667 /* only return location info if ignore == all */
1668 if (ign
== GIT_SUBMODULE_IGNORE_ALL
) {
1669 *out_status
= (sm
->flags
& GIT_SUBMODULE_STATUS__IN_FLAGS
);
1673 /* If the user has requested caching submodule state, performing these
1674 * expensive operations (especially `submodule_update_head`, which is
1675 * bottlenecked on `git_repository_head_tree`) eliminates much of the
1676 * advantage. We will, therefore, interpret the request for caching to
1677 * apply here to and skip them.
1680 if (sm
->repo
->submodule_cache
== NULL
) {
1681 /* refresh the index OID */
1682 if (submodule_update_index(sm
) < 0)
1685 /* refresh the HEAD OID */
1686 if (submodule_update_head(sm
) < 0)
1690 /* for ignore == dirty, don't scan the working directory */
1691 if (ign
== GIT_SUBMODULE_IGNORE_DIRTY
) {
1692 /* git_submodule_open_bare will load WD OID data */
1693 if (git_submodule_open_bare(&smrepo
, sm
) < 0)
1696 git_repository_free(smrepo
);
1698 } else if (git_submodule_open(&smrepo
, sm
) < 0) {
1703 status
= GIT_SUBMODULE_STATUS__CLEAR_INTERNAL(sm
->flags
);
1705 submodule_get_index_status(&status
, sm
);
1706 submodule_get_wd_status(&status
, sm
, smrepo
, ign
);
1708 git_repository_free(smrepo
);
1710 *out_status
= status
;
1712 submodule_copy_oid_maybe(out_head_id
, &sm
->head_oid
,
1713 (sm
->flags
& GIT_SUBMODULE_STATUS__HEAD_OID_VALID
) != 0);
1714 submodule_copy_oid_maybe(out_index_id
, &sm
->index_oid
,
1715 (sm
->flags
& GIT_SUBMODULE_STATUS__INDEX_OID_VALID
) != 0);
1716 submodule_copy_oid_maybe(out_wd_id
, &sm
->wd_oid
,
1717 (sm
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
) != 0);
1722 int git_submodule_status(unsigned int *status
, git_repository
*repo
, const char *name
, git_submodule_ignore_t ignore
)
1727 assert(status
&& repo
&& name
);
1729 if ((error
= git_submodule_lookup(&sm
, repo
, name
)) < 0)
1732 error
= git_submodule__status(status
, NULL
, NULL
, NULL
, sm
, ignore
);
1733 git_submodule_free(sm
);
1738 int git_submodule_location(unsigned int *location
, git_submodule
*sm
)
1740 assert(location
&& sm
);
1742 return git_submodule__status(
1743 location
, NULL
, NULL
, NULL
, sm
, GIT_SUBMODULE_IGNORE_ALL
);
1747 * INTERNAL FUNCTIONS
1750 static int submodule_alloc(
1751 git_submodule
**out
, git_repository
*repo
, const char *name
)
1756 if (!name
|| !(namelen
= strlen(name
))) {
1757 git_error_set(GIT_ERROR_SUBMODULE
, "invalid submodule name");
1761 sm
= git__calloc(1, sizeof(git_submodule
));
1762 GIT_ERROR_CHECK_ALLOC(sm
);
1764 sm
->name
= sm
->path
= git__strdup(name
);
1770 GIT_REFCOUNT_INC(sm
);
1771 sm
->ignore
= sm
->ignore_default
= GIT_SUBMODULE_IGNORE_NONE
;
1772 sm
->update
= sm
->update_default
= GIT_SUBMODULE_UPDATE_CHECKOUT
;
1773 sm
->fetch_recurse
= sm
->fetch_recurse_default
= GIT_SUBMODULE_RECURSE_NO
;
1781 static void submodule_release(git_submodule
*sm
)
1790 if (sm
->path
!= sm
->name
)
1791 git__free(sm
->path
);
1792 git__free(sm
->name
);
1794 git__free(sm
->branch
);
1795 git__memzero(sm
, sizeof(*sm
));
1799 void git_submodule_free(git_submodule
*sm
)
1803 GIT_REFCOUNT_DEC(sm
, submodule_release
);
1806 static int submodule_config_error(const char *property
, const char *value
)
1808 git_error_set(GIT_ERROR_INVALID
,
1809 "invalid value for submodule '%s' property: '%s'", property
, value
);
1813 int git_submodule_parse_ignore(git_submodule_ignore_t
*out
, const char *value
)
1817 if (git_config_lookup_map_value(
1818 &val
, _sm_ignore_map
, ARRAY_SIZE(_sm_ignore_map
), value
) < 0) {
1819 *out
= GIT_SUBMODULE_IGNORE_NONE
;
1820 return submodule_config_error("ignore", value
);
1823 *out
= (git_submodule_ignore_t
)val
;
1827 int git_submodule_parse_update(git_submodule_update_t
*out
, const char *value
)
1831 if (git_config_lookup_map_value(
1832 &val
, _sm_update_map
, ARRAY_SIZE(_sm_update_map
), value
) < 0) {
1833 *out
= GIT_SUBMODULE_UPDATE_CHECKOUT
;
1834 return submodule_config_error("update", value
);
1837 *out
= (git_submodule_update_t
)val
;
1841 int git_submodule_parse_recurse(git_submodule_recurse_t
*out
, const char *value
)
1845 if (git_config_lookup_map_value(
1846 &val
, _sm_recurse_map
, ARRAY_SIZE(_sm_recurse_map
), value
) < 0) {
1847 *out
= GIT_SUBMODULE_RECURSE_YES
;
1848 return submodule_config_error("recurse", value
);
1851 *out
= (git_submodule_recurse_t
)val
;
1855 static int get_value(const char **out
, git_config
*cfg
, git_buf
*buf
, const char *name
, const char *field
)
1861 if ((error
= git_buf_printf(buf
, "submodule.%s.%s", name
, field
)) < 0 ||
1862 (error
= git_config_get_string(out
, cfg
, buf
->ptr
)) < 0)
1868 static bool looks_like_command_line_option(const char *s
)
1870 if (s
&& s
[0] == '-')
1876 static int submodule_read_config(git_submodule
*sm
, git_config
*cfg
)
1878 git_buf key
= GIT_BUF_INIT
;
1880 int error
, in_config
= 0;
1883 * TODO: Look up path in index and if it is present but not a GITLINK
1884 * then this should be deleted (at least to match git's behavior)
1887 if ((error
= get_value(&value
, cfg
, &key
, sm
->name
, "path")) == 0) {
1889 /* We would warn here if we had that API */
1890 if (!looks_like_command_line_option(value
)) {
1892 * TODO: if case insensitive filesystem, then the following strcmp
1893 * should be strcasecmp
1895 if (strcmp(sm
->name
, value
) != 0) {
1896 if (sm
->path
!= sm
->name
)
1897 git__free(sm
->path
);
1898 sm
->path
= git__strdup(value
);
1899 GIT_ERROR_CHECK_ALLOC(sm
->path
);
1903 } else if (error
!= GIT_ENOTFOUND
) {
1907 if ((error
= get_value(&value
, cfg
, &key
, sm
->name
, "url")) == 0) {
1908 /* We would warn here if we had that API */
1909 if (!looks_like_command_line_option(value
)) {
1911 sm
->url
= git__strdup(value
);
1912 GIT_ERROR_CHECK_ALLOC(sm
->url
);
1914 } else if (error
!= GIT_ENOTFOUND
) {
1918 if ((error
= get_value(&value
, cfg
, &key
, sm
->name
, "branch")) == 0) {
1920 sm
->branch
= git__strdup(value
);
1921 GIT_ERROR_CHECK_ALLOC(sm
->branch
);
1922 } else if (error
!= GIT_ENOTFOUND
) {
1926 if ((error
= get_value(&value
, cfg
, &key
, sm
->name
, "update")) == 0) {
1928 if ((error
= git_submodule_parse_update(&sm
->update
, value
)) < 0)
1930 sm
->update_default
= sm
->update
;
1931 } else if (error
!= GIT_ENOTFOUND
) {
1935 if ((error
= get_value(&value
, cfg
, &key
, sm
->name
, "fetchRecurseSubmodules")) == 0) {
1937 if ((error
= git_submodule_parse_recurse(&sm
->fetch_recurse
, value
)) < 0)
1939 sm
->fetch_recurse_default
= sm
->fetch_recurse
;
1940 } else if (error
!= GIT_ENOTFOUND
) {
1944 if ((error
= get_value(&value
, cfg
, &key
, sm
->name
, "ignore")) == 0) {
1946 if ((error
= git_submodule_parse_ignore(&sm
->ignore
, value
)) < 0)
1948 sm
->ignore_default
= sm
->ignore
;
1949 } else if (error
!= GIT_ENOTFOUND
) {
1954 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_CONFIG
;
1959 git_buf_dispose(&key
);
1963 static int submodule_load_each(const git_config_entry
*entry
, void *payload
)
1965 lfc_data
*data
= payload
;
1966 const char *namestart
, *property
;
1967 git_strmap
*map
= data
->map
;
1968 git_buf name
= GIT_BUF_INIT
;
1972 if (git__prefixcmp(entry
->name
, "submodule.") != 0)
1975 namestart
= entry
->name
+ strlen("submodule.");
1976 property
= strrchr(namestart
, '.');
1978 if (!property
|| (property
== namestart
))
1983 if ((error
= git_buf_set(&name
, namestart
, property
- namestart
-1)) < 0)
1986 isvalid
= git_submodule_name_is_valid(data
->repo
, name
.ptr
, 0);
1993 * Now that we have the submodule's name, we can use that to
1994 * figure out whether it's in the map. If it's not, we create
1995 * a new submodule, load the config and insert it. If it's
1996 * already inserted, we've already loaded it, so we skip.
1998 if (git_strmap_exists(map
, name
.ptr
)) {
2003 if ((error
= submodule_alloc(&sm
, data
->repo
, name
.ptr
)) < 0)
2006 if ((error
= submodule_read_config(sm
, data
->mods
)) < 0) {
2007 git_submodule_free(sm
);
2011 if ((error
= git_strmap_set(map
, sm
->name
, sm
)) < 0)
2017 git_buf_dispose(&name
);
2021 static int submodule_load_from_wd_lite(git_submodule
*sm
)
2023 git_buf path
= GIT_BUF_INIT
;
2025 if (git_buf_joinpath(&path
, git_repository_workdir(sm
->repo
), sm
->path
) < 0)
2028 if (git_path_isdir(path
.ptr
))
2029 sm
->flags
|= GIT_SUBMODULE_STATUS__WD_SCANNED
;
2031 if (git_path_contains(&path
, DOT_GIT
))
2032 sm
->flags
|= GIT_SUBMODULE_STATUS_IN_WD
;
2034 git_buf_dispose(&path
);
2039 * Requests a snapshot of $WORK_TREE/.gitmodules.
2041 * Returns GIT_ENOTFOUND in case no .gitmodules file exist
2043 static int gitmodules_snapshot(git_config
**snap
, git_repository
*repo
)
2045 const char *workdir
= git_repository_workdir(repo
);
2046 git_config
*mods
= NULL
;
2047 git_buf path
= GIT_BUF_INIT
;
2051 return GIT_ENOTFOUND
;
2053 if ((error
= git_buf_joinpath(&path
, workdir
, GIT_MODULES_FILE
)) < 0)
2056 if ((error
= git_config_open_ondisk(&mods
, path
.ptr
)) < 0)
2058 git_buf_dispose(&path
);
2060 if ((error
= git_config_snapshot(snap
, mods
)) < 0)
2067 git_config_free(mods
);
2068 git_buf_dispose(&path
);
2073 static git_config_backend
*open_gitmodules(
2074 git_repository
*repo
,
2077 const char *workdir
= git_repository_workdir(repo
);
2078 git_buf path
= GIT_BUF_INIT
;
2079 git_config_backend
*mods
= NULL
;
2081 if (workdir
!= NULL
) {
2082 if (git_buf_joinpath(&path
, workdir
, GIT_MODULES_FILE
) != 0)
2085 if (okay_to_create
|| git_path_isfile(path
.ptr
)) {
2086 /* git_config_backend_from_file should only fail if OOM */
2087 if (git_config_backend_from_file(&mods
, path
.ptr
) < 0)
2089 /* open should only fail here if the file is malformed */
2090 else if (git_config_backend_open(mods
, GIT_CONFIG_LEVEL_LOCAL
, repo
) < 0) {
2091 git_config_backend_free(mods
);
2097 git_buf_dispose(&path
);
2102 /* Lookup name of remote of the local tracking branch HEAD points to */
2103 static int lookup_head_remote_key(git_buf
*remote_name
, git_repository
*repo
)
2106 git_reference
*head
= NULL
;
2107 git_buf upstream_name
= GIT_BUF_INIT
;
2109 /* lookup and dereference HEAD */
2110 if ((error
= git_repository_head(&head
, repo
)) < 0)
2114 * If head does not refer to a branch, then return
2115 * GIT_ENOTFOUND to indicate that we could not find
2116 * a remote key for the local tracking branch HEAD points to.
2118 if (!git_reference_is_branch(head
)) {
2119 git_error_set(GIT_ERROR_INVALID
,
2120 "HEAD does not refer to a branch.");
2121 error
= GIT_ENOTFOUND
;
2125 /* lookup remote tracking branch of HEAD */
2126 if ((error
= git_branch_upstream_name(
2129 git_reference_name(head
))) < 0)
2132 /* lookup remote of remote tracking branch */
2133 if ((error
= git_branch_remote_name(remote_name
, repo
, upstream_name
.ptr
)) < 0)
2137 git_buf_dispose(&upstream_name
);
2138 git_reference_free(head
);
2143 /* Lookup the remote of the local tracking branch HEAD points to */
2144 static int lookup_head_remote(git_remote
**remote
, git_repository
*repo
)
2147 git_buf remote_name
= GIT_BUF_INIT
;
2149 /* lookup remote of remote tracking branch name */
2150 if (!(error
= lookup_head_remote_key(&remote_name
, repo
)))
2151 error
= git_remote_lookup(remote
, repo
, remote_name
.ptr
);
2153 git_buf_dispose(&remote_name
);
2158 /* Lookup remote, either from HEAD or fall back on origin */
2159 static int lookup_default_remote(git_remote
**remote
, git_repository
*repo
)
2161 int error
= lookup_head_remote(remote
, repo
);
2163 /* if that failed, use 'origin' instead */
2164 if (error
== GIT_ENOTFOUND
|| error
== GIT_EUNBORNBRANCH
)
2165 error
= git_remote_lookup(remote
, repo
, "origin");
2167 if (error
== GIT_ENOTFOUND
)
2169 GIT_ERROR_SUBMODULE
,
2170 "cannot get default remote for submodule - no local tracking "
2171 "branch for HEAD and origin does not exist");
2176 static int get_url_base(git_buf
*url
, git_repository
*repo
)
2179 git_worktree
*wt
= NULL
;
2180 git_remote
*remote
= NULL
;
2182 if ((error
= lookup_default_remote(&remote
, repo
)) == 0) {
2183 error
= git_buf_sets(url
, git_remote_url(remote
));
2185 } else if (error
!= GIT_ENOTFOUND
)
2190 /* if repository does not have a default remote, use workdir instead */
2191 if (git_repository_is_worktree(repo
)) {
2192 if ((error
= git_worktree_open_from_repository(&wt
, repo
)) < 0)
2194 error
= git_buf_sets(url
, wt
->parent_path
);
2196 error
= git_buf_sets(url
, git_repository_workdir(repo
));
2199 git_remote_free(remote
);
2200 git_worktree_free(wt
);
2205 static void submodule_get_index_status(unsigned int *status
, git_submodule
*sm
)
2207 const git_oid
*head_oid
= git_submodule_head_id(sm
);
2208 const git_oid
*index_oid
= git_submodule_index_id(sm
);
2210 *status
= *status
& ~GIT_SUBMODULE_STATUS__INDEX_FLAGS
;
2214 *status
|= GIT_SUBMODULE_STATUS_INDEX_ADDED
;
2216 else if (!index_oid
)
2217 *status
|= GIT_SUBMODULE_STATUS_INDEX_DELETED
;
2218 else if (!git_oid_equal(head_oid
, index_oid
))
2219 *status
|= GIT_SUBMODULE_STATUS_INDEX_MODIFIED
;
2223 static void submodule_get_wd_status(
2224 unsigned int *status
,
2226 git_repository
*sm_repo
,
2227 git_submodule_ignore_t ign
)
2229 const git_oid
*index_oid
= git_submodule_index_id(sm
);
2230 const git_oid
*wd_oid
=
2231 (sm
->flags
& GIT_SUBMODULE_STATUS__WD_OID_VALID
) ? &sm
->wd_oid
: NULL
;
2232 git_tree
*sm_head
= NULL
;
2233 git_index
*index
= NULL
;
2234 git_diff_options opt
= GIT_DIFF_OPTIONS_INIT
;
2237 *status
= *status
& ~GIT_SUBMODULE_STATUS__WD_FLAGS
;
2241 *status
|= GIT_SUBMODULE_STATUS_WD_ADDED
;
2244 if ((sm
->flags
& GIT_SUBMODULE_STATUS__WD_SCANNED
) != 0 &&
2245 (sm
->flags
& GIT_SUBMODULE_STATUS_IN_WD
) == 0)
2246 *status
|= GIT_SUBMODULE_STATUS_WD_UNINITIALIZED
;
2248 *status
|= GIT_SUBMODULE_STATUS_WD_DELETED
;
2250 else if (!git_oid_equal(index_oid
, wd_oid
))
2251 *status
|= GIT_SUBMODULE_STATUS_WD_MODIFIED
;
2253 /* if we have no repo, then we're done */
2257 /* the diffs below could be optimized with an early termination
2258 * option to the git_diff functions, but for now this is sufficient
2259 * (and certainly no worse that what core git does).
2262 if (ign
== GIT_SUBMODULE_IGNORE_NONE
)
2263 opt
.flags
|= GIT_DIFF_INCLUDE_UNTRACKED
;
2265 (void)git_repository_index__weakptr(&index
, sm_repo
);
2267 /* if we don't have an unborn head, check diff with index */
2268 if (git_repository_head_tree(&sm_head
, sm_repo
) < 0)
2271 /* perform head to index diff on submodule */
2272 if (git_diff_tree_to_index(&diff
, sm_repo
, sm_head
, index
, &opt
) < 0)
2275 if (git_diff_num_deltas(diff
) > 0)
2276 *status
|= GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED
;
2277 git_diff_free(diff
);
2281 git_tree_free(sm_head
);
2284 /* perform index-to-workdir diff on submodule */
2285 if (git_diff_index_to_workdir(&diff
, sm_repo
, index
, &opt
) < 0)
2289 git_diff_num_deltas_of_type(diff
, GIT_DELTA_UNTRACKED
);
2292 *status
|= GIT_SUBMODULE_STATUS_WD_UNTRACKED
;
2294 if (git_diff_num_deltas(diff
) != untracked
)
2295 *status
|= GIT_SUBMODULE_STATUS_WD_WD_MODIFIED
;
2297 git_diff_free(diff
);