static int run_argv(int *argcp, const char ***argv)
{
int done_alias = 0;
while (1) {
/* See if it's an internal command */
handle_internal_command(*argcp, *argv);
/* .. then try the external ones */
execv_dashed_external(*argv);
/* It could be an alias -- this works around the insanity
* of overriding "git log" with "git show" by having
* alias.log = show
*/
if (done_alias || !handle_alias(argcp, argv))
break;
done_alias = 1;
}
return done_alias;
}
#!/usr/bin/env perl
use strict;
use warnings;
my $path_to_git = '/usr/local/bin/git';
exit(system($path_to_git, @ARGV))
if @ARGV < 2 or $ARGV[0] ne 'clone';
# Override git-clone here...
#!/usr/bin/env bash
###########################
### UTILITY FUNCTIONS ### ...from my .bashrc
###########################
#
# deref "/path/with/links/to/symlink"
# - Returns physical path for specified target
#
# __SUPER__
# - Returns next "$0" in $PATH (that isn't me, or a symlink to me...)
deref() {
( # Wrap 'cd's in a sub-shell
local target="$1"
local counter=0
# If the argument itself is a link [to a link, to a link...]
# NOTE: readlink(1) is not defined by POSIX, but has been shown to
# work on at least MacOS X, CentOS, Ubuntu, openSUSE, and OpenBSD
while [[ -L "$target" ]]; do
[[ $((++counter)) -ge 30 ]] && return 1
cd "${target%/*}"; target="$(readlink "$target")"
done
# Expand parent directory hierarchy
cd "${target%/*}" 2>/dev/null \
&& echo "$(pwd -P)/${target##*/}" \
|| echo "$([[ $target != /* ]] && echo "$(pwd -P)/")$target"
)
}
__SUPER__() {
local cmd="${1:-${0##*/}}"
local me="$(deref "$0")"
# NOTE: We only consider symlinks... We could check for hardlinks by
# comparing device+inode, but stat(1) has portability problems
local IFS=":"
for d in $PATH; do
[[ -x "$d/$cmd" ]] && [[ "$(deref "$d/$cmd")" != "$me" ]] \
&& { echo "$d/$cmd"; return; }
done
# else...
return 1
}
########################################################################
# (1) First, figure out which '$0' we *WOULD* have run...
GIT="$(__SUPER__)" || { echo "${0##*/}: command not found" >&2; exit 1; }
# (2) If we have a "~/bin/git-${command}" wrapper, then
# prepend '.../libexec/git-core' to $PATH and run it
[[ -f "${HOME}/bin/git-$1" ]] &&
PATH="$PATH:$( "$GIT" --exec-path )" \
exec "${HOME}/bin/git-$1" "${@:2}"
# (3) Else fall back to the regular 'git'
exec "$GIT" "$@"
6条答案
按热度按时间sycxhyv71#
这不可能
这是我的git克隆版本。
所以这是不可能的。(
handle_internal_command
如果找到命令就调用exit
)。您可以通过更改行的顺序并在
handle_alias
找到别名时使其调用exit
来在源代码中解决这个问题。ttcibm8c2#
我选择使用bash函数来解决这个问题,如果我调用
git clone
,它会将调用重定向到git cl
,这是我的别名,添加了一些开关。g9icjywg3#
如前所述,不可能使用git别名来覆盖git命令,但是可以使用shell别名来覆盖git命令。对于任何POSIX shell(即不是MS
cmd
),编写一个简单的可执行脚本来执行所需的修改行为,并设置shell别名。在我的.bashrc
(Linux)和.bash_profile
(Mac)中,我有在我的
~/bin
文件夹中,我有一个可执行的Perl脚本my-git
,它检查第一个参数(即git命令)是否为clone
。我的是一个更可配置的一点,但你明白的想法。
31moq8wy4#
在2009年
Hamano replies:
目前git不允许别名覆盖内置函数,我理解这背后的原因,但我怀疑这是否过于保守。
它不是。
大多数shell支持用别名覆盖命令,我不知道为什么git需要比shell更保守。
因为sane shell在脚本中使用时不会展开别名,并且提供了一种即使从命令行也能消除别名的简便方法。
并比较:
knsnq2tg5#
现在,我通过编写下面的
~/bin/git
Package 器解决了这个问题(好吧,“解决了它”...),该 Package 器检查~/bin/git-clone
,并调用that而不是内置函数。[NOTE:我为任何“聪明”的害羞表示歉意,但是在您通过两个helper函数之后--一个用于扩展符号链接,一个用于搜索$PATH以查找要 Package 的可执行文件--实际的脚本本身只是Three Lines of Code™......所以我想我并不感到抱歉,呵呵!]
deyfvvtc6#
这里还有另一个变通方法,它不依赖于 * 实际上 * 覆盖任何东西,而是依赖于滥用自动完成。这感觉比 Package git更安全,更透明。
由于我从不键入完整的命令名,因此定义别名作为要覆盖的命令的前缀就足够了。
例如,要用别名覆盖
git show-branch
,并且知道我通常键入git show-<Tab>
,我定义了show-br
别名来定制show-branch
行为。对于OP的示例
git commit
,我通常键入git com<Tab>
,因此git comm
将是正确的解决方案。这种策略有几个优点: