Skip to content

Commit c16c3e4

Browse files
jlehmanngitster
authored andcommitted
fetch/pull: Don't recurse into a submodule when commits are already present
When looking for submodules where new commits have been recorded in the superproject ignore those cases where the submodules commits are already present locally. This can happen e.g. when the submodule has been rewound to an earlier state. Then there is no need to fetch the submodule again as the commit recorded in the newly fetched superproject commit has already been fetched earlier into the submodule. Signed-off-by: Jens Lehmann <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bf42b38 commit c16c3e4

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

Documentation/fetch-options.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ ifndef::git-pull[]
7373
'yes', which is the default when this option is used without any
7474
value. Use 'on-demand' to only recurse into a populated submodule
7575
when the superproject retrieves a commit that updates the submodule's
76-
reference.
76+
reference to a commit that isn't already in the local submodule
77+
clone.
7778

7879
--no-recurse-submodules::
7980
Disable recursive fetching of submodules (this has the same effect as

submodule.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,33 @@ void set_config_fetch_recurse_submodules(int value)
263263
config_fetch_recurse_submodules = value;
264264
}
265265

266+
static int is_submodule_commit_present(const char *path, unsigned char sha1[20])
267+
{
268+
int is_present = 0;
269+
if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) {
270+
/* Even if the submodule is checked out and the commit is
271+
* present, make sure it is reachable from a ref. */
272+
struct child_process cp;
273+
const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL};
274+
struct strbuf buf = STRBUF_INIT;
275+
276+
argv[3] = sha1_to_hex(sha1);
277+
memset(&cp, 0, sizeof(cp));
278+
cp.argv = argv;
279+
cp.env = local_repo_env;
280+
cp.git_cmd = 1;
281+
cp.no_stdin = 1;
282+
cp.out = -1;
283+
cp.dir = path;
284+
if (!run_command(&cp) && !strbuf_read(&buf, cp.out, 1024))
285+
is_present = 1;
286+
287+
close(cp.out);
288+
strbuf_release(&buf);
289+
}
290+
return is_present;
291+
}
292+
266293
static void submodule_collect_changed_cb(struct diff_queue_struct *q,
267294
struct diff_options *options,
268295
void *data)
@@ -280,7 +307,7 @@ static void submodule_collect_changed_cb(struct diff_queue_struct *q,
280307
* being moved around. */
281308
struct string_list_item *path;
282309
path = unsorted_string_list_lookup(&changed_submodule_paths, p->two->path);
283-
if (!path)
310+
if (!path && !is_submodule_commit_present(p->two->path, p->two->sha1))
284311
string_list_append(&changed_submodule_paths, xstrdup(p->two->path));
285312
} else {
286313
/* Submodule is new or was moved here */

t/t5526-fetch-submodules.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,4 +428,23 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override
428428
test_cmp expect.err.2 actual.err
429429
'
430430

431+
test_expect_success "don't fetch submodule when newly recorded commits are already present" '
432+
(
433+
cd submodule &&
434+
git checkout -q HEAD^^
435+
) &&
436+
head1=$(git rev-parse --short HEAD) &&
437+
git add submodule &&
438+
git commit -m "submodule rewound" &&
439+
head2=$(git rev-parse --short HEAD) &&
440+
echo "From $pwd/." > expect.err &&
441+
echo " $head1..$head2 master -> origin/master" >> expect.err &&
442+
(
443+
cd downstream &&
444+
git fetch >../actual.out 2>../actual.err
445+
) &&
446+
! test -s actual.out &&
447+
test_cmp expect.err actual.err
448+
'
449+
431450
test_done

0 commit comments

Comments
 (0)