@@ -56,7 +56,9 @@ static void feed_object(const struct object_id *oid, FILE *fh, int negative)
56
56
/*
57
57
* Make a pack stream and spit it out into file descriptor fd
58
58
*/
59
- static int pack_objects (int fd , struct ref * refs , struct oid_array * extra , struct send_pack_args * args )
59
+ static int pack_objects (int fd , struct ref * refs , struct oid_array * advertised ,
60
+ struct oid_array * negotiated ,
61
+ struct send_pack_args * args )
60
62
{
61
63
/*
62
64
* The child becomes pack-objects --revs; we feed
@@ -94,8 +96,10 @@ static int pack_objects(int fd, struct ref *refs, struct oid_array *extra, struc
94
96
* parameters by writing to the pipe.
95
97
*/
96
98
po_in = xfdopen (po .in , "w" );
97
- for (i = 0 ; i < extra -> nr ; i ++ )
98
- feed_object (& extra -> oid [i ], po_in , 1 );
99
+ for (i = 0 ; i < advertised -> nr ; i ++ )
100
+ feed_object (& advertised -> oid [i ], po_in , 1 );
101
+ for (i = 0 ; i < negotiated -> nr ; i ++ )
102
+ feed_object (& negotiated -> oid [i ], po_in , 1 );
99
103
100
104
while (refs ) {
101
105
if (!is_null_oid (& refs -> old_oid ))
@@ -409,11 +413,55 @@ static void reject_invalid_nonce(const char *nonce, int len)
409
413
}
410
414
}
411
415
416
+ static void get_commons_through_negotiation (const char * url ,
417
+ const struct ref * remote_refs ,
418
+ struct oid_array * commons )
419
+ {
420
+ struct child_process child = CHILD_PROCESS_INIT ;
421
+ const struct ref * ref ;
422
+ int len = the_hash_algo -> hexsz + 1 ; /* hash + NL */
423
+
424
+ child .git_cmd = 1 ;
425
+ child .no_stdin = 1 ;
426
+ child .out = -1 ;
427
+ strvec_pushl (& child .args , "fetch" , "--negotiate-only" , NULL );
428
+ for (ref = remote_refs ; ref ; ref = ref -> next )
429
+ strvec_pushf (& child .args , "--negotiation-tip=%s" , oid_to_hex (& ref -> new_oid ));
430
+ strvec_push (& child .args , url );
431
+
432
+ if (start_command (& child ))
433
+ die (_ ("send-pack: unable to fork off fetch subprocess" ));
434
+
435
+ do {
436
+ char hex_hash [GIT_MAX_HEXSZ + 1 ];
437
+ int read_len = read_in_full (child .out , hex_hash , len );
438
+ struct object_id oid ;
439
+ const char * end ;
440
+
441
+ if (!read_len )
442
+ break ;
443
+ if (read_len != len )
444
+ die ("invalid length read %d" , read_len );
445
+ if (parse_oid_hex (hex_hash , & oid , & end ) || * end != '\n' )
446
+ die ("invalid hash" );
447
+ oid_array_append (commons , & oid );
448
+ } while (1 );
449
+
450
+ if (finish_command (& child )) {
451
+ /*
452
+ * The information that push negotiation provides is useful but
453
+ * not mandatory.
454
+ */
455
+ warning (_ ("push negotiation failed; proceeding anyway with push" ));
456
+ }
457
+ }
458
+
412
459
int send_pack (struct send_pack_args * args ,
413
460
int fd [], struct child_process * conn ,
414
461
struct ref * remote_refs ,
415
462
struct oid_array * extra_have )
416
463
{
464
+ struct oid_array commons = OID_ARRAY_INIT ;
417
465
int in = fd [0 ];
418
466
int out = fd [1 ];
419
467
struct strbuf req_buf = STRBUF_INIT ;
@@ -426,6 +474,7 @@ int send_pack(struct send_pack_args *args,
426
474
int quiet_supported = 0 ;
427
475
int agent_supported = 0 ;
428
476
int advertise_sid = 0 ;
477
+ int push_negotiate = 0 ;
429
478
int use_atomic = 0 ;
430
479
int atomic_supported = 0 ;
431
480
int use_push_options = 0 ;
@@ -437,6 +486,10 @@ int send_pack(struct send_pack_args *args,
437
486
const char * push_cert_nonce = NULL ;
438
487
struct packet_reader reader ;
439
488
489
+ git_config_get_bool ("push.negotiate" , & push_negotiate );
490
+ if (push_negotiate )
491
+ get_commons_through_negotiation (args -> url , remote_refs , & commons );
492
+
440
493
git_config_get_bool ("transfer.advertisesid" , & advertise_sid );
441
494
442
495
/* Does the other end support the reporting? */
@@ -625,7 +678,7 @@ int send_pack(struct send_pack_args *args,
625
678
PACKET_READ_DIE_ON_ERR_PACKET );
626
679
627
680
if (need_pack_data && cmds_sent ) {
628
- if (pack_objects (out , remote_refs , extra_have , args ) < 0 ) {
681
+ if (pack_objects (out , remote_refs , extra_have , & commons , args ) < 0 ) {
629
682
if (args -> stateless_rpc )
630
683
close (out );
631
684
if (git_connection_is_socket (conn ))
0 commit comments