99#include "object.h"
1010#include "remote.h"
1111#include "transport.h"
12+ #include "string-list.h"
1213
1314static const char receive_pack_usage [] = "git receive-pack <git-dir>" ;
1415
@@ -129,13 +130,12 @@ static void write_head_info(void)
129130struct command {
130131 struct command * next ;
131132 const char * error_string ;
133+ unsigned int skip_update ;
132134 unsigned char old_sha1 [20 ];
133135 unsigned char new_sha1 [20 ];
134136 char ref_name [FLEX_ARRAY ]; /* more */
135137};
136138
137- static struct command * commands ;
138-
139139static const char pre_receive_hook [] = "hooks/pre-receive" ;
140140static const char post_receive_hook [] = "hooks/post-receive" ;
141141
@@ -188,7 +188,7 @@ static int copy_to_sideband(int in, int out, void *arg)
188188 return 0 ;
189189}
190190
191- static int run_receive_hook (const char * hook_name )
191+ static int run_receive_hook (struct command * commands , const char * hook_name )
192192{
193193 static char buf [sizeof (commands -> old_sha1 ) * 2 + PATH_MAX + 4 ];
194194 struct command * cmd ;
@@ -447,15 +447,15 @@ static const char *update(struct command *cmd)
447447
448448static char update_post_hook [] = "hooks/post-update" ;
449449
450- static void run_update_post_hook (struct command * cmd )
450+ static void run_update_post_hook (struct command * commands )
451451{
452- struct command * cmd_p ;
452+ struct command * cmd ;
453453 int argc ;
454454 const char * * argv ;
455455 struct child_process proc ;
456456
457- for (argc = 0 , cmd_p = cmd ; cmd_p ; cmd_p = cmd_p -> next ) {
458- if (cmd_p -> error_string )
457+ for (argc = 0 , cmd = commands ; cmd ; cmd = cmd -> next ) {
458+ if (cmd -> error_string )
459459 continue ;
460460 argc ++ ;
461461 }
@@ -464,12 +464,12 @@ static void run_update_post_hook(struct command *cmd)
464464 argv = xmalloc (sizeof (* argv ) * (2 + argc ));
465465 argv [0 ] = update_post_hook ;
466466
467- for (argc = 1 , cmd_p = cmd ; cmd_p ; cmd_p = cmd_p -> next ) {
467+ for (argc = 1 , cmd = commands ; cmd ; cmd = cmd -> next ) {
468468 char * p ;
469- if (cmd_p -> error_string )
469+ if (cmd -> error_string )
470470 continue ;
471- p = xmalloc (strlen (cmd_p -> ref_name ) + 1 );
472- strcpy (p , cmd_p -> ref_name );
471+ p = xmalloc (strlen (cmd -> ref_name ) + 1 );
472+ strcpy (p , cmd -> ref_name );
473473 argv [argc ] = p ;
474474 argc ++ ;
475475 }
@@ -488,37 +488,92 @@ static void run_update_post_hook(struct command *cmd)
488488 }
489489}
490490
491- static void execute_commands (const char * unpacker_error )
491+ static void check_aliased_update (struct command * cmd , struct string_list * list )
492+ {
493+ struct string_list_item * item ;
494+ struct command * dst_cmd ;
495+ unsigned char sha1 [20 ];
496+ char cmd_oldh [41 ], cmd_newh [41 ], dst_oldh [41 ], dst_newh [41 ];
497+ int flag ;
498+
499+ const char * dst_name = resolve_ref (cmd -> ref_name , sha1 , 0 , & flag );
500+
501+ if (!(flag & REF_ISSYMREF ))
502+ return ;
503+
504+ if ((item = string_list_lookup (dst_name , list )) == NULL )
505+ return ;
506+
507+ cmd -> skip_update = 1 ;
508+
509+ dst_cmd = (struct command * ) item -> util ;
510+
511+ if (!hashcmp (cmd -> old_sha1 , dst_cmd -> old_sha1 ) &&
512+ !hashcmp (cmd -> new_sha1 , dst_cmd -> new_sha1 ))
513+ return ;
514+
515+ dst_cmd -> skip_update = 1 ;
516+
517+ strcpy (cmd_oldh , find_unique_abbrev (cmd -> old_sha1 , DEFAULT_ABBREV ));
518+ strcat (cmd_newh , find_unique_abbrev (cmd -> new_sha1 , DEFAULT_ABBREV ));
519+ strcpy (dst_oldh , find_unique_abbrev (dst_cmd -> old_sha1 , DEFAULT_ABBREV ));
520+ strcat (dst_newh , find_unique_abbrev (dst_cmd -> new_sha1 , DEFAULT_ABBREV ));
521+ rp_error ("refusing inconsistent update between symref '%s' (%s..%s) and"
522+ " its target '%s' (%s..%s)" ,
523+ cmd -> ref_name , cmd_oldh , cmd_newh ,
524+ dst_cmd -> ref_name , dst_oldh , dst_newh );
525+
526+ cmd -> error_string = dst_cmd -> error_string =
527+ "inconsistent aliased update" ;
528+ }
529+
530+ static void check_aliased_updates (struct command * commands )
531+ {
532+ struct command * cmd ;
533+ struct string_list ref_list = { NULL , 0 , 0 , 0 };
534+
535+ for (cmd = commands ; cmd ; cmd = cmd -> next ) {
536+ struct string_list_item * item =
537+ string_list_append (cmd -> ref_name , & ref_list );
538+ item -> util = (void * )cmd ;
539+ }
540+ sort_string_list (& ref_list );
541+
542+ for (cmd = commands ; cmd ; cmd = cmd -> next )
543+ check_aliased_update (cmd , & ref_list );
544+
545+ string_list_clear (& ref_list , 0 );
546+ }
547+
548+ static void execute_commands (struct command * commands , const char * unpacker_error )
492549{
493- struct command * cmd = commands ;
550+ struct command * cmd ;
494551 unsigned char sha1 [20 ];
495552
496553 if (unpacker_error ) {
497- while (cmd ) {
554+ for (cmd = commands ; cmd ; cmd = cmd -> next )
498555 cmd -> error_string = "n/a (unpacker error)" ;
499- cmd = cmd -> next ;
500- }
501556 return ;
502557 }
503558
504- if (run_receive_hook (pre_receive_hook )) {
505- while (cmd ) {
559+ if (run_receive_hook (commands , pre_receive_hook )) {
560+ for (cmd = commands ; cmd ; cmd = cmd -> next )
506561 cmd -> error_string = "pre-receive hook declined" ;
507- cmd = cmd -> next ;
508- }
509562 return ;
510563 }
511564
565+ check_aliased_updates (commands );
566+
512567 head_name = resolve_ref ("HEAD" , sha1 , 0 , NULL );
513568
514- while (cmd ) {
515- cmd -> error_string = update (cmd );
516- cmd = cmd -> next ;
517- }
569+ for (cmd = commands ; cmd ; cmd = cmd -> next )
570+ if (!cmd -> skip_update )
571+ cmd -> error_string = update (cmd );
518572}
519573
520- static void read_head_info (void )
574+ static struct command * read_head_info (void )
521575{
576+ struct command * commands = NULL ;
522577 struct command * * p = & commands ;
523578 for (;;) {
524579 static char line [1000 ];
@@ -548,15 +603,14 @@ static void read_head_info(void)
548603 if (strstr (refname + reflen + 1 , "side-band-64k" ))
549604 use_sideband = LARGE_PACKET_MAX ;
550605 }
551- cmd = xmalloc ( sizeof (struct command ) + len - 80 );
606+ cmd = xcalloc ( 1 , sizeof (struct command ) + len - 80 );
552607 hashcpy (cmd -> old_sha1 , old_sha1 );
553608 hashcpy (cmd -> new_sha1 , new_sha1 );
554609 memcpy (cmd -> ref_name , line + 82 , len - 81 );
555- cmd -> error_string = NULL ;
556- cmd -> next = NULL ;
557610 * p = cmd ;
558611 p = & cmd -> next ;
559612 }
613+ return commands ;
560614}
561615
562616static const char * parse_pack_header (struct pack_header * hdr )
@@ -643,7 +697,7 @@ static const char *unpack(void)
643697 }
644698}
645699
646- static void report (const char * unpack_status )
700+ static void report (struct command * commands , const char * unpack_status )
647701{
648702 struct command * cmd ;
649703 struct strbuf buf = STRBUF_INIT ;
@@ -667,12 +721,12 @@ static void report(const char *unpack_status)
667721 strbuf_release (& buf );
668722}
669723
670- static int delete_only (struct command * cmd )
724+ static int delete_only (struct command * commands )
671725{
672- while (cmd ) {
726+ struct command * cmd ;
727+ for (cmd = commands ; cmd ; cmd = cmd -> next ) {
673728 if (!is_null_sha1 (cmd -> new_sha1 ))
674729 return 0 ;
675- cmd = cmd -> next ;
676730 }
677731 return 1 ;
678732}
@@ -722,6 +776,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
722776 int stateless_rpc = 0 ;
723777 int i ;
724778 char * dir = NULL ;
779+ struct command * commands ;
725780
726781 argv ++ ;
727782 for (i = 1 ; i < argc ; i ++ ) {
@@ -772,18 +827,17 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
772827 if (advertise_refs )
773828 return 0 ;
774829
775- read_head_info ();
776- if (commands ) {
830+ if ((commands = read_head_info ()) != NULL ) {
777831 const char * unpack_status = NULL ;
778832
779833 if (!delete_only (commands ))
780834 unpack_status = unpack ();
781- execute_commands (unpack_status );
835+ execute_commands (commands , unpack_status );
782836 if (pack_lockfile )
783837 unlink_or_warn (pack_lockfile );
784838 if (report_status )
785- report (unpack_status );
786- run_receive_hook (post_receive_hook );
839+ report (commands , unpack_status );
840+ run_receive_hook (commands , post_receive_hook );
787841 run_update_post_hook (commands );
788842 if (auto_gc ) {
789843 const char * argv_gc_auto [] = {
0 commit comments