bug fix with push --dry-run and submodules
cover bug fix with push --dry-run and submodules
While trying to understand how the recursive pushing of submodules worked I discovered that when push was instructed to do a dry-run, while also configured to push unpushed submodules 'on-demand', that the submodule pushes weren't configured to perform dry-runs, but actually performed the pushes. This resulted in the submodules being pushed while leaving the superproject unpushed which is undesirable behavior for a dry-run.
This series introduces a test to illustrate the bug as well as a patch to correct this behavior by passing the --dry-run flag to the child processes which perform the submodule pushes during a dry-run.
This series is based against 'origin/hv/submodule-not-yet-pushed-fix'
Brandon Williams (2):
push: --dry-run updates submodules when --recurse-submodules=on-demand
push: fix --dry-run to not push submodules
submodule.c | 13 ++++++++----- submodule.h | 4 +++- t/t5531-deep-submodule-push.sh | 26 +++++++++++++++++++++++++- transport.c | 9 ++++++--- 4 files changed, 42 insertions(+), 10 deletions(-)
Signature · 1 line
2.8.0.rc3.226.g39d4020
PATCH 1/2 push: --dry-run updates submodules when --recurse-submodules=on-demand
This patch adds a test to illustrate how push run with --dry-run doesn't actually perform a dry-run when push is configured to push submodules on-demand. Instead all submodules which need to be pushed are actually pushed to their remotes while any updates for the superproject are performed as a dry-run. This is a bug and not the intended behaviour of a dry-run.
--- t/t5531-deep-submodule-push.sh | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
t/t5531-deep-submodule-push.sh +25 -1
@@ -427,7 +427,31 @@ test_expect_success 'push unpushable submodule recursively fails' ' cd submodule.git && git rev-parse master >../actual ) && - test_cmp expected actual + test_cmp expected actual && + git -C work reset --hard master^ +' + +test_expect_failure 'push --dry-run does not recursively update submodules' ' + ( + cd work && + ( + cd gar/bage && + git checkout master && + git rev-parse master >../../../expected_submodule && + > junk9 && + git add junk9 && + git commit -m "Ninth junk" + ) && + git checkout master && + git rev-parse master >../expected_pub + git add gar/bage && + git commit -m "Ninth commit for gar/bage" && + git push --dry-run --recurse-submodules=on-demand ../pub.git master + ) && + git -C submodule.git rev-parse master >actual_submodule && + git -C pub.git rev-parse master >actual_pub && + test_cmp expected_pub actual_pub && + test_cmp expected_submodule actual_submodule ' test_done
Signature · 1 line
2.8.0.rc3.226.g39d4020
Re: [PATCH 1/2] push: --dry-run updates submodules when --recurse-submodules=on-demand
Am 15.11.2016 um 02:18 schrieb Brandon Williams:
t/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 431
Quoted 11 lines
t/t5531-deep-submodule-push.sh +2
-1@@ -427,7 +427,31 @@ test_expect_success 'push unpushable submodule recursively fails' ' cd submodule.git && git rev-parse master >../actual ) && - test_cmp expected actual + test_cmp expected actual && + git -C work reset --hard master^
This line looks like a clean-up to be done after the test case. You should wrap it in test_when_finished, but outside of a sub-shell, which looks like it's just one line earlier, before the test_cmp.
t/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 444
Quoted 13 lines
t/t5531-deep-submodule-push.sh +13
-0+' + +test_expect_failure 'push --dry-run does not recursively update submodules' ' + ( + cd work && + ( + cd gar/bage && + git checkout master && + git rev-parse master >../../../expected_submodule && + > junk9 && + git add junk9 && + git commit -m "Ninth junk" + ) &&
Could you please avoid this nested sub-shell? It is fine to cd around when you are in a sub-shell.
t/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 446
Quoted 2 lines
t/t5531-deep-submodule-push.sh +2
-0+ git checkout master && + git rev-parse master >../expected_pub
Broken && chain.
t/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 452
Quoted 6 lines
t/t5531-deep-submodule-push.sh +6
-0+ git add gar/bage && + git commit -m "Ninth commit for gar/bage" && + git push --dry-run --recurse-submodules=on-demand ../pub.git master + ) && + git -C submodule.git rev-parse master >actual_submodule && + git -C pub.git rev-parse master >actual_pub &&
All of the commands above are 'git something' that could become 'git -C work something' and then the sub-shell would be unnecessary. I'm not sure I would appreciate the verbosity of the result, though. (Perhaps aligning the git subcommands after -C foo would help.)
Quoted 6 lines
t/t5531-deep-submodule-push.sh +2
-0+ test_cmp expected_pub actual_pub && + test_cmp expected_submodule actual_submodule ' test_done
Re: [PATCH 1/2] push: --dry-run updates submodules when --recurse-submodules=on-demand
Quoted 16 lines · Johannes Sixt
Am 15.11.2016 um 02:18 schrieb Brandon Williams:
t/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 431
Quoted 11 lines
t/t5531-deep-submodule-push.sh +2
-1@@ -427,7 +427,31 @@ test_expect_success 'push unpushable submodule recursively fails' ' cd submodule.git && git rev-parse master >../actual ) && - test_cmp expected actual + test_cmp expected actual && + git -C work reset --hard master^This line looks like a clean-up to be done after the test case. You should wrap it in
test_when_finished, but outside of a sub-shell, which looks like it's just one line earlier, before thetest_cmp.
K will do.
Quoted 17 lines
Quoted 4 lines
t/t5531-deep-submodule-push.sh +3
-0+' + +test_expect_failure 'push --dry-run does not recursively update submodules' 't/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 444
Quoted 10 lines
t/t5531-deep-submodule-push.sh +10
-0+ ( + cd work && + ( + cd gar/bage && + git checkout master && + git rev-parse master >../../../expected_submodule && + > junk9 && + git add junk9 && + git commit -m "Ninth junk" + ) &&Could you please avoid this nested sub-shell? It is fine to cd around when you are in a sub-shell.
Yes I can reorganize it to avoid the nested sub-shells. I was just trying to follow the organization of the other tests in the same file.
Quoted 6 lines
t/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 446
Quoted 3 lines
t/t5531-deep-submodule-push.sh +2
-0+ git checkout master && + git rev-parse master >../expected_pubBroken && chain.
Quoted 11 lines
t/t5531-deep-submodule-push.sh test_expect_success 'push unpushable submodule recursively fails' ' · line 452
Quoted 6 lines
t/t5531-deep-submodule-push.sh +6
-0+ git add gar/bage && + git commit -m "Ninth commit for gar/bage" && + git push --dry-run --recurse-submodules=on-demand ../pub.git master + ) && + git -C submodule.git rev-parse master >actual_submodule && + git -C pub.git rev-parse master >actual_pub &&All of the commands above are 'git something' that could become 'git -C work something' and then the sub-shell would be unnecessary. I'm not sure I would appreciate the verbosity of the result, though. (Perhaps aligning the git subcommands after -C foo would help.)
I'll play around with it and try to make it look pretty while trying to avoid sub-shells. I'm assuming the reason we want to avoid sub-shells is for performance reasons right?
Signature · 1 line
Brandon Williams
Re: [PATCH 1/2] push: --dry-run updates submodules when --recurse-submodules=on-demand
Am 15.11.2016 um 18:29 schrieb Brandon Williams:
Quoted 2 lines
I'm assuming the reason we want to avoid sub-shells is for performance reasons right?
Yes, every fork() saved is a win on Windows. (No pun intended ;)
-- Hannes
PATCH 2/2 push: fix --dry-run to not push submodules
In reply to Brandon WilliamsTeach push to respect the --dry-run option when configured to recursively push submodules 'on-demand'. This is done by passing the --dry-run flag to the child process which performs a push for a submodules when performing a dry-run.
In order to preserve good user experience, the additional check for unpushed submodules is skipped during a dry-run when --recurse-submodules=on-demand. The check is skipped because the submodule pushes were performed as dry-runs and this check would always fail as the submodules would still need to be pushed.
--- submodule.c | 13 ++++++++----- submodule.h | 4 +++- t/t5531-deep-submodule-push.sh | 2 +- transport.c | 9 ++++++--- 4 files changed, 18 insertions(+), 10 deletions(-)
submodule.c +8 -5
@@ -676,16 +676,17 @@ int find_unpushed_submodules(struct sha1_array *hashes,return needs_pushing->nr; } -static int push_submodule (const char *path) +static int push_submodule (const char *path,int dry_run) {if (add_submodule_odb (path))return 1 ;if (for_each_remote_ref_submodule (path, has_remote,NULL ) >0 ) {struct child_process cp =CHILD_PROCESS_INIT ; -const char *argv[] = {"push" ,NULL }; +argv_array_push (&cp.args,"push" ); +if (dry_run) +argv_array_push (&cp.args,"--dry-run" ); - cp.argv = argv;prepare_submodule_repo_env (&cp.env_array); cp.git_cmd =1 ; cp.no_stdin =1 ;
@@ -698,7 +699,9 @@ static int push_submodule(const char *path)return 1 ; } -int push_unpushed_submodules (struct sha1_array *hashes,const char *remotes_name) +int push_unpushed_submodules (struct sha1_array *hashes, +const char *remotes_name, +int dry_run) {int i, ret =1 ;struct string_list needs_pushing =STRING_LIST_INIT_DUP ;
@@ -709,7 +712,7 @@ int push_unpushed_submodules(struct sha1_array *hashes, const char *remotes_namefor (i =0 ; i < needs_pushing.nr; i++) {const char *path = needs_pushing.items[i].string;fprintf (stderr,"Pushing submodule '%s'\n" , path); -if (!push_submodule (path)) { +if (!push_submodule (path, dry_run)) {fprintf (stderr,"Unable to push submodule '%s'\n" , path); ret =0 ; }
submodule.h +3 -1
@@ -65,7 +65,9 @@ int merge_submodule(unsigned char result[20], const char *path, const unsigned c const unsigned char a[20], const unsigned char b[20], int search);int find_unpushed_submodules (struct sha1_array *hashes,const char *remotes_name,struct string_list *needs_pushing); -int push_unpushed_submodules (struct sha1_array *hashes,const char *remotes_name); +extern int push_unpushed_submodules (struct sha1_array *hashes, +const char *remotes_name, +int dry_run);void connect_work_tree_and_git_dir (const char *work_tree,const char *git_dir);int parallel_submodules (void );
t/t5531-deep-submodule-push.sh +1 -1
@@ -431,7 +431,7 @@ test_expect_success 'push unpushable submodule recursively fails' ' git -C work reset --hard master^ ' -test_expect_failure 'push --dry-run does not recursively update submodules' ' +test_expect_success 'push --dry-run does not recursively update submodules' ' ( cd work && (
transport.c +6 -3
@@ -921,15 +921,18 @@ int transport_push(struct transport *transport,if (!is_null_oid (&ref->new_oid))sha1_array_append (&hashes, ref->new_oid.hash); -if (!push_unpushed_submodules (&hashes, transport->remote->name)) { +if (!push_unpushed_submodules (&hashes, + transport->remote->name, + pretend)) {sha1_array_clear (&hashes);die ("Failed to push all needed submodules!" ); }sha1_array_clear (&hashes); } -if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND | -TRANSPORT_RECURSE_SUBMODULES_CHECK )) && !is_bare_repository ()) { +if (((flags &TRANSPORT_RECURSE_SUBMODULES_CHECK ) || + ((flags &TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND ) && + !pretend)) && !is_bare_repository ()) {struct ref *ref = remote_refs;struct string_list needs_pushing =STRING_LIST_INIT_DUP ;struct sha1_array hashes =SHA1_ARRAY_INIT ;
Signature · 1 line
2.8.0.rc3.226.g39d4020
v2 cover bug fix with push --dry-run and submodules
In reply to Brandon Williamsv2 of this series is just a small cleanup of removing a nested sub-shell from a test and rebasing on the latest version of 'origin/hv/submodule-not-yet-pushed-fix'
As stated above this series is based on 'origin/hv/submodule-not-yet-pushed-fix'
Brandon Williams (2):
push: --dry-run updates submodules when --recurse-submodules=on-demand
push: fix --dry-run to not push submodules
submodule.c | 13 ++++++++----- submodule.h | 4 +++- t/t5531-deep-submodule-push.sh | 24 ++++++++++++++++++++++++ transport.c | 11 +++++++---- 4 files changed, 42 insertions(+), 10 deletions(-)
Signature · 1 line
2.8.0.rc3.226.g39d4020
PATCH v2 1/2 push: --dry-run updates submodules when --recurse-submodules=on-demand
This patch adds a test to illustrate how push run with --dry-run doesn't actually perform a dry-run when push is configured to push submodules on-demand. Instead all submodules which need to be pushed are actually pushed to their remotes while any updates for the superproject are performed as a dry-run. This is a bug and not the intended behaviour of a dry-run.
--- t/t5531-deep-submodule-push.sh | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
t/t5531-deep-submodule-push.sh +24 -0
@@ -427,7 +427,31 @@ test_expect_success 'push unpushable submodule recursively fails' ' cd submodule.git && git rev-parse master >../actual ) && + test_when_finished git -C work reset --hard master^ && test_cmp expected actual ' +test_expect_failure 'push --dry-run does not recursively update submodules' ' + ( + cd work/gar/bage && + git checkout master && + git rev-parse master >../../../expected_submodule && + > junk9 && + git add junk9 && + git commit -m "Ninth junk" && + + # Go up to 'work' directory + cd ../.. && + git checkout master && + git rev-parse master >../expected_pub && + git add gar/bage && + git commit -m "Ninth commit for gar/bage" && + git push --dry-run --recurse-submodules=on-demand ../pub.git master + ) && + git -C submodule.git rev-parse master >actual_submodule && + git -C pub.git rev-parse master >actual_pub && + test_cmp expected_pub actual_pub && + test_cmp expected_submodule actual_submodule +' + test_done
Signature · 1 line
2.8.0.rc3.226.g39d4020
PATCH v2 2/2 push: fix --dry-run to not push submodules
In reply to Brandon WilliamsTeach push to respect the --dry-run option when configured to recursively push submodules 'on-demand'. This is done by passing the --dry-run flag to the child process which performs a push for a submodules when performing a dry-run.
In order to preserve good user experience, the additional check for unpushed submodules is skipped during a dry-run when --recurse-submodules=on-demand. The check is skipped because the submodule pushes were performed as dry-runs and this check would always fail as the submodules would still need to be pushed.
--- submodule.c | 13 ++++++++----- submodule.h | 4 +++- t/t5531-deep-submodule-push.sh | 2 +- transport.c | 11 +++++++---- 4 files changed, 19 insertions(+), 11 deletions(-)
submodule.c +8 -5
@@ -683,16 +683,17 @@ int find_unpushed_submodules(struct sha1_array *commits,return needs_pushing->nr; } -static int push_submodule (const char *path) +static int push_submodule (const char *path,int dry_run) {if (add_submodule_odb (path))return 1 ;if (for_each_remote_ref_submodule (path, has_remote,NULL ) >0 ) {struct child_process cp =CHILD_PROCESS_INIT ; -const char *argv[] = {"push" ,NULL }; +argv_array_push (&cp.args,"push" ); +if (dry_run) +argv_array_push (&cp.args,"--dry-run" ); - cp.argv = argv;prepare_submodule_repo_env (&cp.env_array); cp.git_cmd =1 ; cp.no_stdin =1 ;
@@ -705,7 +706,9 @@ static int push_submodule(const char *path)return 1 ; } -int push_unpushed_submodules (struct sha1_array *commits,const char *remotes_name) +int push_unpushed_submodules (struct sha1_array *commits, +const char *remotes_name, +int dry_run) {int i, ret =1 ;struct string_list needs_pushing =STRING_LIST_INIT_DUP ;
@@ -716,7 +719,7 @@ int push_unpushed_submodules(struct sha1_array *commits, const char *remotes_namfor (i =0 ; i < needs_pushing.nr; i++) {const char *path = needs_pushing.items[i].string;fprintf (stderr,"Pushing submodule '%s'\n" , path); -if (!push_submodule (path)) { +if (!push_submodule (path, dry_run)) {fprintf (stderr,"Unable to push submodule '%s'\n" , path); ret =0 ; }
submodule.h +3 -1
@@ -65,7 +65,9 @@ int merge_submodule(unsigned char result[20], const char *path, const unsigned c const unsigned char a[20], const unsigned char b[20], int search);int find_unpushed_submodules (struct sha1_array *commits,const char *remotes_name,struct string_list *needs_pushing); -int push_unpushed_submodules (struct sha1_array *commits,const char *remotes_name); +extern int push_unpushed_submodules (struct sha1_array *commits, +const char *remotes_name, +int dry_run);void connect_work_tree_and_git_dir (const char *work_tree,const char *git_dir);int parallel_submodules (void );
t/t5531-deep-submodule-push.sh +1 -1
@@ -431,7 +431,7 @@ test_expect_success 'push unpushable submodule recursively fails' ' test_cmp expected actual ' -test_expect_failure 'push --dry-run does not recursively update submodules' ' +test_expect_success 'push --dry-run does not recursively update submodules' ' ( cd work/gar/bage && git checkout master &&
transport.c +7 -4
@@ -921,15 +921,18 @@ int transport_push(struct transport *transport,if (!is_null_oid (&ref->new_oid))sha1_array_append (&commits, ref->new_oid.hash); -if (!push_unpushed_submodules (&commits, transport->remote->name)) { +if (!push_unpushed_submodules (&commits, + transport->remote->name, + pretend)) {sha1_array_clear (&commits); -die ("Failed to push all needed submodules!" ); +die ("Failed to push all needed submodules!" ); }sha1_array_clear (&commits); } -if ((flags & (TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND | -TRANSPORT_RECURSE_SUBMODULES_CHECK )) && !is_bare_repository ()) { +if (((flags &TRANSPORT_RECURSE_SUBMODULES_CHECK ) || + ((flags &TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND ) && + !pretend)) && !is_bare_repository ()) {struct ref *ref = remote_refs;struct string_list needs_pushing =STRING_LIST_INIT_DUP ;struct sha1_array commits =SHA1_ARRAY_INIT ;
Signature · 1 line
2.8.0.rc3.226.g39d4020
Re: [PATCH v2 2/2] push: fix --dry-run to not push submodules
transport.c int transport_push(struct transport *transport, · line 928
Quoted 3 lines · Brandon Williams
sha1_array_clear(&commits);transport.c +1
-1-die ("Failed to push all needed submodules!" ); +die ("Failed to push all needed submodules!" );
huh? Is this a whitespace change?
Re: [PATCH v2 2/2] push: fix --dry-run to not push submodules
Quoted 7 lines · Stefan Beller
transport.c int transport_push(struct transport *transport, · line 928
Quoted 3 lines · Brandon Williams
sha1_array_clear(&commits);transport.c +1
-1-die ("Failed to push all needed submodules!" ); +die ("Failed to push all needed submodules!" );huh? Is this a whitespace change?
That's odd...I didn't mean to add that lone space.
Signature · 1 line
Brandon Williams
Re: [PATCH v2 2/2] push: fix --dry-run to not push submodules
Quoted 10 lines · Brandon Williams
Quoted 7 lines · Stefan Beller
transport.c int transport_push(struct transport *transport, · line 928
Quoted 3 lines · Brandon Williams
sha1_array_clear(&commits);transport.c +1
-1-die ("Failed to push all needed submodules!" ); +die ("Failed to push all needed submodules!" );huh? Is this a whitespace change?
That's odd...I didn't mean to add that lone space.
Is that the only glitch in this round? IOW, is the series OK to be picked up as long as I treak this out while queuing?
Re: [PATCH v2 2/2] push: fix --dry-run to not push submodules
Quoted 9 lines · Junio C Hamano
Quoted 7 lines · Brandon Williams
Quoted 6 lines · Stefan Beller
Quoted 3 lines · Brandon Williams
sha1_array_clear(&commits);transport.c +1
-1-die ("Failed to push all needed submodules!" ); +die ("Failed to push all needed submodules!" );
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
huh? Is this a whitespace change?
That's odd...I didn't mean to add that lone space.
Is that the only glitch in this round? IOW, is the series OK to be picked up as long as I treak this out while queuing?
It looks that way. And I did fix this in my local series. Let me know if you would rather I resend the series. Otherwise I think it looks good.
I do also have a follow on series I'm planning on sending out later to actually add in a feature which mimics what this bug does (as this functionality could be desirable in some circumstances) but thought it best to wait till heiko's and this series were more stable.
Signature · 1 line
Brandon Williams
Re: [PATCH v2 2/2] push: fix --dry-run to not push submodules
Quoted 12 lines · Brandon Williams
Quoted 11 lines · Junio C Hamano
Quoted 9 lines · Brandon Williams
Quoted 7 lines · Stefan Beller
transport.c int transport_push(struct transport *transport, · line 928
Quoted 3 lines · Brandon Williams
sha1_array_clear(&commits);transport.c +1
-1-die ("Failed to push all needed submodules!" ); +die ("Failed to push all needed submodules!" );huh? Is this a whitespace change?
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
That's odd...I didn't mean to add that lone space.
Is that the only glitch in this round? IOW, is the series OK to be picked up as long as I treak this out while queuing?
It looks that way. And I did fix this in my local series. Let me know if you would rather I resend the series. Otherwise I think it looks good.
OK, queued with trivial fix for now.
Thanks.
Quoted 5 lines · Brandon Williams
v2 of this series is just a small cleanup of removing a nested sub-shell from a test and rebasing on the latest version of 'origin/hv/submodule-not-yet-pushed-fix'
As stated above this series is based on 'origin/hv/submodule-not-yet-pushed-fix'
an interdiff to v1 would be nice :)
Now t5531 is inconsistent in style,
how much time would you estimate to add a commit to refactor that test to follow the style with excessive use of -C for all the other tests and avoiding subshells there, too?
(It's mainly Windows that benefits from such a refactoring immediately, but consistency is a really nice feat for the long term code health of the Git project)
Apart from one nit (and this refactoring decision/consistency discussion), the series looks good!
Thanks,
Stefan
Quoted 5 lines · Stefan Beller
Quoted 4 lines · Brandon Williams
v2 of this series is just a small cleanup of removing a nested sub-shell from a test and rebasing on the latest version of 'origin/hv/submodule-not-yet-pushed-fix'
Quoted 8 lines
Quoted 1 line
As stated above this series is based on 'origin/hv/submodule-not-yet-pushed-fix'
an interdiff to v1 would be nice :)
Now t5531 is inconsistent in style,
how much time would you estimate to add a commit to refactor that test to follow the style with excessive use of -C for all the other tests and avoiding subshells there, too?
I didn't change to an excessive use of the -C option, but rather eliminated the nested-subshell and instead cd'ed to the required directories in the subshell. Excessive use of -C seemed to greatly reduce the readability of the test (at least it did to me).
Signature · 1 line
Brandon Williams