2828#define NEED_WORK_TREE (1<<3)
2929#define DELAY_PAGER_CONFIG (1<<4)
3030#define NO_PARSEOPT (1<<5) /* parse-options is not used */
31+ #define DEPRECATED (1<<6)
3132
3233struct cmd_struct {
3334 const char * cmd ;
@@ -51,7 +52,9 @@ const char git_more_info_string[] =
5152
5253static int use_pager = -1 ;
5354
54- static void list_builtins (struct string_list * list , unsigned int exclude_option );
55+ static void list_builtins (struct string_list * list ,
56+ unsigned int include_option ,
57+ unsigned int exclude_option );
5558
5659static void exclude_helpers_from_list (struct string_list * list )
5760{
@@ -88,7 +91,7 @@ static int list_cmds(const char *spec)
8891 int len = sep - spec ;
8992
9093 if (match_token (spec , len , "builtins" ))
91- list_builtins (& list , 0 );
94+ list_builtins (& list , 0 , 0 );
9295 else if (match_token (spec , len , "main" ))
9396 list_all_main_cmds (& list );
9497 else if (match_token (spec , len , "others" ))
@@ -99,6 +102,8 @@ static int list_cmds(const char *spec)
99102 list_aliases (& list );
100103 else if (match_token (spec , len , "config" ))
101104 list_cmds_by_config (& list );
105+ else if (match_token (spec , len , "deprecated" ))
106+ list_builtins (& list , DEPRECATED , 0 );
102107 else if (len > 5 && !strncmp (spec , "list-" , 5 )) {
103108 struct strbuf sb = STRBUF_INIT ;
104109
@@ -322,7 +327,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
322327 if (!strcmp (cmd , "parseopt" )) {
323328 struct string_list list = STRING_LIST_INIT_DUP ;
324329
325- list_builtins (& list , NO_PARSEOPT );
330+ list_builtins (& list , 0 , NO_PARSEOPT );
326331 for (size_t i = 0 ; i < list .nr ; i ++ )
327332 printf ("%s " , list .items [i ].string );
328333 string_list_clear (& list , 0 );
@@ -360,7 +365,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
360365 return (* argv ) - orig_argv ;
361366}
362367
363- static int handle_alias (struct strvec * args )
368+ static int handle_alias (struct strvec * args , struct string_list * expanded_aliases )
364369{
365370 int envchanged = 0 , ret = 0 , saved_errno = errno ;
366371 int count , option_count ;
@@ -371,6 +376,8 @@ static int handle_alias(struct strvec *args)
371376 alias_command = args -> v [0 ];
372377 alias_string = alias_lookup (alias_command );
373378 if (alias_string ) {
379+ struct string_list_item * seen ;
380+
374381 if (args -> nr == 2 && !strcmp (args -> v [1 ], "-h" ))
375382 fprintf_ln (stderr , _ ("'%s' is aliased to '%s'" ),
376383 alias_command , alias_string );
@@ -418,6 +425,25 @@ static int handle_alias(struct strvec *args)
418425 if (!strcmp (alias_command , new_argv [0 ]))
419426 die (_ ("recursive alias: %s" ), alias_command );
420427
428+ string_list_append (expanded_aliases , alias_command );
429+ seen = unsorted_string_list_lookup (expanded_aliases ,
430+ new_argv [0 ]);
431+
432+ if (seen ) {
433+ struct strbuf sb = STRBUF_INIT ;
434+ for (size_t i = 0 ; i < expanded_aliases -> nr ; i ++ ) {
435+ struct string_list_item * item = & expanded_aliases -> items [i ];
436+
437+ strbuf_addf (& sb , "\n %s" , item -> string );
438+ if (item == seen )
439+ strbuf_addstr (& sb , " <==" );
440+ else if (i == expanded_aliases -> nr - 1 )
441+ strbuf_addstr (& sb , " ==>" );
442+ }
443+ die (_ ("alias loop detected: expansion of '%s' does"
444+ " not terminate:%s" ), expanded_aliases -> items [0 ].string , sb .buf );
445+ }
446+
421447 trace_argv_printf (new_argv ,
422448 "trace: alias expansion: %s =>" ,
423449 alias_command );
@@ -590,7 +616,7 @@ static struct cmd_struct commands[] = {
590616 { "notes" , cmd_notes , RUN_SETUP },
591617 { "pack-objects" , cmd_pack_objects , RUN_SETUP },
592618#ifndef WITH_BREAKING_CHANGES
593- { "pack-redundant" , cmd_pack_redundant , RUN_SETUP | NO_PARSEOPT },
619+ { "pack-redundant" , cmd_pack_redundant , RUN_SETUP | NO_PARSEOPT | DEPRECATED },
594620#endif
595621 { "pack-refs" , cmd_pack_refs , RUN_SETUP },
596622 { "patch-id" , cmd_patch_id , RUN_SETUP_GENTLY | NO_PARSEOPT },
@@ -647,7 +673,7 @@ static struct cmd_struct commands[] = {
647673 { "verify-tag" , cmd_verify_tag , RUN_SETUP },
648674 { "version" , cmd_version },
649675#ifndef WITH_BREAKING_CHANGES
650- { "whatchanged" , cmd_whatchanged , RUN_SETUP },
676+ { "whatchanged" , cmd_whatchanged , RUN_SETUP | DEPRECATED },
651677#endif
652678 { "worktree" , cmd_worktree , RUN_SETUP },
653679 { "write-tree" , cmd_write_tree , RUN_SETUP },
@@ -668,11 +694,16 @@ int is_builtin(const char *s)
668694 return !!get_builtin (s );
669695}
670696
671- static void list_builtins (struct string_list * out , unsigned int exclude_option )
697+ static void list_builtins (struct string_list * out ,
698+ unsigned int include_option ,
699+ unsigned int exclude_option )
672700{
701+ if (include_option && exclude_option )
702+ BUG ("'include_option' and 'exclude_option' are mutually exclusive" );
673703 for (size_t i = 0 ; i < ARRAY_SIZE (commands ); i ++ ) {
674- if (exclude_option &&
675- (commands [i ].option & exclude_option ))
704+ if (include_option && !(commands [i ].option & include_option ))
705+ continue ;
706+ if (exclude_option && (commands [i ].option & exclude_option ))
676707 continue ;
677708 string_list_append (out , commands [i ].cmd );
678709 }
@@ -793,13 +824,29 @@ static void execv_dashed_external(const char **argv)
793824 exit (128 );
794825}
795826
827+ static int is_deprecated_command (const char * cmd )
828+ {
829+ struct cmd_struct * builtin = get_builtin (cmd );
830+ return builtin && (builtin -> option & DEPRECATED );
831+ }
832+
796833static int run_argv (struct strvec * args )
797834{
798835 int done_alias = 0 ;
799- struct string_list cmd_list = STRING_LIST_INIT_DUP ;
800- struct string_list_item * seen ;
836+ struct string_list expanded_aliases = STRING_LIST_INIT_DUP ;
801837
802838 while (1 ) {
839+ /*
840+ * Allow deprecated commands to be overridden by aliases. This
841+ * creates a seamless path forward for people who want to keep
842+ * using the name after it is gone, but want to skip the
843+ * deprecation complaint in the meantime.
844+ */
845+ if (is_deprecated_command (args -> v [0 ]) &&
846+ handle_alias (args , & expanded_aliases )) {
847+ done_alias = 1 ;
848+ continue ;
849+ }
803850 /*
804851 * If we tried alias and futzed with our environment,
805852 * it no longer is safe to invoke builtins directly in
@@ -849,35 +896,17 @@ static int run_argv(struct strvec *args)
849896 /* .. then try the external ones */
850897 execv_dashed_external (args -> v );
851898
852- seen = unsorted_string_list_lookup (& cmd_list , args -> v [0 ]);
853- if (seen ) {
854- struct strbuf sb = STRBUF_INIT ;
855- for (size_t i = 0 ; i < cmd_list .nr ; i ++ ) {
856- struct string_list_item * item = & cmd_list .items [i ];
857-
858- strbuf_addf (& sb , "\n %s" , item -> string );
859- if (item == seen )
860- strbuf_addstr (& sb , " <==" );
861- else if (i == cmd_list .nr - 1 )
862- strbuf_addstr (& sb , " ==>" );
863- }
864- die (_ ("alias loop detected: expansion of '%s' does"
865- " not terminate:%s" ), cmd_list .items [0 ].string , sb .buf );
866- }
867-
868- string_list_append (& cmd_list , args -> v [0 ]);
869-
870899 /*
871900 * It could be an alias -- this works around the insanity
872901 * of overriding "git log" with "git show" by having
873902 * alias.log = show
874903 */
875- if (!handle_alias (args ))
904+ if (!handle_alias (args , & expanded_aliases ))
876905 break ;
877906 done_alias = 1 ;
878907 }
879908
880- string_list_clear (& cmd_list , 0 );
909+ string_list_clear (& expanded_aliases , 0 );
881910
882911 return done_alias ;
883912}
0 commit comments