From 88a21979c5717e3f37b9691e90b6dbf2b94c751a Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 6 Mar 2011 23:10:46 +0100 Subject: fetch/pull: recurse into submodules when necessary To be able to access all commits of populated submodules referenced by the superproject it is sufficient to only then let "git fetch" recurse into a submodule when the new commits fetched in the superproject record new commits for it. Having these commits present is extremely useful when using the "--submodule" option to "git diff" (which is what "git gui" and "gitk" do since 1.6.6), as all submodule commits needed for creating a descriptive output can be accessed. Also merging submodule commits (added in 1.7.3) depends on the submodule commits in question being present to work. Last but not least this enables disconnected operation when using submodules, as all commits necessary for a successful "git submodule update -N" will have been fetched automatically. So we choose this mode as the default for fetch and pull. Before a new or changed ref from upstream is updated in update_local_ref() "git rev-list --not --branches --remotes" is used to determine all newly fetched commits. These are then walked and diffed against their parent(s) to see if a submodule has been changed. If that is the case, its path is stored to be fetched after the superproject fetch is completed. Using the "--recurse-submodules" or the "--no-recurse-submodules" option disables the examination of the fetched refs because the result will be ignored anyway. There is currently no infrastructure for storing deleted and new submodules in the .git directory of the superproject. That's why fetch and pull for now only fetch submodules that are already checked out and are not renamed. In t7403 the "--no-recurse-submodules" argument had to be added to "git pull" to avoid failure because of the moved upstream submodule repo. Thanks-to: Jonathan Nieder Thanks-to: Heiko Voigt Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- t/t5526-fetch-submodules.sh | 109 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) (limited to 't/t5526-fetch-submodules.sh') diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index a5f458533..6d92f7a5a 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -192,4 +192,113 @@ test_expect_success "--no-recurse-submodules overrides config setting" ' ! test -s actual.err ' +test_expect_success "Recursion doesn't happen when no new commits are fetched in the superproject" ' + ( + cd downstream && + ( + cd submodule && + git config --unset fetch.recurseSubmodules + ) && + git config --unset fetch.recurseSubmodules + git fetch >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "Recursion stops when no new submodule commits are fetched" ' + head1=$(git rev-parse --short HEAD) && + git add submodule && + git commit -m "new submodule" && + head2=$(git rev-parse --short HEAD) && + echo "Fetching submodule submodule" > expect.out.sub && + echo "From $pwd/." > expect.err.sub && + echo " $head1..$head2 master -> origin/master" >> expect.err.sub + head -2 expect.err >> expect.err.sub && + ( + cd downstream && + git fetch >../actual.out 2>../actual.err + ) && + test_cmp expect.err.sub actual.err && + test_cmp expect.out.sub actual.out +' + +test_expect_success "Recursion doesn't happen when new superproject commits don't change any submodules" ' + add_upstream_commit && + head1=$(git rev-parse --short HEAD) && + echo a > file && + git add file && + git commit -m "new file" && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/." > expect.err.file && + echo " $head1..$head2 master -> origin/master" >> expect.err.file && + ( + cd downstream && + git fetch >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + test_cmp expect.err.file actual.err +' + +test_expect_success "Recursion picks up config in submodule" ' + ( + cd downstream && + git fetch --recurse-submodules && + ( + cd submodule && + git config fetch.recurseSubmodules true + ) + ) && + add_upstream_commit && + head1=$(git rev-parse --short HEAD) && + git add submodule && + git commit -m "new submodule" && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/." > expect.err.sub && + echo " $head1..$head2 master -> origin/master" >> expect.err.sub && + cat expect.err >> expect.err.sub && + ( + cd downstream && + git fetch >../actual.out 2>../actual.err && + ( + cd submodule && + git config --unset fetch.recurseSubmodules + ) + ) && + test_cmp expect.err.sub actual.err && + test_cmp expect.out actual.out +' + +test_expect_success "Recursion picks up all submodules when necessary" ' + add_upstream_commit && + ( + cd submodule && + ( + cd deepsubmodule && + git fetch && + git checkout -q FETCH_HEAD + ) && + head1=$(git rev-parse --short HEAD^) && + git add deepsubmodule && + git commit -m "new deepsubmodule" + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/submodule" > ../expect.err.sub && + echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub + ) && + head1=$(git rev-parse --short HEAD) && + git add submodule && + git commit -m "new submodule" && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/." > expect.err.2 && + echo " $head1..$head2 master -> origin/master" >> expect.err.2 && + cat expect.err.sub >> expect.err.2 && + tail -2 expect.err >> expect.err.2 && + ( + cd downstream && + git fetch >../actual.out 2>../actual.err + ) && + test_cmp expect.err.2 actual.err && + test_cmp expect.out actual.out +' + test_done -- cgit v1.2.1 From 8f0700dd33f63e594b9b34c84efe94e670ea4f45 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 6 Mar 2011 23:11:21 +0100 Subject: fetch/pull: Add the 'on-demand' value to the --recurse-submodules option Until now the --recurse-submodules option could only be used to either fetch all populated submodules recursively or to disable recursion completely. As fetch and pull now by default just fetch those submodules for which new commits have been fetched in the superproject, a command line option to enforce that behavior is needed to be able to override configuration settings. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- t/t5526-fetch-submodules.sh | 71 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 't/t5526-fetch-submodules.sh') diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 6d92f7a5a..4cd723c9e 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -301,4 +301,75 @@ test_expect_success "Recursion picks up all submodules when necessary" ' test_cmp expect.out actual.out ' +test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" ' + add_upstream_commit && + ( + cd submodule && + ( + cd deepsubmodule && + git fetch && + git checkout -q FETCH_HEAD + ) && + head1=$(git rev-parse --short HEAD^) && + git add deepsubmodule && + git commit -m "new deepsubmodule" + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/submodule" > ../expect.err.sub && + echo " $head1..$head2 master -> origin/master" >> ../expect.err.sub + ) && + ( + cd downstream && + git config fetch.recurseSubmodules true && + git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err && + git config --unset fetch.recurseSubmodules + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" ' + head1=$(git rev-parse --short HEAD) && + git add submodule && + git commit -m "new submodule" && + head2=$(git rev-parse --short HEAD) && + tail -2 expect.err > expect.err.deepsub && + echo "From $pwd/." > expect.err && + echo " $head1..$head2 master -> origin/master" >> expect.err + cat expect.err.sub >> expect.err && + cat expect.err.deepsub >> expect.err && + ( + cd downstream && + git config fetch.recurseSubmodules false && + ( + cd submodule && + git config -f .gitmodules submodule.deepsubmodule.fetchRecursive false + ) && + git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err && + git config --unset fetch.recurseSubmodules + ( + cd submodule && + git config --unset -f .gitmodules submodule.deepsubmodule.fetchRecursive + ) + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" ' + add_upstream_commit && + head1=$(git rev-parse --short HEAD) && + echo a >> file && + git add file && + git commit -m "new file" && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/." > expect.err.file && + echo " $head1..$head2 master -> origin/master" >> expect.err.file && + ( + cd downstream && + git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + test_cmp expect.err.file actual.err +' + test_done -- cgit v1.2.1 From 1fb2550202d6f88d90121624c1fac0b81ff8c33f Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 6 Mar 2011 23:11:48 +0100 Subject: config: teach the fetch.recurseSubmodules option the 'on-demand' value To enable the user to change the default behavior of "git fetch" and "git pull" regarding submodule recursion add the new "on-demand" value which has just been added to the "--recurse-submodules" command line option. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- t/t5526-fetch-submodules.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 't/t5526-fetch-submodules.sh') diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 4cd723c9e..e6d873a48 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -372,4 +372,32 @@ test_expect_success "'--recurse-submodules=on-demand' stops when no new submodul test_cmp expect.err.file actual.err ' +test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config" ' + ( + cd downstream && + git fetch --recurse-submodules + ) && + add_upstream_commit && + git config --global fetch.recurseSubmodules false && + head1=$(git rev-parse --short HEAD) && + git add submodule && + git commit -m "new submodule" && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/." > expect.err.2 && + echo " $head1..$head2 master -> origin/master" >> expect.err.2 + head -2 expect.err >> expect.err.2 && + ( + cd downstream && + git config fetch.recurseSubmodules on-demand && + git fetch >../actual.out 2>../actual.err + ) && + git config --global --unset fetch.recurseSubmodules && + ( + cd downstream && + git config --unset fetch.recurseSubmodules + ) && + test_cmp expect.out.sub actual.out && + test_cmp expect.err.2 actual.err +' + test_done -- cgit v1.2.1 From bf42b384058ee2b34f587426d0788353ffa9012a Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 6 Mar 2011 23:12:19 +0100 Subject: Submodules: Add 'on-demand' value for the 'fetchRecurseSubmodule' option Now the behavior of fetch and pull can be configured to the recently added 'on-demand' mode separately for each submodule too. Signed-off-by: Jens Lehmann Signed-off-by: Junio C Hamano --- t/t5526-fetch-submodules.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 't/t5526-fetch-submodules.sh') diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index e6d873a48..09701aa1a 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -400,4 +400,32 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config test_cmp expect.err.2 actual.err ' +test_expect_success "'submodule..fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" ' + ( + cd downstream && + git fetch --recurse-submodules + ) && + add_upstream_commit && + git config fetch.recurseSubmodules false && + head1=$(git rev-parse --short HEAD) && + git add submodule && + git commit -m "new submodule" && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/." > expect.err.2 && + echo " $head1..$head2 master -> origin/master" >> expect.err.2 + head -2 expect.err >> expect.err.2 && + ( + cd downstream && + git config submodule.submodule.fetchRecurseSubmodules on-demand && + git fetch >../actual.out 2>../actual.err + ) && + git config --unset fetch.recurseSubmodules && + ( + cd downstream && + git config --unset submodule.submodule.fetchRecurseSubmodules + ) && + test_cmp expect.out.sub actual.out && + test_cmp expect.err.2 actual.err +' + test_done -- cgit v1.2.1 From c16c3e40b5908ecf28be12b1caf266c7ab8de3c6 Mon Sep 17 00:00:00 2001 From: Jens Lehmann Date: Sun, 6 Mar 2011 23:12:58 +0100 Subject: 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 Signed-off-by: Junio C Hamano --- t/t5526-fetch-submodules.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 't/t5526-fetch-submodules.sh') diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index 09701aa1a..3decfae6e 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -428,4 +428,23 @@ test_expect_success "'submodule..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 -- cgit v1.2.1