是否可以通过git别名覆盖git命令?

时间:2010-08-21 20:10:57

标签: git alias

我的〜/ .gitconfig是:

[alias]
        commit = "!sh commit.sh"

但是,当我输入 git commit 时,不会调用脚本。

是否可能,或者我必须使用其他别名?

5 个答案:

答案 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

2009年http://git.661346.n2.nabble.com/allowing-aliases-to-override-builtins-to-support-default-options-td2438491.html

Hamano replies

  
    

目前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" "$@"