在我的zsh
shell 中,我根据我是否在git
存储库内动态更改提示。我正在使用以下 git 命令来检查:
if $(git rev-parse --is-inside-work-tree >/dev/null 2>&1); then
...
现在我还想区分当前目录是否被忽略git
。所以我在我的if
声明中又添加了一项检查:
if $(git rev-parse --is-inside-work-tree >/dev/null 2>&1) && ! $(git check-ignore . >/dev/null 2>&1); then
...
这工作正常,但我想知道是否可以将其简化为一个git
命令。由于提示符每次都会刷新ENTER,因此在某些速度较慢的机器上,它往往会显着减慢 shell 的速度。
更新
@Stephen Kitt 接受的解决方案效果很好,但以下情况除外:
我正在跨文件系统使用存储库。假设 git 驻留在/.git
(因为我想跟踪 中的配置文件/etc
),但我也想跟踪 中的一些文件/var/foo
,这是一个不同的分区/文件系统。
当我位于/
并执行以下命令时,一切都按预期工作,并且我得到返回代码1
(因为/var/foo
正在跟踪):
# git check-ignore -q /var/foo
但是当我位于 中的任何位置时/var
,相同的命令会失败,并显示错误代码128
和以下错误消息:
# git check-ignore -q /var/foo
fatal: not a git repository (or any parent up to mount point /)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
但我认为这只是check-ignore
命令的问题。否则 git 似乎可以在文件系统上正常工作。我可以/var/foo
很好地跟踪文件。
预期的行为应该是git check-ignore -q /var/foo
返回1
,如果没有被跟踪,则git check-ignore -q /var/bar
返回。0
我该如何解决这个问题?
答案1
git check-ignore .
.
如果不在存储库中(或发生任何其他错误),则会失败并显示退出代码 128 git
,并且仅当不忽略路径时才会显示退出代码 1。所以你只能检查后者:
git check-ignore -q . 2>/dev/null; if [ "$?" -ne "1" ]; then ...
在 内部,您正在处理git 存储库中被忽略或不被忽略的then
情况。.
要使其跨文件系统边界工作,请设置GIT_DISCOVERY_ACROSS_FILESYSTEM
到true
:
GIT_DISCOVERY_ACROSS_FILESYSTEM=true git check-ignore -q . 2>/dev/null; if [ "$?" -ne "1" ]; then ...
答案2
首先应该是:
if
git rev-parse --is-inside-work-tree >/dev/null 2>&1 &&
! git check-ignore . >/dev/null 2>&1
then...
命令替换 ( $(...)
) 是检索命令的输出。在这里,当您将其重定向到时没有输出/dev/null
,如果有,它将被视为要执行的命令(并检查其退出状态)。
请注意,仅当第一个命令成功时才会运行第二个命令。
@StephenKitt 展示了如何将这两个命令分解为一个git
命令,但如果这仍然对性能没有帮助,您始终可以将信息缓存在关联数组中。
typeset -A is_git # declared globally in your ~/.zshrc
if (( ! $+is_git[$PWD] )); then
git check-ignore -q . 2> /dev/null
is_git[$PWD]=$(( $? == 1 ))
fi
if (( $is_git[$PWD] )); then...
如果您重命名目录、删除.git
目录或更改忽略文件的列表,该缓存可能会变得过时。您可以使用is_git=()
或 重新启动zsh
使其无效exec zsh
。
另一种选择是仅在使用挂钩输入目录时进行检查chpwd
:
check_git() {
git check-ignore -q . 2> /dev/null
(( is_git = $? == 1 ))
}
chpwd_functions+=(check_git)
然后,在您的提示例程中,只需执行以下操作:
if (( is_git )); then...