Skip to content

Commit 6be70d6

Browse files
committed
Merge branch 'jk/maint-fetch-submodule-check-fix'
* jk/maint-fetch-submodule-check-fix: fetch: avoid quadratic loop checking for updated submodules
2 parents c4800a3 + 6859de4 commit 6be70d6

File tree

1 file changed

+72
-5
lines changed

1 file changed

+72
-5
lines changed

submodule.c

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88
#include "diffcore.h"
99
#include "refs.h"
1010
#include "string-list.h"
11+
#include "sha1-array.h"
1112

1213
static struct string_list config_name_for_path;
1314
static struct string_list config_fetch_recurse_submodules_for_name;
1415
static struct string_list config_ignore_for_name;
1516
static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
1617
static struct string_list changed_submodule_paths;
18+
static int initialized_fetch_ref_tips;
19+
static struct sha1_array ref_tips_before_fetch;
20+
static struct sha1_array ref_tips_after_fetch;
21+
1722
/*
1823
* The following flag is set if the .gitmodules file is unmerged. We then
1924
* disable recursion for all submodules where .git/config doesn't have a
@@ -474,20 +479,76 @@ static void submodule_collect_changed_cb(struct diff_queue_struct *q,
474479
}
475480
}
476481

482+
static int add_sha1_to_array(const char *ref, const unsigned char *sha1,
483+
int flags, void *data)
484+
{
485+
sha1_array_append(data, sha1);
486+
return 0;
487+
}
488+
477489
void check_for_new_submodule_commits(unsigned char new_sha1[20])
490+
{
491+
if (!initialized_fetch_ref_tips) {
492+
for_each_ref(add_sha1_to_array, &ref_tips_before_fetch);
493+
initialized_fetch_ref_tips = 1;
494+
}
495+
496+
sha1_array_append(&ref_tips_after_fetch, new_sha1);
497+
}
498+
499+
struct argv_array {
500+
const char **argv;
501+
unsigned int argc;
502+
unsigned int alloc;
503+
};
504+
505+
static void init_argv(struct argv_array *array)
506+
{
507+
array->argv = NULL;
508+
array->argc = 0;
509+
array->alloc = 0;
510+
}
511+
512+
static void push_argv(struct argv_array *array, const char *value)
513+
{
514+
ALLOC_GROW(array->argv, array->argc + 2, array->alloc);
515+
array->argv[array->argc++] = xstrdup(value);
516+
array->argv[array->argc] = NULL;
517+
}
518+
519+
static void clear_argv(struct argv_array *array)
520+
{
521+
int i;
522+
for (i = 0; i < array->argc; i++)
523+
free((char **)array->argv[i]);
524+
free(array->argv);
525+
init_argv(array);
526+
}
527+
528+
static void add_sha1_to_argv(const unsigned char sha1[20], void *data)
529+
{
530+
push_argv(data, sha1_to_hex(sha1));
531+
}
532+
533+
static void calculate_changed_submodule_paths(void)
478534
{
479535
struct rev_info rev;
480536
struct commit *commit;
481-
const char *argv[] = {NULL, NULL, "--not", "--all", NULL};
482-
int argc = ARRAY_SIZE(argv) - 1;
537+
struct argv_array argv;
483538

484539
/* No need to check if there are no submodules configured */
485540
if (!config_name_for_path.nr)
486541
return;
487542

488543
init_revisions(&rev, NULL);
489-
argv[1] = xstrdup(sha1_to_hex(new_sha1));
490-
setup_revisions(argc, argv, &rev, NULL);
544+
init_argv(&argv);
545+
push_argv(&argv, "--"); /* argv[0] program name */
546+
sha1_array_for_each_unique(&ref_tips_after_fetch,
547+
add_sha1_to_argv, &argv);
548+
push_argv(&argv, "--not");
549+
sha1_array_for_each_unique(&ref_tips_before_fetch,
550+
add_sha1_to_argv, &argv);
551+
setup_revisions(argv.argc, argv.argv, &rev, NULL);
491552
if (prepare_revision_walk(&rev))
492553
die("revision walk setup failed");
493554

@@ -511,7 +572,11 @@ void check_for_new_submodule_commits(unsigned char new_sha1[20])
511572
parent = parent->next;
512573
}
513574
}
514-
free((char *)argv[1]);
575+
576+
clear_argv(&argv);
577+
sha1_array_clear(&ref_tips_before_fetch);
578+
sha1_array_clear(&ref_tips_after_fetch);
579+
initialized_fetch_ref_tips = 0;
515580
}
516581

517582
int fetch_populated_submodules(int num_options, const char **options,
@@ -545,6 +610,8 @@ int fetch_populated_submodules(int num_options, const char **options,
545610
cp.git_cmd = 1;
546611
cp.no_stdin = 1;
547612

613+
calculate_changed_submodule_paths();
614+
548615
for (i = 0; i < active_nr; i++) {
549616
struct strbuf submodule_path = STRBUF_INIT;
550617
struct strbuf submodule_git_dir = STRBUF_INIT;

0 commit comments

Comments
 (0)