我的〜/ .gitconfig是:
[alias]
commit = "!sh commit.sh"
但是,当我输入 git commit 时,不会调用脚本。
是否可能,或者我必须使用其他别名?
答案 0 :(得分:40)
这是不可能的
这是我克隆的git.git:
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;
}
所以它不可能。 (handle_internal_command
如果找到命令,则调用exit
。
您可以通过更改行的顺序并在handle_alias
调用exit
(如果找到别名)时在您的来源中解决此问题。
答案 1 :(得分:21)
如前所述,不可能使用git别名来覆盖git命令。但是,可以使用shell别名覆盖git命令。对于任何POSIXy shell(即不是MS cmd
),编写一个执行所需修改行为的简单可执行脚本并设置shell别名。在我的.bashrc
(Linux)和.bash_profile
(Mac)中,我有
export PATH="~/bin:$PATH"
...
alias git='my-git'
在我的~/bin
文件夹中,我有一个名为my-git
的可执行Perl脚本,用于检查第一个参数(即git命令)是否为clone
。看起来基本上是这样的:
#!/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...
我的可配置性更强一些,但你明白了。
答案 2 :(得分:17)
我选择用bash函数来解决这个问题。如果我拨打git clone
,它会将呼叫重定向到git cl
,这是我的别名,其中添加了一些开关。
function git {
if [[ "$1" == "clone" && "$@" != *"--help"* ]]; then
shift 1
command git cl "$@"
else
command git "$@"
fi
}
答案 3 :(得分:14)
不仅不可能,还有WONTFIX
目前git不允许别名覆盖内置。一世 理解这背后的原因,但我不知道它是否过分 保守。
不是。
大多数shell支持使用别名覆盖命令,我不确定 为什么git需要比shell更保守。
因为在脚本中使用时,理智的shell不会扩展别名,并且 提供了一种方便的方法,甚至可以从命令行中击败别名。
$ alias ls='ls -aF' $ echo ls >script $ chmod +x script
并比较:
$ ./script $ ls $ /bin/ls
答案 4 :(得分:0)
FWIW,我通过编写以下~/bin/git
包装器(例如,检查~/bin/git-clone
)来解决此问题(好的,“已解决” ...),并调用那个,而不是内置的。
[注意:对于任何“聪明的” bash行为,我深表歉意,但是在您通过了两个帮助器函数之后-一个用于扩展符号链接,一个用于在$ PATH中搜索被包装的可执行文件-实际的脚本本身就是三行代码™...所以我想我一点都不后悔,呵呵!]
#!/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" "$@"