Skip to content

Commit

Permalink
fetch/pull: Don't recurse into a submodule when commits are already p…
Browse files Browse the repository at this point in the history
…resent

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 <Jens.Lehmann@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jens Lehmann authored and Junio C Hamano committed Mar 9, 2011
1 parent bf42b38 commit c16c3e4
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 2 deletions.
3 changes: 2 additions & 1 deletion Documentation/fetch-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ ifndef::git-pull[]
'yes', which is the default when this option is used without any
value. Use 'on-demand' to only recurse into a populated submodule
when the superproject retrieves a commit that updates the submodule's
reference.
reference to a commit that isn't already in the local submodule
clone.

--no-recurse-submodules::
Disable recursive fetching of submodules (this has the same effect as
Expand Down
29 changes: 28 additions & 1 deletion submodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,33 @@ void set_config_fetch_recurse_submodules(int value)
config_fetch_recurse_submodules = value;
}

static int is_submodule_commit_present(const char *path, unsigned char sha1[20])
{
int is_present = 0;
if (!add_submodule_odb(path) && lookup_commit_reference(sha1)) {
/* Even if the submodule is checked out and the commit is
* present, make sure it is reachable from a ref. */
struct child_process cp;
const char *argv[] = {"rev-list", "-n", "1", NULL, "--not", "--all", NULL};
struct strbuf buf = STRBUF_INIT;

argv[3] = sha1_to_hex(sha1);
memset(&cp, 0, sizeof(cp));
cp.argv = argv;
cp.env = local_repo_env;
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.out = -1;
cp.dir = path;
if (!run_command(&cp) && !strbuf_read(&buf, cp.out, 1024))
is_present = 1;

close(cp.out);
strbuf_release(&buf);
}
return is_present;
}

static void submodule_collect_changed_cb(struct diff_queue_struct *q,
struct diff_options *options,
void *data)
Expand All @@ -280,7 +307,7 @@ static void submodule_collect_changed_cb(struct diff_queue_struct *q,
* being moved around. */
struct string_list_item *path;
path = unsorted_string_list_lookup(&changed_submodule_paths, p->two->path);
if (!path)
if (!path && !is_submodule_commit_present(p->two->path, p->two->sha1))
string_list_append(&changed_submodule_paths, xstrdup(p->two->path));
} else {
/* Submodule is new or was moved here */
Expand Down
19 changes: 19 additions & 0 deletions t/t5526-fetch-submodules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -428,4 +428,23 @@ test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' override
test_cmp expect.err.2 actual.err
'

test_expect_success "don't fetch submodule when newly recorded commits are already present" '
(
cd submodule &&
git checkout -q HEAD^^
) &&
head1=$(git rev-parse --short HEAD) &&
git add submodule &&
git commit -m "submodule rewound" &&
head2=$(git rev-parse --short HEAD) &&
echo "From $pwd/." > expect.err &&
echo " $head1..$head2 master -> origin/master" >> expect.err &&
(
cd downstream &&
git fetch >../actual.out 2>../actual.err
) &&
! test -s actual.out &&
test_cmp expect.err actual.err
'

test_done

0 comments on commit c16c3e4

Please sign in to comment.