Skip to content

Commit bf68b11

Browse files
LemmingAvalanchegitster
authored andcommitted
git: allow alias-shadowing deprecated builtins
git-whatchanged(1) is deprecated and you need to pass `--i-still-use-this` in order to force it to work as before. There are two affected users, or usages: 1. people who use the command in scripts; and 2. people who are used to using it interactively. For (1) the replacement is straightforward.[1] But people in (2) might like the name or be really used to typing it.[3] An obvious first thought is to suggest aliasing `whatchanged` to the git-log(1) equivalent.[1] But this doesn’t work and is awkward since you cannot shadow builtins via aliases. Now you are left in an uncomfortable limbo; your alias won’t work until the command is removed for good. Let’s lift this limitation by allowing *deprecated* builtins to be shadowed by aliases. The only observed demand for aliasing has been for git-whatchanged(1), not for git-pack-redundant(1). But let’s be consistent and treat all deprecated commands the same. [1]: git log --raw --no-merges With a minor caveat: you get different outputs if you happen to have empty commits (no changes)[2] [2]: https://lore.kernel.org/git/[email protected]/ [3]: https://lore.kernel.org/git/BL3P221MB0449288C8B0FA448A227FD48833AA@BL3P221MB0449.NAMP221.PROD.OUTLOOK.COM/ Based-on-patch-by: Jeff King <[email protected]> Signed-off-by: Kristoffer Haugsbakk <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b4f9282 commit bf68b11

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

Documentation/config/alias.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ alias.*::
33
after defining `alias.last = cat-file commit HEAD`, the invocation
44
`git last` is equivalent to `git cat-file commit HEAD`. To avoid
55
confusion and troubles with script usage, aliases that
6-
hide existing Git commands are ignored. Arguments are split by
6+
hide existing Git commands are ignored except for deprecated
7+
commands. Arguments are split by
78
spaces, the usual shell quoting and escaping are supported.
89
A quote pair or a backslash can be used to quote them.
910
+

git.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,12 +824,29 @@ static void execv_dashed_external(const char **argv)
824824
exit(128);
825825
}
826826

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+
827833
static int run_argv(struct strvec *args)
828834
{
829835
int done_alias = 0;
830836
struct string_list expanded_aliases = STRING_LIST_INIT_DUP;
831837

832838
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+
}
833850
/*
834851
* If we tried alias and futzed with our environment,
835852
* it no longer is safe to invoke builtins directly in

t/t0014-alias.sh

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@ test_expect_success 'looping aliases - internal execution' '
2727
test_grep "^fatal: alias loop detected: expansion of" output
2828
'
2929

30+
test_expect_success 'looping aliases - deprecated builtins' '
31+
test_config alias.whatchanged pack-redundant &&
32+
test_config alias.pack-redundant whatchanged &&
33+
cat >expect <<-EOF &&
34+
${SQ}whatchanged${SQ} is aliased to ${SQ}pack-redundant${SQ}
35+
${SQ}pack-redundant${SQ} is aliased to ${SQ}whatchanged${SQ}
36+
fatal: alias loop detected: expansion of ${SQ}whatchanged${SQ} does not terminate:
37+
whatchanged <==
38+
pack-redundant ==>
39+
EOF
40+
test_must_fail git whatchanged -h 2>actual &&
41+
test_cmp expect actual
42+
'
43+
3044
# This test is disabled until external loops are fixed, because would block
3145
# the test suite for a full minute.
3246
#
@@ -55,4 +69,30 @@ test_expect_success 'tracing a shell alias with arguments shows trace of prepare
5569
test_cmp expect actual
5670
'
5771

72+
can_alias_deprecated_builtin () {
73+
cmd="$1" &&
74+
# some git(1) commands will fail for `-h` (the case for
75+
# git-status as of 2025-09-07)
76+
test_might_fail git status -h >expect &&
77+
test_file_not_empty expect &&
78+
test_might_fail git -c alias."$cmd"=status "$cmd" -h >actual &&
79+
test_cmp expect actual
80+
}
81+
82+
test_expect_success 'can alias-shadow deprecated builtins' '
83+
for cmd in $(git --list-cmds=deprecated)
84+
do
85+
can_alias_deprecated_builtin "$cmd" || return 1
86+
done
87+
'
88+
89+
test_expect_success 'can alias-shadow via two deprecated builtins' '
90+
# some git(1) commands will fail... (see above)
91+
test_might_fail git status -h >expect &&
92+
test_file_not_empty expect &&
93+
test_might_fail git -c alias.whatchanged=pack-redundant \
94+
-c alias.pack-redundant=status whatchanged -h >actual &&
95+
test_cmp expect actual
96+
'
97+
5898
test_done

0 commit comments

Comments
 (0)