自定义 Git “bang” 别名的 Zsh 完成 - Git 分支名称

11

我有一个Git别名update,我想要添加分支名称自动补全功能。该别名定义如下:

[alias]
        update = "!f() { git push . origin/$1:$1; }; f"

(它会更新本地跟踪分支,而无需检出该分支。虽然不是特别重要,但与具体问题无关。)

我希望命令能够为其$1参数的现有分支名称提供制表符自动完成。我知道可以定义一个名为_git-update的函数来控制完成,但我缺少一些使它正常工作的组成部分:

_git-update ()
{
  ***some-function-here*** "$(__git_branch_names)"
}

我正在使用OS X上通过brew install zsh-completions安装的补全功能,这是在https://github.com/zsh-users/zsh-completions设置的。

(这个问题直接类比于https://dev59.com/t53ha4cB1Zd3GeqPXJ-F#41307951,但针对的是Zsh而不是Bash。)


@Kache:你使用的Git版本是什么?Git 2.31最近改进了分支完成功能:https://stackoverflow.com/a/66192741/6309 - VonC
最近,我没有Git版本的限制。 - Kache
4个回答

4

可能有点过早,但这个正在运作:

# provides completion options similar to git branch/rebase/log
_complete_like_git_branch() {
  __gitcomp_nl_append "FETCH_HEAD"
  __gitcomp_nl_append "HEAD"
  __gitcomp_nl_append "ORIG_HEAD"
  __gitcomp_nl_append "$(__git_heads)"
  __gitcomp_nl_append "$(__git_remote_heads)"
  __gitcomp_nl_append "$(__git_tags)"
  __gitcomp_nl_append "$(__git_complete_refs)"
}

_git_rebase_chain() { _complete_like_git_branch }

# my git "bang" alias of git log
_git_lgk() { _complete_like_git_branch }

参考资料:contrib/completion/git-completion.bash

可能的改进:

  • 上述方法是否规范正确?即在~/.zshrc中使用全局shell函数?
  • 选项与git rebase和git log非常相似,但它们是否完全相同

2

如果您想要与现有的 git 子命令(已知于完成系统中)相同的完成功能,最简单的方法如下:

[alias]
    update = "!f() { : git branch ; git push . origin/$1:$1; }; f"

使用空命令(:)后跟git子命令(例如git branch),可以告诉git自动补全系统使用子命令的自动补全来完成您的别名。
这个功能已经内置于git别名系统中,使用它意味着您不必担心shell的差异。

1
谢谢,如果我能让它工作就太好了——现在我的别名已经完全按照上述方式描述,但似乎在 git 版本 2.36.1 下无法完整地执行。是否还有其他因素在起作用,或者我需要启用其他东西吗? - Ken Williams
我能想到的唯一一件事,@Ken,是有些系统会为git打包他们自己的完成器,也许你的系统正在使用不支持空命令完成规范的非本地完成器。不幸的是,我还没有找到如何获取zsh使用哪个完成器的信息(他们的文档非常不友好,而且他们有两个不同的完成系统 叹气)。 - DylanYoung
就我个人而言,使用zsh 5.9和Git 2.39.2时,上述别名的参数仍然能够成功地与文件名配合完成。 - VZ.

0
我使用这个函数将工作分支附加到我的PS1中:
    parse_git_branch() {
        git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
    }


0

看起来 Git 源中的补全与 zsh 实际使用的补全不同,至少对于 zsh Debian 包而言。该包安装了 /usr/share/zsh/functions/Completion/Unix/_git,其中在开头附近的注释中解释了如何自定义补全,并且只需要定义以下函数:

_git-update() { __git_branch_names }

(当然可以/应该使其自动加载)。

顺便说一句,我希望在我的别名中避免完成当前分支名称,并且我无法看到在使用__git_branch_names时如何排除它,所以我最终做了这个替代:

_git-my-alias () {
        head=$(git symbolic-ref HEAD)
        for b in $(ls -1 $(git rev-parse --git-dir)/refs/heads)
        do
                if [[ "refs/heads/$b" != $head ]]
                then
                        compadd $b
                fi
        done
}

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