@@ -398,6 +398,7 @@ struct git_transport_data {
398398 struct git_transport_options options ;
399399 struct child_process * conn ;
400400 int fd [2 ];
401+ unsigned got_remote_heads : 1 ;
401402 struct extra_have_objects extra_have ;
402403};
403404
@@ -432,10 +433,15 @@ static int set_git_option(struct git_transport_options *opts,
432433static int connect_setup (struct transport * transport , int for_push , int verbose )
433434{
434435 struct git_transport_data * data = transport -> data ;
436+
437+ if (data -> conn )
438+ return 0 ;
439+
435440 data -> conn = git_connect (data -> fd , transport -> url ,
436441 for_push ? data -> options .receivepack :
437442 data -> options .uploadpack ,
438443 verbose ? CONNECT_VERBOSE : 0 );
444+
439445 return 0 ;
440446}
441447
@@ -447,6 +453,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
447453 connect_setup (transport , for_push , 0 );
448454 get_remote_heads (data -> fd [0 ], & refs , 0 , NULL ,
449455 for_push ? REF_NORMAL : 0 , & data -> extra_have );
456+ data -> got_remote_heads = 1 ;
450457
451458 return refs ;
452459}
@@ -477,9 +484,10 @@ static int fetch_refs_via_pack(struct transport *transport,
477484 for (i = 0 ; i < nr_heads ; i ++ )
478485 origh [i ] = heads [i ] = xstrdup (to_fetch [i ]-> name );
479486
480- if (!data -> conn ) {
487+ if (!data -> got_remote_heads ) {
481488 connect_setup (transport , 0 , 0 );
482489 get_remote_heads (data -> fd [0 ], & refs_tmp , 0 , NULL , 0 , NULL );
490+ data -> got_remote_heads = 1 ;
483491 }
484492
485493 refs = fetch_pack (& args , data -> fd , data -> conn ,
@@ -490,6 +498,7 @@ static int fetch_refs_via_pack(struct transport *transport,
490498 if (finish_connect (data -> conn ))
491499 refs = NULL ;
492500 data -> conn = NULL ;
501+ data -> got_remote_heads = 0 ;
493502
494503 free_refs (refs_tmp );
495504
@@ -718,12 +727,13 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
718727 struct send_pack_args args ;
719728 int ret ;
720729
721- if (!data -> conn ) {
730+ if (!data -> got_remote_heads ) {
722731 struct ref * tmp_refs ;
723732 connect_setup (transport , 1 , 0 );
724733
725734 get_remote_heads (data -> fd [0 ], & tmp_refs , 0 , NULL , REF_NORMAL ,
726735 NULL );
736+ data -> got_remote_heads = 1 ;
727737 }
728738
729739 memset (& args , 0 , sizeof (args ));
@@ -741,6 +751,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
741751 close (data -> fd [0 ]);
742752 ret |= finish_connect (data -> conn );
743753 data -> conn = NULL ;
754+ data -> got_remote_heads = 0 ;
744755
745756 return ret ;
746757}
@@ -749,7 +760,8 @@ static int disconnect_git(struct transport *transport)
749760{
750761 struct git_transport_data * data = transport -> data ;
751762 if (data -> conn ) {
752- packet_flush (data -> fd [1 ]);
763+ if (data -> got_remote_heads )
764+ packet_flush (data -> fd [1 ]);
753765 close (data -> fd [0 ]);
754766 close (data -> fd [1 ]);
755767 finish_connect (data -> conn );
@@ -759,6 +771,32 @@ static int disconnect_git(struct transport *transport)
759771 return 0 ;
760772}
761773
774+ void transport_take_over (struct transport * transport ,
775+ struct child_process * child )
776+ {
777+ struct git_transport_data * data ;
778+
779+ if (!transport -> smart_options )
780+ die ("Bug detected: Taking over transport requires non-NULL "
781+ "smart_options field." );
782+
783+ data = xcalloc (1 , sizeof (* data ));
784+ data -> options = * transport -> smart_options ;
785+ data -> conn = child ;
786+ data -> fd [0 ] = data -> conn -> out ;
787+ data -> fd [1 ] = data -> conn -> in ;
788+ data -> got_remote_heads = 0 ;
789+ transport -> data = data ;
790+
791+ transport -> set_option = NULL ;
792+ transport -> get_refs_list = get_refs_via_connect ;
793+ transport -> fetch = fetch_refs_via_pack ;
794+ transport -> push = NULL ;
795+ transport -> push_refs = git_transport_push ;
796+ transport -> disconnect = disconnect_git ;
797+ transport -> smart_options = & (data -> options );
798+ }
799+
762800static int is_local (const char * url )
763801{
764802 const char * colon = strchr (url , ':' );
@@ -867,6 +905,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
867905 ret -> smart_options = & (data -> options );
868906
869907 data -> conn = NULL ;
908+ data -> got_remote_heads = 0 ;
870909 } else if (!prefixcmp (url , "http://" )
871910 || !prefixcmp (url , "https://" )
872911 || !prefixcmp (url , "ftp://" )) {
@@ -927,9 +966,9 @@ int transport_push(struct transport *transport,
927966 * nonfastforward = 0 ;
928967 verify_remote_names (refspec_nr , refspec );
929968
930- if (transport -> push )
969+ if (transport -> push ) {
931970 return transport -> push (transport , refspec_nr , refspec , flags );
932- if (transport -> push_refs ) {
971+ } else if (transport -> push_refs ) {
933972 struct ref * remote_refs =
934973 transport -> get_refs_list (transport , 1 );
935974 struct ref * local_refs = get_local_heads ();
@@ -973,6 +1012,7 @@ const struct ref *transport_get_remote_refs(struct transport *transport)
9731012{
9741013 if (!transport -> remote_refs )
9751014 transport -> remote_refs = transport -> get_refs_list (transport , 0 );
1015+
9761016 return transport -> remote_refs ;
9771017}
9781018
@@ -1007,6 +1047,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
10071047 }
10081048
10091049 rc = transport -> fetch (transport , nr_heads , heads );
1050+
10101051 free (heads );
10111052 return rc ;
10121053}
0 commit comments