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 );
@@ -591,7 +617,7 @@ static struct cmd_struct commands[] = {
591617 { "notes" , cmd_notes , RUN_SETUP },
592618 { "pack-objects" , cmd_pack_objects , RUN_SETUP },
593619#ifndef WITH_BREAKING_CHANGES
594- { "pack-redundant" , cmd_pack_redundant , RUN_SETUP | NO_PARSEOPT },
620+ { "pack-redundant" , cmd_pack_redundant , RUN_SETUP | NO_PARSEOPT | DEPRECATED },
595621#endif
596622 { "pack-refs" , cmd_pack_refs , RUN_SETUP },
597623 { "patch-id" , cmd_patch_id , RUN_SETUP_GENTLY | NO_PARSEOPT },
@@ -649,7 +675,7 @@ static struct cmd_struct commands[] = {
649675 { "verify-tag" , cmd_verify_tag , RUN_SETUP },
650676 { "version" , cmd_version },
651677#ifndef WITH_BREAKING_CHANGES
652- { "whatchanged" , cmd_whatchanged , RUN_SETUP },
678+ { "whatchanged" , cmd_whatchanged , RUN_SETUP | DEPRECATED },
653679#endif
654680 { "worktree" , cmd_worktree , RUN_SETUP },
655681 { "write-tree" , cmd_write_tree , RUN_SETUP },
@@ -670,11 +696,16 @@ int is_builtin(const char *s)
670696 return !!get_builtin (s );
671697}
672698
673- static void list_builtins (struct string_list * out , unsigned int exclude_option )
699+ static void list_builtins (struct string_list * out ,
700+ unsigned int include_option ,
701+ unsigned int exclude_option )
674702{
703+ if (include_option && exclude_option )
704+ BUG ("'include_option' and 'exclude_option' are mutually exclusive" );
675705 for (size_t i = 0 ; i < ARRAY_SIZE (commands ); i ++ ) {
676- if (exclude_option &&
677- (commands [i ].option & exclude_option ))
706+ if (include_option && !(commands [i ].option & include_option ))
707+ continue ;
708+ if (exclude_option && (commands [i ].option & exclude_option ))
678709 continue ;
679710 string_list_append (out , commands [i ].cmd );
680711 }
@@ -795,13 +826,29 @@ static void execv_dashed_external(const char **argv)
795826 exit (128 );
796827}
797828
829+ static int is_deprecated_command (const char * cmd )
830+ {
831+ struct cmd_struct * builtin = get_builtin (cmd );
832+ return builtin && (builtin -> option & DEPRECATED );
833+ }
834+
798835static int run_argv (struct strvec * args )
799836{
800837 int done_alias = 0 ;
801- struct string_list cmd_list = STRING_LIST_INIT_DUP ;
802- struct string_list_item * seen ;
838+ struct string_list expanded_aliases = STRING_LIST_INIT_DUP ;
803839
804840 while (1 ) {
841+ /*
842+ * Allow deprecated commands to be overridden by aliases. This
843+ * creates a seamless path forward for people who want to keep
844+ * using the name after it is gone, but want to skip the
845+ * deprecation complaint in the meantime.
846+ */
847+ if (is_deprecated_command (args -> v [0 ]) &&
848+ handle_alias (args , & expanded_aliases )) {
849+ done_alias = 1 ;
850+ continue ;
851+ }
805852 /*
806853 * If we tried alias and futzed with our environment,
807854 * it no longer is safe to invoke builtins directly in
@@ -851,35 +898,17 @@ static int run_argv(struct strvec *args)
851898 /* .. then try the external ones */
852899 execv_dashed_external (args -> v );
853900
854- seen = unsorted_string_list_lookup (& cmd_list , args -> v [0 ]);
855- if (seen ) {
856- struct strbuf sb = STRBUF_INIT ;
857- for (size_t i = 0 ; i < cmd_list .nr ; i ++ ) {
858- struct string_list_item * item = & cmd_list .items [i ];
859-
860- strbuf_addf (& sb , "\n %s" , item -> string );
861- if (item == seen )
862- strbuf_addstr (& sb , " <==" );
863- else if (i == cmd_list .nr - 1 )
864- strbuf_addstr (& sb , " ==>" );
865- }
866- die (_ ("alias loop detected: expansion of '%s' does"
867- " not terminate:%s" ), cmd_list .items [0 ].string , sb .buf );
868- }
869-
870- string_list_append (& cmd_list , args -> v [0 ]);
871-
872901 /*
873902 * It could be an alias -- this works around the insanity
874903 * of overriding "git log" with "git show" by having
875904 * alias.log = show
876905 */
877- if (!handle_alias (args ))
906+ if (!handle_alias (args , & expanded_aliases ))
878907 break ;
879908 done_alias = 1 ;
880909 }
881910
882- string_list_clear (& cmd_list , 0 );
911+ string_list_clear (& expanded_aliases , 0 );
883912
884913 return done_alias ;
885914}
0 commit comments