Git 别名 - 分支名称命令行自动完成

34
如果我运行常规的git命令,比如git checkout,当按下tab键时,会显示分支名称的自动完成帮助信息。
我有一些以分支名称作为参数的git别名,我想知道是否有办法使分支名称的自动完成功能也适用于它们? 编辑: 只是为了从评论中提供一些澄清,直接映射的别名可以正常工作,例如:
ci = commit
co = checkout

有些情况下需要使用参数$1来处理复杂的内容,例如:

tagarchive = !f() { git tag archive/$1 origin/$1 && git push origin :$1 && git push origin archive/$1 && git branch -d $1; }; f

2
自动补全在我的别名上是有效的。你使用的是bash吗?你在哪个系统上?(操作系统,发行版,软件包管理器等)只是确认一下,你所说的“git别名”是指名为alias.foo的git配置条目,对吧? - kini
在Ubuntu上使用Bash。Git别名存储在配置文件中的[alias]中,是的。 - bcmcfc
1
@David,这解释了一些问题 - 我也有一些重命名的别名 - 我怀疑当别名做更多的事情而不是直接映射时,自动完成会停止工作。像 co (checkout) 这样的别名对我来说很好用。已更新问题。 - bcmcfc
似乎你的问题与git不太相关,而是更多地涉及到bash。你可能会发现这个链接有帮助:为别名命令提供Bash自动完成 - Yannick Blondeau
1
Git自动补全应该在Git 2.1(2014年8月)中更好地工作。请参见下面的答案:https://dev59.com/SWgu5IYBdhLWcg3wP01m#25099026 - VonC
显示剩余2条评论
2个回答

39

对于 git 别名,git 命令的自动补全函数 (__git())会调用 git config --get "alias.$1" 来确定相应的自动补全函数。这对于简单映射有效,但在更复杂的别名上会出错。

为了解决这个问题,可以定义一个名称与别名匹配的自动补全函数,例如 _git_tagarchive()。git 的自动补全函数将会调用该函数并用于自动补全。

例如:

[me@home]$ git tagarchive <TAB><TAB>
AUTHORS             gentleSelect/       .gitignore          LICENSE             test_multiple.html  
cron/               .git/               index.html          README.md  
[me@home]$ _git_tagarchive() {
> _git_branch  # reuse that of git branch
> }
[me@home]$ git tagarchive  <TAB><TAB>
enable_multiple          master                   origin/gh-pages          v0.1                     v0.1.3 
FETCH_HEAD               ORIG_HEAD                origin/HEAD              v0.1.1                   v0.1.3.1 
HEAD                     origin/enable_multiple   origin/master            v0.1.2 

如果需要更为持久的解决方案,只需将该函数定义添加到您的bashrc文件中即可,例如:

_git_tagarchive() 
{
    _git_branch
}

请注意,我只是简单地重用了 git branch 的自动补全功能;您可能希望将其更改为更合适的内容或编写自己的内容。

更多信息

此解决方案基于对 /etc/bash_completion.d/git 进行探索而确定。

通常,别名 git 命令由 __git_aliased_commands() 函数处理,该函数解析 git config --get "alias.$1" 的输出以决定要使用的自动补全函数。如果将更复杂的 shell 命令用作别名目标,则可以理解地破坏这种方法。

进一步查看后,似乎 git 的自动补全功能 (_git()) 通过在函数中简单地添加前缀 _git_ (其中命令中的连字符 (-) 替换为下划线) 来链接子命令的自动补全功能。这是在检查 __git_aliased_command() 之前完成的,因此我们可以使用它。

_git ()
{ 
   # .....
   local completion_func="_git_${command//-/_}"
   declare -f $completion_func >/dev/null && $completion_func && return

   local expansion=$(__git_aliased_command "$command")
   if [ -n "$expansion" ]; then
       completion_func="_git_${expansion//-/_}"
       declare -f $completion_func >/dev/null && $completion_func
   fi

}
我采用的方法是确保存在一个与您的别名匹配的函数,即_git_tagarchive()

那个很有效,感谢你详细的解释。 - bcmcfc
在提供的函数中,是否有可能禁用某些组件选项(我不希望它默认文件名完成)? - William Boman

5

2015年7月更新(Git 2.5):在contrib/completion/git-completion.bash中获取git别名更加容易。

请参见提交记录12bdc88提交记录e8f9e42(2015年5月10日),作者为SZEDER Gábor(szeder
(由Junio C Hamano -- gitster --于2015年5月22日合并至提交记录935d937

~~~~~~~~~~~~~~

在Git 2.1(2014年8月)中,使用复杂的Git别名时,自动补全功能应该会更好用。
请参见提交记录56f24e8,作者为Steffen Prohaska(sprohaska

自动补全:处理'!f() { ... }; f'和"!sh -c '...' -"别名

'!f() { ... }; f'和"!sh -c '....' -"是声明更复杂的别名的推荐模式(请参见Git Wiki)。
此提交记录使得自动补全功能能够处理它们。

在确定要使用哪个自动补全功能时,现在会跳过开括号或单引号,并继续搜索git命令。
例如,别名'!f() { git commit ... }'或"!sh -c 'git commit ...'"现在会触发提交自动补全功能。
以前,搜索在开括号或引号处停止,自动补全功能试图确定如何完成,这显然是无用的。

现在跳过了null命令':',因此可以将其用作声明所需自动补全样式的解决方法。

例如,以下别名:

!f() { : git commit ; if ... } f
!sh -c ': git commit; if ...' -

现在触发提交完成。

Shell函数声明现在可以在括号之前或之后添加空格,例如 '!f() ...' 和 '!f () ...' 都可以正常工作。


对我来说,使用git v2.17.1并不简单。我无论如何都不能在别名的值中使用;字符(即使转义)。最终我使用了&&代替——虽然含义不同,但与空命令组合时实际上没有区别。 - helvete

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接