那么,让我们看看 Mercurial bash 完成脚本是如何做到这一点的。
这是important part:
_hg_status()
{
local files="$(_hg_cmd status -n$1 .)"
local IFS=$'\n'
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
}
它被称为here:
_hg_command_specific()
{
case "$cmd" in
[...]
diff)
_hg_status "mar"
;;
[...]
esac
return 0
}
因此,它只是对hg status -nmar 的调用,并将输出用作完成的文件列表。
我认为将类似的东西修补到git completion script 中不会太难 - 我们必须在此处修改__git_diff 以不执行普通文件名+分支完成,而是调用git status。
命令
git status --porcelain | grep '^.[^ ?]' | cut -b 4-
(对于git diff --cached)和
git status --porcelain | grep '^[^ ?]' | cut -b 4-
(对于git diff)似乎输出了正确的东西(如果没有重命名)。
不过,当 diff 到 HEAD 以外的任何东西时,它们都没有用。
更通用的方法是使用
git diff --relative --name-only [--cached] [commit1] [commit2]]
其中commit1 和commit2(可能还有--cached)来自已经给出的diff 命令行。
我在 bash 中实现了上面概述的想法,并修补到 git-completion.bash。如果您不想更改您的git-completion.bash,请将这两个函数添加到某个 bash 文件中,并在原始git-completion.bash 之后获取它。它现在应该可以使用像
这样的命令了
git diff -- <tab>
git diff --cached -- <tab>
git diff HEAD^^ -- <tab>
git diff origin/master master -- <tab>
我submitted this 作为 git 邮件列表的补丁,让我们看看由此产生的结果。 (我会在收到反馈时更新这个答案。)
# Completion for the file argument for git diff.
# It completes only files actually changed. This might be useful
# as completion for other commands as well.
#
# The idea comes from the bash completion for Mercurial (hg),
# which does something similar (but more simple, only difference of
# working directory to HEAD and/or index, if I understand right).
# It (the idea) was brought to us by the question
# http://stackoverflow.com/q/6034472/600500
# from "olt".
__git_complete_changed_files()
{
#
# We use "git diff --name-only --relative" to generate the list,
# but this needs the same --cached and <commit> arguments as the
# command line being constructed.
#
# first grab arguments like --cached and any commit arguments.
local -a args=()
local finish=false
for (( i=1 ; i < cword ; i++)) do
local current_arg=${words[$i]}
# echo checking $current_arg >&2
case $current_arg in
--cached)
args+=( $current_arg )
;;
--)
# finish parsing arguments, the rest are file names
break
;;
-*)
# other options are ignored
;;
*)
if git cat-file -e $current_arg 2> /dev/null
then
case $( git cat-file -t $current_arg ) in
commit|tag)
# commits and tags are added to the command line.
args+=( $current_arg )
# echo adding $current_arg >&2
;;
*)
esac
fi
;;
esac
done
# now we can call `git diff`
COMPREPLY=( $( compgen \
-W "$( git diff --name-only --relative "${args[@]}" -- )" -- $cur ) )
}
_git_diff ()
{
if __git_has_doubledash
then
# complete for the file part: only changed files
__git_complete_changed_files
else
case "$cur" in
--*)
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
--base --ours --theirs --no-index
$__git_diff_common_options
"
return
;;
esac
__git_complete_revlist_file
fi
}
更新: 看起来这种形式不需要此补丁,因为当前完成文件的方法对于想要检查某些子目录中是否有更改的人更有用(例如,完成时diff 输出可能为空)。如果链接到某个配置变量(默认为当前行为),它可能会被接受。此外,缩进应该适应标准(参见Junio C Hamano的答案)。
我可能会再做一次,但不能保证在不久的将来会这样做。如果其他人想做,请随时拿走我的代码,更改并再次提交。