我在.bash_profile中有git别名,并希望在使用这些命令时启用自动完成(例如:自动完成分支名称)。如果我使用完整的git命令但是当我使用别名时,这对我有用。
我听说如果你使用通过.gitconfig配置的别名可以自动完成,但是这些别名强制使用git,而我在.bash_profile中配置的别名将“git”替换为“g”,这样更方便。
各种命令的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别名。为完成目的,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