fetch: make sure submodule oids are fetched
v5 cover fetch: make sure submodule oids are fetched
This is nearly the same as sent in [1], with one commit message fixed.
[1] https://public-inbox.org/git/[email protected]/
and replaces sb/submodule-recursive-fetch-gets-the-tip.
Thanks,
Stefan
Stefan Beller (9):
sha1-array: provide oid_array_filter
submodule.c: fix indentation
submodule.c: sort changed_submodule_names before searching it submodule.c: move global changed_submodule_names into fetch submodule
struct
submodule.c: do not copy around submodule list
repository: repo_submodule_init to take a submodule struct
submodule: fetch in submodules git directory instead of in worktree
fetch: retry fetching submodules if needed objects were not fetched builtin/fetch: check for submodule updates for non branch fetches
Documentation/technical/api-oid-array.txt | 5 + builtin/fetch.c | 14 +- builtin/grep.c | 17 +- builtin/ls-files.c | 12 +- builtin/submodule--helper.c | 2 +- repository.c | 27 +-- repository.h | 11 +- sha1-array.c | 17 ++ sha1-array.h | 3 + submodule.c | 275 +++++++++++++++++----- t/t5526-fetch-submodules.sh | 23 +- 11 files changed, 311 insertions(+), 95 deletions(-)
Signature · 1 line
2.19.0
PATCH v5 1/9 sha1-array: provide oid_array_filter
--- Documentation/technical/api-oid-array.txt | 5 +++++ sha1-array.c | 17 +++++++++++++++++ sha1-array.h | 3 +++ 3 files changed, 25 insertions(+)
Documentation/technical/api-oid-array.txt +5 -0
@@ -48,6 +48,11 @@ Functions is not sorted, this function has the side effect of sorting it. +`oid_array_filter`:: + Apply the callback function `want` to each entry in the array, + retaining only the entries for which the function returns true. + Preserve the order of the entries that are retained. + Examples --------
sha1-array.c +17 -0
@@ -77,3 +77,20 @@ int oid_array_for_each_unique(struct oid_array *array, }return 0 ; } + +void oid_array_filter (struct oid_array *array, +for_each_oid_fn want, +void *cb_data) +{ +unsigned nr = array->nr, src, dst; +struct object_id *oids = array->oid; + +for (src = dst =0 ; src < nr; src++) { +if (want (&oids[src], cb_data)) { +if (src != dst) +oidcpy (&oids[dst], &oids[src]); + dst++; + } + } + array->nr = dst; +}
sha1-array.h +3 -0
@@ -22,5 +22,8 @@ int oid_array_for_each(struct oid_array *array,int oid_array_for_each_unique (struct oid_array *array,for_each_oid_fn fn,void *data); +void oid_array_filter (struct oid_array *array, +for_each_oid_fn want, +void *cbdata);#endif /* SHA1_ARRAY_H */
Signature · 1 line
2.19.0
PATCH v5 2/9 submodule.c: fix indentation
In reply to Stefan BellerThe submodule subsystem is really bad at staying within 80 characters. Fix it while we are here.
--- submodule.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
submodule.c +6 -3
@@ -1244,7 +1244,8 @@ static int get_next_submodule(struct child_process *cp,if (!submodule) {const char *name =default_name_or_path (ce->name);if (name) { - default_submodule.path = default_submodule.name = name; + default_submodule.path = name; + default_submodule.name = name; submodule = &default_submodule; } }
@@ -1254,8 +1255,10 @@ static int get_next_submodule(struct child_process *cp,default :case RECURSE_SUBMODULES_DEFAULT :case RECURSE_SUBMODULES_ON_DEMAND : -if (!submodule || !unsorted_string_list_lookup (&changed_submodule_names, - submodule->name)) +if (!submodule || + !unsorted_string_list_lookup ( + &changed_submodule_names, + submodule->name))continue ; default_argv ="on-demand" ;break ;
Signature · 1 line
2.19.0
PATCH v5 3/9 submodule.c: sort changed_submodule_names before searching it
In reply to Stefan BellerWe can string_list_insert() to maintain sorted-ness of the list as we find new items, or we can string_list_append() to build an unsorted list and sort it at the end just once.
As we do not rely on the sortedness while building the list, we pick the "append and sort at the end" as it has better worst case execution times.
--- submodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
submodule.c +2 -1
@@ -1256,7 +1256,7 @@ static int get_next_submodule(struct child_process *cp,case RECURSE_SUBMODULES_DEFAULT :case RECURSE_SUBMODULES_ON_DEMAND :if (!submodule || - !unsorted_string_list_lookup ( + !string_list_lookup ( &changed_submodule_names, submodule->name))continue ;
@@ -1350,6 +1350,7 @@ int fetch_populated_submodules(struct repository *r,/* default value, "--submodule-prefix" and its value are added later */ calculate_changed_submodule_paths (); +string_list_sort (&changed_submodule_names); run_processes_parallel(max_parallel_jobs, get_next_submodule, fetch_start_failure,
Signature · 1 line
2.19.0
PATCH v5 4/9 submodule.c: move global changed_submodule_names into fetch submodule struct
In reply to Stefan BellerThe changed_submodule_names are only used for fetching, so let's make it part of the struct that is passed around for fetching submodules.
--- submodule.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-)
submodule.c +23 -19
@@ -25,7 +25,7 @@#include "commit-reach.h" static int config_update_recurse_submodules =RECURSE_SUBMODULES_OFF ; -static struct string_list changed_submodule_names =STRING_LIST_INIT_DUP ; +static int initialized_fetch_ref_tips;static struct oid_array ref_tips_before_fetch;static struct oid_array ref_tips_after_fetch;
@@ -1110,7 +1110,22 @@ void check_for_new_submodule_commits(struct object_id *oid)oid_array_append (&ref_tips_after_fetch, oid); } -static void calculate_changed_submodule_paths (void ) +struct submodule_parallel_fetch { +int count; +struct argv_array args; +struct repository *r; +const char *prefix; +int command_line_option; +int default_option; +int quiet; +int result; + +struct string_list changed_submodule_names; +}; +#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0, STRING_LIST_INIT_DUP } + +static void calculate_changed_submodule_paths ( +struct submodule_parallel_fetch *spf) {struct argv_array argv =ARGV_ARRAY_INIT ;struct string_list changed_submodules =STRING_LIST_INIT_DUP ;
@@ -1148,7 +1163,8 @@ static void calculate_changed_submodule_paths(void)continue ;if (!submodule_has_commits (path, commits)) -string_list_append (&changed_submodule_names, name->string); +string_list_append (&spf->changed_submodule_names, + name->string); }free_submodules_oids (&changed_submodules);
@@ -1185,18 +1201,6 @@ int submodule_touches_in_range(struct object_id *excl_oid,return ret; } -struct submodule_parallel_fetch { -int count; -struct argv_array args; -struct repository *r; -const char *prefix; -int command_line_option; -int default_option; -int quiet; -int result; -}; -#define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0} -static int get_fetch_recurse_config (const struct submodule *submodule,struct submodule_parallel_fetch *spf) {
@@ -1257,7 +1261,7 @@ static int get_next_submodule(struct child_process *cp,case RECURSE_SUBMODULES_ON_DEMAND :if (!submodule || !string_list_lookup ( - &changed_submodule_names, + &spf->changed_submodule_names, submodule->name))continue ; default_argv ="on-demand" ;
@@ -1349,8 +1353,8 @@ int fetch_populated_submodules(struct repository *r,argv_array_push (&spf.args,"--recurse-submodules-default" );/* default value, "--submodule-prefix" and its value are added later */ -calculate_changed_submodule_paths (); -string_list_sort (&changed_submodule_names); +calculate_changed_submodule_paths (&spf); +string_list_sort (&spf.changed_submodule_names); run_processes_parallel(max_parallel_jobs, get_next_submodule, fetch_start_failure,
@@ -1359,7 +1363,7 @@ int fetch_populated_submodules(struct repository *r,argv_array_clear (&spf.args); out: -string_list_clear (&changed_submodule_names,1 ); +string_list_clear (&spf.changed_submodule_names,1 );return spf.result; }
Signature · 1 line
2.19.0
PATCH v5 5/9 submodule.c: do not copy around submodule list
In reply to Stefan Beller'calculate_changed_submodule_paths' uses a local list to compute the changed submodules, and then produces the result by copying appropriate items into the result list.
Instead use the result list directly and prune items afterwards using string_list_remove_empty_items.
By doing so we'll have access to the util pointer for longer that contains the commits that we need to fetch, which will be useful in a later patch.
--- submodule.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
submodule.c +10 -9
@@ -1128,8 +1128,7 @@ static void calculate_changed_submodule_paths( struct submodule_parallel_fetch *spf) {struct argv_array argv =ARGV_ARRAY_INIT ; -struct string_list changed_submodules =STRING_LIST_INIT_DUP ; -const struct string_list_item *name; +struct string_list_item *name;/* No need to check if there are no submodules configured */ if (!submodule_from_path (the_repository,NULL ,NULL ))
@@ -1146,9 +1145,9 @@ static void calculate_changed_submodule_paths(* Collect all submodules (whether checked out or not) for which new * commits have been recorded upstream in "changed_submodule_names". */ -collect_changed_submodules (&changed_submodules, &argv); +collect_changed_submodules (&spf->changed_submodule_names, &argv); -for_each_string_list_item (name, &changed_submodules) { +for_each_string_list_item (name, &spf->changed_submodule_names) {struct oid_array *commits = name->util;const struct submodule *submodule;const char *path =NULL ;
@@ -1162,12 +1161,14 @@ static void calculate_changed_submodule_paths(if (!path)continue ; -if (!submodule_has_commits (path, commits)) -string_list_append (&spf->changed_submodule_names, - name->string); +if (submodule_has_commits (path, commits)) { +oid_array_clear (commits); + *name->string ='\0' ; + } } -free_submodules_oids (&changed_submodules); +string_list_remove_empty_items (&spf->changed_submodule_names,1 ); +argv_array_clear (&argv);oid_array_clear (&ref_tips_before_fetch);oid_array_clear (&ref_tips_after_fetch);
@@ -1363,7 +1364,7 @@ int fetch_populated_submodules(struct repository *r,argv_array_clear (&spf.args); out: -string_list_clear (&spf.changed_submodule_names,1 ); +free_submodules_oids (&spf.changed_submodule_names);return spf.result; }
Signature · 1 line
2.19.0
PATCH v5 6/9 repository: repo_submodule_init to take a submodule struct
In reply to Stefan BellerWhen constructing a struct repository for a submodule for some revision of the superproject where the submodule is not contained in the index, it may not be present in the working tree currently either. In that siutation giving a 'path' argument is not useful. Upgrade the repo_submodule_init function to take a struct submodule instead.
While we are at it, overhaul the repo_submodule_init function by renaming the submodule repository struct, which is to be initialized, to a name that is not confused with the struct submodule as easily.
Also move its documentation into the header file.
--- builtin/grep.c | 17 ++++++++++------- builtin/ls-files.c | 12 +++++++----- builtin/submodule--helper.c | 2 +- repository.c | 27 ++++++++++----------------- repository.h | 11 +++++++++-- 5 files changed, 37 insertions(+), 32 deletions(-)
builtin/grep.c +10 -7
@@ -418,16 +418,19 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,const struct object_id *oid, const char *filename, const char *path) { - struct repository submodule; + struct repository subrepo; +const struct submodule *sub =submodule_from_path (superproject, + &null_oid, path); +int hit;if (!is_submodule_active (superproject, path))return 0 ; -if (repo_submodule_init (&submodule, superproject, path)) +if (repo_submodule_init (&subrepo, superproject, sub))return 0 ; -repo_read_gitmodules (&submodule); +repo_read_gitmodules (&subrepo);/* * NEEDSWORK: This adds the submodule's object directory to the list of
@@ -440,7 +443,7 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,* object. */ grep_read_lock (); -add_to_alternates_memory (submodule.objects->objectdir); +add_to_alternates_memory (subrepo.objects->objectdir);grep_read_unlock ();if (oid) {
@@ -465,14 +468,14 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,init_tree_desc (&tree, data, size); hit =grep_tree (opt, pathspec, &tree, &base, base.len, - object->type ==OBJ_COMMIT , &submodule); + object->type ==OBJ_COMMIT , &subrepo);strbuf_release (&base);free (data); }else { - hit =grep_cache (opt, &submodule, pathspec,1 ); + hit =grep_cache (opt, &subrepo, pathspec,1 ); } -repo_clear (&submodule); +repo_clear (&subrepo);return hit; }
builtin/ls-files.c +7 -5
@@ -206,17 +206,19 @@ static void show_files(struct repository *repo, struct dir_struct *dir);static void show_submodule (struct repository *superproject,struct dir_struct *dir,const char *path) { -struct repository submodule; +struct repository subrepo; +const struct submodule *sub =submodule_from_path (superproject, + &null_oid, path); -if (repo_submodule_init (&submodule, superproject, path)) +if (repo_submodule_init (&subrepo, superproject, sub))return ; -if (repo_read_index (&submodule) <0 ) +if (repo_read_index (&subrepo) <0 )die ("index file corrupt" ); -show_files (&submodule, dir); +show_files (&subrepo, dir); -repo_clear (&submodule); +repo_clear (&subrepo); } static void show_ce(struct repository *repo, struct dir_struct *dir,
builtin/submodule--helper.c +1 -1
@@ -2038,7 +2038,7 @@ static int ensure_core_worktree(int argc, const char **argv, const char *prefix)if (!sub)BUG ("We could get the submodule handle before?" ); -if (repo_submodule_init (&subrepo, the_repository, path)) +if (repo_submodule_init (&subrepo, the_repository, sub))die (_ ("could not get a repository handle for submodule '%s'" ), path);if (!repo_config_get_string (&subrepo,"core.worktree" , &cw)) {
repository.c +10 -17
@@ -166,30 +166,23 @@ int repo_init(struct repository *repo,return -1 ; } -/* -* Initialize 'submodule' as the submodule given by 'path' in parent repository -* 'superproject'. -* Return 0 upon success and a non-zero value upon failure. -*/ -int repo_submodule_init (struct repository *submodule, +int repo_submodule_init (struct repository *subrepo,struct repository *superproject, -const char *path) +const struct submodule *sub) { -const struct submodule *sub;struct strbuf gitdir =STRBUF_INIT ;struct strbuf worktree =STRBUF_INIT ;int ret =0 ; - sub =submodule_from_path (superproject, &null_oid, path);if (!sub) { ret =-1 ; goto out; } -strbuf_repo_worktree_path (&gitdir, superproject,"%s/.git" , path); -strbuf_repo_worktree_path (&worktree, superproject,"%s" , path); +strbuf_repo_worktree_path (&gitdir, superproject,"%s/.git" , sub->path); +strbuf_repo_worktree_path (&worktree, superproject,"%s" , sub->path); -if (repo_init (submodule, gitdir.buf, worktree.buf)) { +if (repo_init (subrepo, gitdir.buf, worktree.buf)) {/* * If initilization fails then it may be due to the submodule * not being populated in the superproject's worktree. Instead
@@ -201,16 +194,16 @@ int repo_submodule_init(struct repository *submodule,strbuf_repo_git_path (&gitdir, superproject,"modules/%s" , sub->name); -if (repo_init (submodule, gitdir.buf,NULL )) { +if (repo_init (subrepo, gitdir.buf,NULL )) { ret =-1 ; goto out; } } - submodule->submodule_prefix =xstrfmt ("%s%s/" , - superproject->submodule_prefix ? - superproject->submodule_prefix : -"" , path); + subrepo->submodule_prefix =xstrfmt ("%s%s/" , + superproject->submodule_prefix ? + superproject->submodule_prefix : +"" , sub->path); out:strbuf_release (&gitdir);
repository.h +9 -2
@@ -116,9 +116,16 @@ void repo_set_worktree(struct repository *repo, const char *path);void repo_set_hash_algo (struct repository *repo,int algo);void initialize_the_repository (void );int repo_init (struct repository *r,const char *gitdir,const char *worktree); -int repo_submodule_init (struct repository *submodule, + +/* +* Initialize the repository 'subrepo' as the submodule given by the +* struct submodule 'sub' in parent repository 'superproject'. +* Return 0 upon success and a non-zero value upon failure. +*/ +struct submodule ; +int repo_submodule_init (struct repository *subrepo,struct repository *superproject, -const char *path); +const struct submodule *sub);void repo_clear (struct repository *repo);/*
Signature · 1 line
2.19.0
PATCH v5 7/9 submodule: fetch in submodules git directory instead of in worktree
In reply to Stefan BellerThis patch started as a refactoring to make 'get_next_submodule' more readable, but upon doing so, I realized that "git fetch" of the submodule actually doesn't need to be run in the submodules worktree. So let's run it in its git dir instead.
That should pave the way towards fetching submodules that are currently not checked out.
This patch leaks the cp->dir in get_next_submodule, as any further callback in run_processes_parallel doesn't have access to the child process any more. In an early iteration of this patch, the function get_submodule_repo_for directly returned the string containing the git directory, which would be a better design choice for this patch.
However the next patch both fixes the memory leak of cp->dir and also has a use case for using the full repository handle of the submodule, so it makes sense to introduce the get_submodule_repo_for here already.
--- submodule.c | 51 +++++++++++++++++++++++++++---------- t/t5526-fetch-submodules.sh | 7 ++++- 2 files changed, 44 insertions(+), 14 deletions(-)
submodule.c +38 -13
@@ -481,6 +481,12 @@ void prepare_submodule_repo_env(struct argv_array *out) DEFAULT_GIT_DIR_ENVIRONMENT); } +static void prepare_submodule_repo_env_in_gitdir (struct argv_array *out) +{ +prepare_submodule_repo_env_no_git_dir (out); +argv_array_pushf (out,"%s=." ,GIT_DIR_ENVIRONMENT ); +} +/* Helper function to display the submodule header line prior to the full * summary output. If it can locate the submodule objects directory it will * attempt to lookup both the left and right commits and put them into the
@@ -1227,6 +1233,29 @@ static int get_fetch_recurse_config(const struct submodule *submodule,return spf->default_option; } +static struct repository *get_submodule_repo_for (struct repository *r, +const struct submodule *sub) +{ +struct repository *ret =xmalloc (sizeof (*ret)); + +if (repo_submodule_init (ret, r, sub)) { +/* +* No entry in .gitmodules? Technically not a submodule, +* but historically we supported repositories that happen to be +* in-place where a gitlink is. Keep supporting them. +*/ +struct strbuf gitdir =STRBUF_INIT ; +strbuf_repo_worktree_path (&gitdir, r,"%s/.git" , sub->path); +if (repo_init (ret, gitdir.buf,NULL )) { +strbuf_release (&gitdir); +return NULL ; + } +strbuf_release (&gitdir); + } + +return ret; +} +static int get_next_submodule (struct child_process *cp,struct strbuf *err,void *data,void **task_cb) {
@@ -1234,12 +1263,11 @@ static int get_next_submodule(struct child_process *cp,struct submodule_parallel_fetch *spf = data;for (; spf->count < spf->r->index->cache_nr; spf->count++) { -struct strbuf submodule_path =STRBUF_INIT ; -struct strbuf submodule_git_dir =STRBUF_INIT ;struct strbuf submodule_prefix =STRBUF_INIT ;const struct cache_entry *ce = spf->r->index->cache[spf->count]; -const char *git_dir, *default_argv; +const char *default_argv;const struct submodule *submodule; +struct repository *repo;struct submodule default_submodule =SUBMODULE_INIT ;if (!S_ISGITLINK (ce->ce_mode))
@@ -1274,16 +1302,12 @@ static int get_next_submodule(struct child_process *cp,continue ; } -strbuf_repo_worktree_path (&submodule_path, spf->r,"%s" , ce->name); -strbuf_addf (&submodule_git_dir,"%s/.git" , submodule_path.buf);strbuf_addf (&submodule_prefix,"%s%s/" , spf->prefix, ce->name); - git_dir =read_gitfile (submodule_git_dir.buf); -if (!git_dir) - git_dir = submodule_git_dir.buf; -if (is_directory (git_dir)) { + repo =get_submodule_repo_for (spf->r, submodule); +if (repo) {child_process_init (cp); - cp->dir =strbuf_detach (&submodule_path,NULL ); -prepare_submodule_repo_env (&cp->env_array); +prepare_submodule_repo_env_in_gitdir (&cp->env_array); + cp->dir =xstrdup (repo->gitdir); cp->git_cmd =1 ;if (!spf->quiet) strbuf_addf(err, "Fetching submodule %s%s\n",
@@ -1293,10 +1317,11 @@ static int get_next_submodule(struct child_process *cp,argv_array_push (&cp->args, default_argv);argv_array_push (&cp->args,"--submodule-prefix" );argv_array_push (&cp->args, submodule_prefix.buf); + +repo_clear (repo); +free (repo); ret =1 ; } -strbuf_release (&submodule_path); -strbuf_release (&submodule_git_dir);strbuf_release (&submodule_prefix);if (ret) { spf->count++;
t/t5526-fetch-submodules.sh +6 -1
@@ -566,7 +566,12 @@ test_expect_success 'fetching submodule into a broken repository' ' test_must_fail git -C dst status && test_must_fail git -C dst diff && - test_must_fail git -C dst fetch --recurse-submodules + + # git-fetch cannot find the git directory of the submodule, + # so it will do nothing, successfully, as it cannot distinguish between + # this broken submodule and a submodule that was just set active but + # not cloned yet + git -C dst fetch --recurse-submodules ' test_expect_success "fetch new commits when submodule got renamed" '
Signature · 1 line
2.19.0
PATCH v5 8/9 fetch: retry fetching submodules if needed objects were not fetched
In reply to Stefan BellerCurrently when git-fetch is asked to recurse into submodules, it dispatches a plain "git-fetch -C <submodule-dir>" (with some submodule related options such as prefix and recusing strategy, but) without any information of the remote or the tip that should be fetched.
This works surprisingly well in some workflows (such as using submodules as a third party library), while not so well in other scenarios, such as in a Gerrit topic-based workflow, that can tie together changes (potentially across repositories) on the server side. One of the parts of such a Gerrit workflow is to download a change when wanting to examine it, and you'd want to have its submodule changes that are in the same topic downloaded as well. However these submodule changes reside in their own repository in their own ref (refs/changes/<int>).
Retry fetching a submodule by object name if the object id that the superproject points to, cannot be found.
This retrying does not happen when the "git fetch" done at the superproject is not storing the fetched results in remote tracking branches (i.e. instead just recording them to FETCH_HEAD) in this step. A later patch will fix this.
builtin/fetch used to only inspect submodules when they were fetched "on-demand", as in either on/off case it was clear whether the submodule needs to be fetched. However to know whether we need to try fetching the object ids, we need to identify the object names, which is done in this function check_for_new_submodule_commits(), so we'll also run that code in case the submodule recursion is set to "on".
--- builtin/fetch.c | 9 +- submodule.c | 185 ++++++++++++++++++++++++++++++------ t/t5526-fetch-submodules.sh | 16 ++++ 3 files changed, 177 insertions(+), 33 deletions(-)
builtin/fetch.c +3 -6
@@ -707,8 +707,7 @@ static int update_local_ref(struct ref *ref, what =_ ("[new ref]" ); } -if ((recurse_submodules !=RECURSE_SUBMODULES_OFF ) && - (recurse_submodules !=RECURSE_SUBMODULES_ON )) +if (recurse_submodules !=RECURSE_SUBMODULES_OFF )check_for_new_submodule_commits (&ref->new_oid); r =s_update_ref (msg, ref,0 ); format_display(display, r ? '!' : '*', what,
@@ -723,8 +722,7 @@ static int update_local_ref(struct ref *ref,strbuf_add_unique_abbrev (&quickref, ¤t->object.oid,DEFAULT_ABBREV );strbuf_addstr (&quickref,".." );strbuf_add_unique_abbrev (&quickref, &ref->new_oid,DEFAULT_ABBREV ); -if ((recurse_submodules !=RECURSE_SUBMODULES_OFF ) && - (recurse_submodules !=RECURSE_SUBMODULES_ON )) +if (recurse_submodules !=RECURSE_SUBMODULES_OFF )check_for_new_submodule_commits (&ref->new_oid); r =s_update_ref ("fast-forward" , ref,1 ); format_display(display, r ? '!' : ' ', quickref.buf,
@@ -738,8 +736,7 @@ static int update_local_ref(struct ref *ref,strbuf_add_unique_abbrev (&quickref, ¤t->object.oid,DEFAULT_ABBREV );strbuf_addstr (&quickref,"..." );strbuf_add_unique_abbrev (&quickref, &ref->new_oid,DEFAULT_ABBREV ); -if ((recurse_submodules !=RECURSE_SUBMODULES_OFF ) && - (recurse_submodules !=RECURSE_SUBMODULES_ON )) +if (recurse_submodules !=RECURSE_SUBMODULES_OFF )check_for_new_submodule_commits (&ref->new_oid); r =s_update_ref ("forced-update" , ref,1 ); format_display(display, r ? '!' : '+', quickref.buf,
submodule.c +158 -27
261 lines not on this page · raw message
t/t5526-fetch-submodules.sh +16 -0
@@ -605,4 +605,20 @@ test_expect_success "fetch new commits when submodule got renamed" ' test_cmp expect actual ' +test_expect_success "fetch new commits on-demand when they are not reachable" ' + git checkout --detach && + C=$(git -C submodule commit-tree -m "new change outside refs/heads" HEAD^{tree}) && + git -C submodule update-ref refs/changes/1 $C && + git update-index --cacheinfo 160000 $C submodule && + git commit -m "updated submodule outside of refs/heads" && + D=$(git rev-parse HEAD) && + git update-ref refs/changes/2 $D && + ( + cd downstream && + git fetch --recurse-submodules --recurse-submodules-default on-demand origin refs/changes/2:refs/heads/my_branch && + git -C submodule cat-file -t $C && + git checkout --recurse-submodules FETCH_HEAD + ) +' + test_done
Signature · 1 line
2.19.0
PATCH v5 9/9 builtin/fetch: check for submodule updates for non branch fetches
In reply to Stefan BellerGerrit, the code review tool, has a different workflow than our mailing list based approach. Usually users upload changes to a Gerrit server and continuous integration and testing happens by bots. Sometimes however a user wants to checkout a change locally and look at it locally. For this use case, Gerrit offers a command line snippet to copy and paste to your terminal, which looks like
git fetch https://<host>/gerrit refs/changes/<id> && git checkout FETCH_HEAD
For Gerrit changes that contain changing submodule gitlinks, it would be easy to extend both the fetch and checkout with the '--recurse-submodules' flag, such that this command line snippet would produce the state of a change locally.
However the functionality added in the previous patch, which would ensure that we fetch the objects in the submodule that the gitlink pointed at, only works for remote tracking branches so far, not for FETCH_HEAD.
Make sure that fetching a superproject to its FETCH_HEAD, also respects the existence checks for objects in the submodule recursion.
--- builtin/fetch.c | 5 ++++- t/t5526-fetch-submodules.sh | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-)
builtin/fetch.c +4 -1
@@ -894,11 +894,14 @@ static int store_updated_refs(const char *raw_url, const char *remote_name, rc |=update_local_ref (ref, what, rm, ¬e, summary_width);free (ref); - }else + }else { +check_for_new_submodule_commits (&rm->old_oid);format_display (¬e,'*' , *kind ? kind :"branch" ,NULL , *what ? what :"HEAD" ,"FETCH_HEAD" , summary_width); + } +if (note.len) {if (verbosity >=0 && !shown_url) { fprintf(stderr, _("From %.*s\n"),
t/t5526-fetch-submodules.sh +1 -1
@@ -615,7 +615,7 @@ test_expect_success "fetch new commits on-demand when they are not reachable" ' git update-ref refs/changes/2 $D && ( cd downstream && - git fetch --recurse-submodules --recurse-submodules-default on-demand origin refs/changes/2:refs/heads/my_branch && + git fetch --recurse-submodules origin refs/changes/2 && git -C submodule cat-file -t $C && git checkout --recurse-submodules FETCH_HEAD )
Signature · 1 line
2.19.0