举个例子:

我是一个在mac上的bash v3.2.17,我使用的git安装通过macports与bash_completion变体。

当我输入git checkout m<tab>。例如,我把它完成了。

然而,我有一个别名git结帐,gco。当我输入gco m<tab>时,我没有得到自动完成的分支名称。

理想情况下,我想自动完成只是神奇地为我所有的别名工作。这可能吗?如果做不到这一点,我想为每个别名手动定制它。那么,我该怎么做呢?


当前回答

Felipe Contreras对Git补全功能(参见Git 2.30中的Zsh补全)非常积极,他提出(可能是Git 2.31, Q1 2021)一个公共函数将有助于别名自动补全。

他的建议:

Back in 2012 I argued for the introduction of a helper that would allow users to specify aliases like: git_complete gf git_fetch Back then there was pushback because there was no clear guideline for public functions (git_complete vs _git_complete vs _GIT_complete), and some aliases didn't actually work. Fast-forward to 2020 and there's still no guideline for public functions, and those aliases still don't work (even though I sent the fixes). This has not prevented people from using this function that is clearly needed to setup custom aliases (this page), and in fact it's the recommended way. But it is cumbersome that the user must type: __git_complete gf _git_fetch Or worse: __git_complete gk __gitk_main 8 years is more than enough time to stop waiting for the perfect to come; let's define a public function (with the same name) that is actually user-friendly: __git_complete gf git_fetch __git_complete gk gitk While also maintaining backwards compatibility. The logic is: If $2 exists, use it directly If not, check if __$2_main exists If not, check if _$2 exists If not, fail

其他回答

这个论坛页面展示了一个解决方案。

把这些行放到你的.bashrc或.bash_profile中:

# Author.: Ole J
# Date...: 23.03.2008
# License: Whatever

# Wraps a completion function
# make-completion-wrapper <actual completion function> <name of new func.>
#                         <command name> <list supplied arguments>
# eg.
#   alias agi='apt-get install'
#   make-completion-wrapper _apt_get _apt_get_install apt-get install
# defines a function called _apt_get_install (that's $2) that will complete
# the 'agi' alias. (complete -F _apt_get_install agi)
#
function make-completion-wrapper () {
    local function_name="$2"
    local arg_count=$(($#-3))
    local comp_function_name="$1"
    shift 2
    local function="
function $function_name {
    ((COMP_CWORD+=$arg_count))
    COMP_WORDS=( "$@" \${COMP_WORDS[@]:1} )
    "$comp_function_name"
    return 0
}"
    eval "$function"
}

# and now the commands that are specific to this SO question

alias gco='git checkout'

# we create a _git_checkout_mine function that will do the completion for "gco"
# using the completion function "_git"
make-completion-wrapper _git _git_checkout_mine git checkout

# we tell bash to actually use _git_checkout_mine to complete "gco"
complete -o bashdefault -o default -o nospace -F _git_checkout_mine gco

这个解决方案类似于balshetzer的脚本,但只有这个对我有效。(巴尔谢策的脚本对我的一些别名有问题。)

您还可以尝试使用Git别名。例如,在我的~/。gitconfig文件,我有一个看起来像这样的部分:

[alias]
        co = checkout

所以你可以输入git com <TAB>,这应该扩展到git co master,这是git checkout命令。

我也遇到了这个问题,并提出了这个代码片段。这将自动为您提供所有别名的补全。在声明所有(或任何)别名后运行它。

# wrap_alias takes three arguments:
# $1: The name of the alias
# $2: The command used in the alias
# $3: The arguments in the alias all in one string
# Generate a wrapper completion function (completer) for an alias
# based on the command and the given arguments, if there is a
# completer for the command, and set the wrapper as the completer for
# the alias.
function wrap_alias() {
  [[ "$#" == 3 ]] || return 1

  local alias_name="$1"
  local aliased_command="$2"
  local alias_arguments="$3"
  local num_alias_arguments=$(echo "$alias_arguments" | wc -w)

  # The completion currently being used for the aliased command.
  local completion=$(complete -p $aliased_command 2> /dev/null)

  # Only a completer based on a function can be wrapped so look for -F
  # in the current completion. This check will also catch commands
  # with no completer for which $completion will be empty.
  echo $completion | grep -q -- -F || return 0

  local namespace=alias_completion::

  # Extract the name of the completion function from a string that
  # looks like: something -F function_name something
  # First strip the beginning of the string up to the function name by
  # removing "* -F " from the front.
  local completion_function=${completion##* -F }
  # Then strip " *" from the end, leaving only the function name.
  completion_function=${completion_function%% *}

  # Try to prevent an infinite loop by not wrapping a function
  # generated by this function. This can happen when the user runs
  # this twice for an alias like ls='ls --color=auto' or alias l='ls'
  # and alias ls='l foo'
  [[ "${completion_function#$namespace}" != $completion_function ]] && return 0

  local wrapper_name="${namespace}${alias_name}"

  eval "
function ${wrapper_name}() {
  let COMP_CWORD+=$num_alias_arguments
  args=( \"${alias_arguments}\" )
  COMP_WORDS=( $aliased_command \${args[@]} \${COMP_WORDS[@]:1} )
  $completion_function
  }
"

  # To create the new completion we use the old one with two
  # replacements:
  # 1) Replace the function with the wrapper.
  local new_completion=${completion/-F * /-F $wrapper_name }
  # 2) Replace the command being completed with the alias.
  new_completion="${new_completion% *} $alias_name"

  eval "$new_completion"
}

# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias -p | sed -e 's/alias \([^=][^=]*\)='\''\([^ ][^ ]*\) *\(.*\)'\''/wrap_alias \1 \2 '\''\3'\'' /')"

unset wrap_alias

您可以将Tab绑定到alias-expand-line并在~/.inputrc中完成(它的默认动作)。要做到这一点,你首先需要将每个动作绑定到一个键,然后将它们链接在一起:

"\M-z":alias-expand-line
"\M-x":complete
TAB:"\M-z\M-x"

你可以使用任何你喜欢的组合键,我使用元键,因为它是免费的。更多信息见男子3阅读线。

现在,如果你打开一个新终端,输入别名:

gco m<TAB>

线路将被改造成

git checkout master

当然,即使不涉及别名,Tab也将照常工作。

这个问题有很多答案,就像我自己一样,我打赌很多读者都很困惑。对于我来说,我还需要让我的dotfile在多个平台上使用不同版本的Git。我也没有使用g=git的别名,而是将g定义为一个函数。

为了做到这一点,我必须把不同的答案拼凑成一个解决方案。虽然这重复了之前的答案,但我认为在我的船上的人可能会发现这个汇编很有用,就像我第一次遇到这个问题时一样。

这假设旧的和新的Git完成,Ubuntu默认,并在MacOS上brew安装Git。在后一种情况下,bash没有处理brew安装完成(稍后我将对此进行诊断)。

# Alias g to git

g() {
  if [[ $# > 0 ]]; then
    git "$@"
  else
    git status -sb
  fi
}

# Preload git completion in Ubuntu which is normally lazy loaded but we need
# the __git_wrap__git_main function available for our completion.
if [[ -e /usr/share/bash-completion/completions/git ]]; then
  source /usr/share/bash-completion/completions/git
elif [[ -e /usr/local/etc/bash_completion.d/git-completion.bash ]]; then
  source /usr/local/etc/bash_completion.d/git-completion.bash
fi

if command_exists __git_complete; then
  __git_complete g _git
elif command_exists __git_wrap__git_main; then
  complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g
fi