From: Fredrik Gustafsson <hidden> Date: 2016-06-15 22:51:27
This series adds support to submodule update to continue if some
submodules fail to do so.
This is the third iteration of this patch series.
The first can be found on:
http://thread.gmane.org/gmane.comp.version-control.git/171895
The second can be found on:
http://thread.gmane.org/gmane.comp.version-control.git/173629
Fredrik Gustafsson (2):
Add new function die_with_status
submodule update: continue when a checkout fails
git-sh-setup.sh | 12 +++-
git-submodule.sh | 48 +++++++++++++--
t/t7406-submodule-update.sh | 144 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 196 insertions(+), 8 deletions(-)
--
1.7.6.rc0.14.g4fc55
From: Fredrik Gustafsson <hidden> Date: 2016-06-15 22:51:27
This function takes the exit code as a parameter.
This allows scripts to control the exit code when they need to die.
Make the old die-function to use die_with_status for simpler
maintenance.
die no longer prints empty die messages, this is a changed behavior.
Signed-off-by: Fredrik Gustafsson <redacted>
Mentored-by: Jens Lehmann [off-list ref]
Mentored-by: Heiko Voigt [off-list ref]
---
git-sh-setup.sh | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
From: Fredrik Gustafsson <hidden> Date: 2016-06-15 22:51:27
"git submodule update" stops at the first error and gives control
back to the user. Only after the user fixes the problematic
submodule and runs "git submodule update" again, the second error
is found. And the user needs to repeat until all the problems are
found and fixed one by one. This is tedious.
Instead, the command can remember which submodules it had trouble with,
continue updating the ones it can, and report which ones had errors at
the end. The user can run "git submodule update", find all the ones that
need minor fixing (e.g. working tree was dirty) to fix them in a single
pass. Then another "git submodule update" can be run to update all.
Note that the problematic submodules are skipped only when they are to
be integrated with a safer value of submodule.<name>.update option,
namely "checkout". Fixing a failure in a submodule that uses "rebase" or
"merge" may need an involved conflict resolution by the user, and
leaving too many submodules in states that need resolution would not
reduce the mental burden on the user.
Signed-off-by: Fredrik Gustafsson <redacted>
Mentored-by: Jens Lehmann [off-list ref]
Mentored-by: Heiko Voigt [off-list ref]
---
git-submodule.sh | 48 +++++++++++++--
t/t7406-submodule-update.sh | 144 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 186 insertions(+), 6 deletions(-)
@@ -525,17 +526,52 @@ cmd_update();;esac-(clear_local_git_env;cd"$path"&&$command"$sha1")||-die"Unable to $action '$sha1' in submodule path '$path'"-say"Submodule path '$path': $msg '$sha1'"+if(clear_local_git_env;cd"$path"&&$command"$sha1")+then+say"Submodule path '$path': $msg '$sha1'"+else+case$actionin+rebase|merge)+die_with_status2"Unable to $action '$sha1' in submodule path '$path'"+;;+*)+err="${err} \"Failed to $action in submodule path '$path'\""+continue+;;+esac+fifiiftest-n"$recursive"then-(clear_local_git_env;cd"$path"&&evalcmd_update"$orig_flags")||-die"Failed to recurse into submodule path '$path'"+(clear_local_git_env;cd"$path"&&evalcmd_update"$orig_flags")+res=$?+iftest$res-gt0+then+iftest$res-eq1+then+err="${err} \"Failed to recurse into submodule path '$path'\""+continue+else+die_with_status$res"Failed to recurse into submodule path '$path'"+fi+fifidone++iftest-n"$err"+then+OIFS=$IFS+IFS=';'+forein$err+do+echo$e+done+IFS=$OIFS+die+fi++}} set_name_rev(){
@@ -298,4 +298,148 @@ test_expect_success 'submodule update ignores update=rebase config for new submo)'+test_expect_success'submodule update continues after checkout error''+(cdsuper&&+gitreset--hardHEAD&&+gitsubmoduleadd../submodulesubmodule2&&+gitsubmoduleinit&&+gitcommit-am"new_submodule"&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect+)&&+(cdsubmodule&&+test_commit"update_submodule"file+)&&+(cdsubmodule2&&+test_commit"update_submodule2"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"two_new_submodule_commits"&&+(cdsubmodule&&+echo"">file+)&&+gitcheckoutHEAD^&&+test_must_failgitsubmoduleupdate&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+'+test_expect_success'submodule update continues after recursive checkout error''+(cdsuper&&+gitreset--hardHEAD&&+gitcheckoutmaster&&+gitsubmoduleupdate&&+(cdsubmodule&&+gitsubmoduleadd../submodulesubsubmodule&&+gitsubmoduleinit&&+gitcommit-m"new_subsubmodule"+)&&+gitaddsubmodule&&+gitcommit-m"update_submodule"&&+(cdsubmodule&&+(cdsubsubmodule&&+test_commit"update_subsubmodule"file+)&&+gitaddsubsubmodule&&+test_commit"update_submodule_again"file&&+(cdsubsubmodule&&+test_commit"update_subsubmodule_again"file+)&&+test_commit"update_submodule_again_again"file+)&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect&&+test_commit"update_submodule2_again"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"new_commits"&&+gitcheckoutHEAD^&&+(cdsubmodule&&+gitcheckoutHEAD^&&+(cdsubsubmodule&&+echo"">file+)+)&&+test_must_failgitsubmoduleupdate--recursive&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+'++test_expect_success'submodule update exit immediately in case of merge conflict''+(cdsuper&&+gitcheckoutmaster&&+gitreset--hardHEAD&&+(cdsubmodule&&+(cdsubsubmodule&&+gitreset--hardHEAD+)+)&&+gitsubmoduleupdate--recursive&&+(cdsubmodule&&+test_commit"update_submodule_2"file+)&&+(cdsubmodule2&&+test_commit"update_submodule2_2"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"two_new_submodule_commits"&&+(cdsubmodule&&+gitcheckoutmaster&&+test_commit"conflict"file&&+echo"conflict">file+)&&+gitcheckoutHEAD^&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect+)&&+gitconfigsubmodule.submodule.updatemerge&&+test_must_failgitsubmoduleupdate&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+'+test_expect_success'submodule update exit immediately after recursive rebase error''+(cdsuper&&+gitcheckoutmaster&&+gitreset--hardHEAD&&+(cdsubmodule&&+gitreset--hardHEAD&&+gitsubmoduleupdate--recursive+)&&+(cdsubmodule&&+test_commit"update_submodule_3"file+)&&+(cdsubmodule2&&+test_commit"update_submodule2_3"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"two_new_submodule_commits"&&+(cdsubmodule&&+gitcheckoutmaster&&+test_commit"conflict2"file&&+echo"conflict">file+)&&+gitcheckoutHEAD^&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect+)&&+gitconfigsubmodule.submodule.updaterebase&&+test_must_failgitsubmoduleupdate&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+' test_done
From: Junio C Hamano <hidden> Date: 2016-06-15 22:51:27
Fredrik Gustafsson [off-list ref] writes:
+ *)
+ err="${err} \"Failed to $action in submodule path '$path'\""
...
+ err="${err} \"Failed to recurse into submodule path '$path'\""
+ continue
+ else
+ die_with_status $res "Failed to recurse into submodule path '$path'"
+ fi
+ fi
fi
done
+
+ if test -n "$err"
+ then
+ OIFS=$IFS
+ IFS=';'
+ for e in $err
Hmm, I do not see anybody concatenating things with semicolons in between...
Am I reading a right patch?
Also I am puzzled what the double-quotes around each error message are
doing. Are they meant to be shown to the end user?
+ do
+ echo $e
Should this go to the standard error output?
+ done
+ IFS=$OIFS
+ die
Do we want to give an extra empty line here with "die"?
From: Fredrik Gustafsson <hidden> Date: 2016-06-15 22:51:28
"git submodule update" stops at the first error and gives control
back to the user. Only after the user fixes the problematic
submodule and runs "git submodule update" again, the second error
is found. And the user needs to repeat until all the problems are
found and fixed one by one. This is tedious.
Instead, the command can remember which submodules it had trouble with,
continue updating the ones it can, and report which ones had errors at
the end. The user can run "git submodule update", find all the ones that
need minor fixing (e.g. working tree was dirty) to fix them in a single
pass. Then another "git submodule update" can be run to update all.
Note that the problematic submodules are skipped only when they are to
be integrated with a safer value of submodule.<name>.update option,
namely "checkout". Fixing a failure in a submodule that uses "rebase" or
"merge" may need an involved conflict resolution by the user, and
leaving too many submodules in states that need resolution would not
reduce the mental burden on the user.
Signed-off-by: Fredrik Gustafsson <redacted>
Mentored-by: Jens Lehmann [off-list ref]
Mentored-by: Heiko Voigt [off-list ref]
---
I'm sorry. You were reading a mix between two solutions that slipped
through. Here's a corrected patch.
I'll changed it to be printed to standard error output instead.
die will not print an empty line (as of the first patch in this series) but I
changed this to "exit 1" instead to be more clear.
git-submodule.sh | 50 +++++++++++++--
t/t7406-submodule-update.sh | 144 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 188 insertions(+), 6 deletions(-)
@@ -525,17 +526,54 @@ cmd_update();;esac-(clear_local_git_env;cd"$path"&&$command"$sha1")||-die"Unable to $action '$sha1' in submodule path '$path'"-say"Submodule path '$path': $msg '$sha1'"+if(clear_local_git_env;cd"$path"&&$command"$sha1")+then+say"Submodule path '$path': $msg '$sha1'"+else+case$actionin+rebase|merge)+die_with_status2"Unable to $action '$sha1' in submodule path '$path'"+;;+*)+err="${err};Failed to $action in submodule path '$path'"+continue+;;+esac+fifiiftest-n"$recursive"then-(clear_local_git_env;cd"$path"&&evalcmd_update"$orig_flags")||-die"Failed to recurse into submodule path '$path'"+(clear_local_git_env;cd"$path"&&evalcmd_update"$orig_flags")+res=$?+iftest$res-gt0+then+iftest$res-eq1+then+err="${err};Failed to recurse into submodule path '$path'"+continue+else+die_with_status$res"Failed to recurse into submodule path '$path'"+fi+fifidone++iftest-n"$err"+then+OIFS=$IFS+IFS=';'+forein$err+do+iftest-n"$e"+then+echo>&2"$e"+fi+done+IFS=$OIFS+exit1+fi+}} set_name_rev(){
@@ -298,4 +298,148 @@ test_expect_success 'submodule update ignores update=rebase config for new submo)'+test_expect_success'submodule update continues after checkout error''+(cdsuper&&+gitreset--hardHEAD&&+gitsubmoduleadd../submodulesubmodule2&&+gitsubmoduleinit&&+gitcommit-am"new_submodule"&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect+)&&+(cdsubmodule&&+test_commit"update_submodule"file+)&&+(cdsubmodule2&&+test_commit"update_submodule2"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"two_new_submodule_commits"&&+(cdsubmodule&&+echo"">file+)&&+gitcheckoutHEAD^&&+test_must_failgitsubmoduleupdate&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+'+test_expect_success'submodule update continues after recursive checkout error''+(cdsuper&&+gitreset--hardHEAD&&+gitcheckoutmaster&&+gitsubmoduleupdate&&+(cdsubmodule&&+gitsubmoduleadd../submodulesubsubmodule&&+gitsubmoduleinit&&+gitcommit-m"new_subsubmodule"+)&&+gitaddsubmodule&&+gitcommit-m"update_submodule"&&+(cdsubmodule&&+(cdsubsubmodule&&+test_commit"update_subsubmodule"file+)&&+gitaddsubsubmodule&&+test_commit"update_submodule_again"file&&+(cdsubsubmodule&&+test_commit"update_subsubmodule_again"file+)&&+test_commit"update_submodule_again_again"file+)&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect&&+test_commit"update_submodule2_again"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"new_commits"&&+gitcheckoutHEAD^&&+(cdsubmodule&&+gitcheckoutHEAD^&&+(cdsubsubmodule&&+echo"">file+)+)&&+test_must_failgitsubmoduleupdate--recursive&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+'++test_expect_success'submodule update exit immediately in case of merge conflict''+(cdsuper&&+gitcheckoutmaster&&+gitreset--hardHEAD&&+(cdsubmodule&&+(cdsubsubmodule&&+gitreset--hardHEAD+)+)&&+gitsubmoduleupdate--recursive&&+(cdsubmodule&&+test_commit"update_submodule_2"file+)&&+(cdsubmodule2&&+test_commit"update_submodule2_2"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"two_new_submodule_commits"&&+(cdsubmodule&&+gitcheckoutmaster&&+test_commit"conflict"file&&+echo"conflict">file+)&&+gitcheckoutHEAD^&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect+)&&+gitconfigsubmodule.submodule.updatemerge&&+test_must_failgitsubmoduleupdate&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+'+test_expect_success'submodule update exit immediately after recursive rebase error''+(cdsuper&&+gitcheckoutmaster&&+gitreset--hardHEAD&&+(cdsubmodule&&+gitreset--hardHEAD&&+gitsubmoduleupdate--recursive+)&&+(cdsubmodule&&+test_commit"update_submodule_3"file+)&&+(cdsubmodule2&&+test_commit"update_submodule2_3"file+)&&+gitaddsubmodule&&+gitaddsubmodule2&&+gitcommit-m"two_new_submodule_commits"&&+(cdsubmodule&&+gitcheckoutmaster&&+test_commit"conflict2"file&&+echo"conflict">file+)&&+gitcheckoutHEAD^&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../expect+)&&+gitconfigsubmodule.submodule.updaterebase&&+test_must_failgitsubmoduleupdate&&+(cdsubmodule2&&+gitrev-parse--max-count=1HEAD>../actual+)&&+test_cmpexpectactual+)+' test_done