serialize collection of changed submodules
To check whether a submodule needs to be pushed we need to collect all changed submodules. Lets collect them first and then execute the possibly expensive test whether certain revisions are already pushed only once per submodule. There is further potential for optimization since we can assemble one command and only issued that instead of one call for each remote ref in the submodule. Signed-off-by: Heiko Voigt <hvoigt@hvoigt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Heiko Voigt committed
Nov 16, 2016 at 16:11 UTC
147394470c4be34038e520e74a017da6a3745e90
1 file changed
+55
-4
submodule.c
+55
-4
@@ -554,19 +554,34 @@ static int submodule_needs_pushing(const char *path, const unsigned char sha1[20
554
return 0;
555
}
556
557
+static struct sha1_array *submodule_commits(struct string_list *submodules,
558
+ const char *path)
559
+{
560
+ struct string_list_item *item;
561
+
562
+ item = string_list_insert(submodules, path);
563
+ if (item->util)
564
+ return (struct sha1_array *) item->util;
565
+
566
+ /* NEEDSWORK: should we have sha1_array_init()? */
567
+ item->util = xcalloc(1, sizeof(struct sha1_array));
568
+ return (struct sha1_array *) item->util;
569
+}
570
+
571
static void collect_submodules_from_diff(struct diff_queue_struct *q,
572
struct diff_options *options,
573
void *data)
574
{
575
int i;
562
- struct string_list *needs_pushing = data;
576
+ struct string_list *submodules = data;
577
578
for (i = 0; i < q->nr; i++) {
579
struct diff_filepair *p = q->queue[i];
580
+ struct sha1_array *commits;
581
if (!S_ISGITLINK(p->two->mode))
582
continue;
568
- if (submodule_needs_pushing(p->two->path, p->two->oid.hash))
569
- string_list_insert(needs_pushing, p->two->path);
583
+ commits = submodule_commits(submodules, p->two->path);
584
+ sha1_array_append(commits, p->two->oid.hash);
585
}
586
}
587
@@ -582,6 +597,30 @@ static void find_unpushed_submodule_commits(struct commit *commit,
597
diff_tree_combined_merge(commit, 1, &rev);
598
}
599
600
+struct collect_submodule_from_sha1s_data {
601
+ char *submodule_path;
602
+ struct string_list *needs_pushing;
603
+};
604
+
605
+static int collect_submodules_from_sha1s(const unsigned char sha1[20],
606
+ void *data)
607
+{
608
+ struct collect_submodule_from_sha1s_data *me = data;
609
+
610
+ if (submodule_needs_pushing(me->submodule_path, sha1))
611
+ string_list_insert(me->needs_pushing, me->submodule_path);
612
+
613
+ return 0;
614
+}
615
+
616
+static void free_submodules_sha1s(struct string_list *submodules)
617
+{
618
+ struct string_list_item *item;
619
+ for_each_string_list_item(item, submodules)
620
+ sha1_array_clear((struct sha1_array *) item->util);
621
+ string_list_clear(submodules, 1);
622
+}
623
+
624
int find_unpushed_submodules(unsigned char new_sha1[20],
625
const char *remotes_name, struct string_list *needs_pushing)
626
{
@@ -590,6 +629,8 @@ int find_unpushed_submodules(unsigned char new_sha1[20],
629
const char *argv[] = {NULL, NULL, "--not", "NULL", NULL};
630
int argc = ARRAY_SIZE(argv) - 1;
631
char *sha1_copy;
632
+ struct string_list submodules = STRING_LIST_INIT_DUP;
633
+ struct string_list_item *submodule;
634
635
struct strbuf remotes_arg = STRBUF_INIT;
636
@@ -603,12 +644,22 @@ int find_unpushed_submodules(unsigned char new_sha1[20],
644
die("revision walk setup failed");
645
646
while ((commit = get_revision(&rev)) != NULL)
606
- find_unpushed_submodule_commits(commit, needs_pushing);
647
+ find_unpushed_submodule_commits(commit, &submodules);
648
649
reset_revision_walk();
650
free(sha1_copy);
651
strbuf_release(&remotes_arg);
652
653
+ for_each_string_list_item(submodule, &submodules) {
654
+ struct collect_submodule_from_sha1s_data data;
655
+ data.submodule_path = submodule->string;
656
+ data.needs_pushing = needs_pushing;
657
+ sha1_array_for_each_unique((struct sha1_array *) submodule->util,
658
+ collect_submodules_from_sha1s,
659
+ &data);
660
+ }
661
+ free_submodules_sha1s(&submodules);
662
+
663
return needs_pushing->nr;
664
}
665