如果在.bash_profile中使用别名,如何启用git命令的自动完成?

问题描述 投票:1回答:1

我在.bash_profile中有git别名,并希望在使用这些命令时启用自动完成(例如:自动完成分支名称)。如果我使用完整的git命令但是当我使用别名时,这对我有用。

我听说如果你使用通过.gitconfig配置的别名可以自动完成,但是这些别名强制使用git,而我在.bash_profile中配置的别名将“git”替换为“g”,这样更方便。

git
1个回答
4
投票

各种命令的bash完成通常包含在bash_completions包中或随各个命令提供。它们的安装位置在某种程度上取决于操作系统,在Ubuntu中它们被收集在各个地方,从/etc/bash_completion开始。此脚本源自全局bash.bashrc,并最终提供各种其他脚本,用于定义各种命令的完成。最终,他们都调用complete命令来定义何时调用完成。

git安装了/usr/share/bash-completion/completions/git(再次在Ubuntu,地点可能不同)的完成。该文件来自the git source repository并定义了各个命令的完成函数,并最终定义了一个__git_complete函数,该函数接受命令和完成函数并安装该命令的完成:

__git_complete git __git_main

上面添加了git的完成来调用__git_main(也在该文件中定义)。由于所有的完成都是源代码,因此所使用的函数都可以在shell中使用,因此您可以使用相同的调用将git完成添加到别名中:

__git_complete g __git_main

如果您的别名包含某个git子命令,请使用该文件中定义的各种子命令完成之一。如果你有一个别名ga来表示git add你将使用_git_add完成而不是:

__git_complete ga _git_add

请注意,__git_complete函数(可能是该文件中的所有函数)都是私有的,并不意味着直接使用。该功能标有相应的警告:

这不是一个公共职能;使用风险自负。

这基本上意味着,更新你的git和/或bash_completions可能会改变完成文件以及如何命名上述函数并且工作可能会改变,这会破坏你的设置。因此,如果您准备经常重做该设置,则应仅使用上述内容。

另请注意,您可能必须从.bashrc.profile明确获取git完成文件才能使函数可用:

source /usr/share/bash-completion/completions/git

特别案例

一些git完成实际上检查当前命令行以决定接下来要完成什么。其中的例子是任何完成遥控器或refspecs的东西,即fetch,pull,remote和push。在这种情况下,使用相应的函数完成别名是不够的,因为别名将隐藏实际的git命令,因此完成将不知道如何继续。作为评论的一个例子:

$ alias gpr='git pull --rebase'
$ __git_complete gpr _git_pull
$ gpr o[TAB]
$ gpr origin m[TAB]
$ gpr origin m

在这种情况下,遥控器(在这种情况下是原点)仍然可以完成,但refspec无法完成。这是由于命令行上缺少“pull”命令。

这种情况无法完全解决,但可以构建需要额外选项卡的变通方法。不是直接挂钩到git完成,而是定义一个包装器函数,首先使用所需的命令行扩展别名,然后传递以进一步完成:

function _gpr {
    if [ $COMP_CWORD = 1 ]
    then
        COMPREPLY=('pull --rebase ')
        return 0
    fi

    __git_func_wrap __git_main
}

包装器函数检查当前单词是否是第一个,并且在这种情况下将COMPREPLY变量设置为所需的命令行扩展(有关详细信息,请参阅the documentation for programmable completion)。请注意最后需要的额外空间,因为该函数将使用nospace选项安装,以防止自动插入空格。

然后安装包装函数作为所需别名的完成:

complete -o bashdefault -o default -o nospace -F _gpr gpr

-F _gpr参数指定要调用的包装函数和最后一个参数(gpr)要完成的命令(有关其他选项,请参阅the full documentation of the complete builtin)。

随着包装器完成,上面的会话现在变为:

$ gpr [TAB]
$ gpr pull --rebase o[TAB]
$ gpr pull --rebase origin m[TAB]
$ gpr pull --rebase origin master

在别名之后需要一个额外的选项卡,以首先扩展到之前完全隐藏在别名中的所需命令行。从那时起,完井工作按预期进行。

请注意,由于所需的命令行现在是实际命令行的一部分,因此别名应仅指向git而不指向git pull --rebase。这也是包装函数始终将完成传递给__git_main而不是单个子命令完成的原因。别名定义变为:

alias gpr=git

组合shell和git别名

上述特殊情况的一个很好的替代方案是组合shell和git别名。为完成目的,git完成扩展git别名(即用git config alias.<name> '<command>'创建的别名)。为实际命令配置git别名:

$ git config --global alias.pr 'pull --rebase'

然后为git安装一个速记shell别名:

$ alias g=git

并使用原始方法将其连接到__git_main完成:

$ __git_complete g __git_main

允许此会话:

$ g pr o[TAB]
$ g pr origin m[TAB]
$ g pr origin master
© www.soinside.com 2019 - 2024. All rights reserved.