问题
我有以下内容
git reset HEAD^ half_entered_file_n<Tab>
此时,我希望 half_entered_file_name.txt 能够通过 Tab 完成。
我自己的调查
如果我写的话,Tab 补全就可以正常工作
git reset HEAD\^ ...
而是转义“^”。
将“^”写为最后一个字符似乎不会影响自动完成,除非也存在 HEAD:
#autocomplete works
git reset RANDOM^ half_entered_file_n<Tab> #works
Zsh 配置
我正在使用 Oh-my-zsh。在 oh-my-zsh 之上,我配置了以下可能相关的内容:
# Let <TAB> auto completion add a slash at the end instead of space (like BASH)
zstyle ':completion:*' special-dirs true
# Unless this option is set, you can't write git checkout HEAD^^ without escaping ^ as \^ in zsh
setopt NO_NOMATCH
# Standard git plugins
plugins=(git git-extras)
为了完整起见,这是我的配置
我在 OSX 上的 iTerm2 中运行它。
谢谢!
更新
我已经找到了一些半解决方案,但没有一个能够达到“已回答”的状态,这基本上使它们成为非解决方案。
compdef -d git
在 .zshrc 中设置正如“穴居人”所建议的- 解决:现在 HEAD^ 不再破坏文件自动完成。
- 缺点:git 命令自动完成功能不再起作用。
- 使用接受“ralphtheninja”对此问题的回答
- 解决:应该替换文件完成列表的生成方式,这样可以解决问题。
- 缺点:不起作用。看来 git-completion.zsh/.bash 已经改变了语法。
我对 shell 脚本不够了解,无法确切了解 git-completion.zsh/.bash 中发生了什么,以及这是否是导致问题发生的原因。
答案1
为什么你不应该假设
长期以来,我一直假设我的 zsh 配置中的 git 补全来自/usr/local/share/git-core/contrib/completion/
,特别是来自git-completion.zsh
甚至git-completion.bash
。我猜我之所以这样假设是因为大多数搜索都会产生谈论这些文件的结果。然而,我没有明确包含任何这些文件,长期以来,我只是猜测 oh-my-zsh 包含它们。
但...
我们不再在堪萨斯了
直到我使用通过 启用的 zsh 方法跟踪时setopt xtrace
,我才意识到(通过谷歌搜索一些方法名称)正在使用的脚本实际上是/usr/local/share/zsh/functions/_git
。我以前曾使用过XCode Instruments.app监视文件系统上哪些脚本正在被访问,但当时没有弄清楚(输出非常详细,还显示来自其他应用程序的访问)。
这是怎么回事?
痕迹表明了这一点(前方有部分痕迹!)
git reset HEAD <TAB>
...
+__git_tree_files:17> tree=HEAD
+__git_tree_files:18> tree_files+=+__git_tree_files:18> _call_program tree-files git ls-tree --name-only -z HEAD ./
+__git_tree_files:18> tree_files+=( first second third )
和
git reset HEAD^ <TAB>
...
+__git_tree_files:17> tree=HEAD^
+__git_tree_files:18> tree_files+=+__git_tree_files:18> _call_program tree-files git ls-tree --name-only -z 'HEAD^' ./
+__git_tree_files:18> tree_files+=( )
那个空的tree_files
看上去很可疑。
在第 6058 行/usr/local/share/zsh/functions/_git
我们发现
tree_files+=(${(ps:\0:)"$(_call_program tree-files git ls-tree $extra_args --name-only -z $tree $Path 2>/dev/null)"})
我们绝对需要转义该$tree
变量。说了又做了:
tree_files+=(${(ps:\0:)"$(_call_program tree-files git ls-tree $extra_args --name-only -z ${(q)tree} $Path 2>/dev/null)"})
结语
此脚本中还存在一些错误(例如,的文件列表git reset <tree-ish>
基于<tree-ish>
,而它应该基于 HEAD。现在我知道在哪里修复它们了!
更新
也可以从 git 运行完成脚本。你可以按照这个答案来做到这一点。