用文件名支持Git bash-completion?

olt*_*olt 10 git bash bash-completion

是否有支持文件名完成的bash-completion脚本?我主要使用mercurial,我可以输入:

hg diff test/test_<tab>
Run Code Online (Sandbox Code Playgroud)

它将显示/完成所有修改过的测试文件.它适用于大多数子命令,即hg add <tab><tab>只列出未跟踪的文件.这真的很方便.

来自git contrib seams的bash脚本不支持此功能.有没有其他选择,或者你如何在命令行上使用git?

编辑2015

git-completion.bash支持完整的文件名完成,因为~1.8.2

Paŭ*_*ann 13

那么,让我们看看Mercurial bash完成脚本是如何做到这一点的.

这是重要的部分:

_hg_status()
{
    local files="$(_hg_cmd status -n$1 .)"
    local IFS=$'\n'
    COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
}
Run Code Online (Sandbox Code Playgroud)

它在这里被调用:

_hg_command_specific()
{
    case "$cmd" in 
    [...]
    diff)
        _hg_status "mar"
    ;;
    [...]
    esac
    return 0
}
Run Code Online (Sandbox Code Playgroud)

因此,它只是一个调用hg status -nmar,并使用输出作为完成文件列表.

我认为将类似的东西修补到git完成脚本中并不太难- 我们必须在__git_diff这里修改不做纯文件名+分支完成,而是调用git status.


命令

git status --porcelain | grep '^.[^ ?]' | cut -b 4-
Run Code Online (Sandbox Code Playgroud)

(为git diff --cached)和

git status --porcelain | grep '^[^ ?]' | cut -b 4-
Run Code Online (Sandbox Code Playgroud)

(git diff似乎)输出正确的东西(如果没有重命名).

但是,当它们传播到除HEAD以外的任何东西时,它们都没用.

更通用的方法是使用

git diff --relative --name-only [--cached] [commit1] [commit2]]
Run Code Online (Sandbox Code Playgroud)

where commit1commit2(也许--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>
Run Code Online (Sandbox Code Playgroud)

将此作为补丁提交给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
}
Run Code Online (Sandbox Code Playgroud)

更新:在这种形式下看起来不需要此补丁,因为当前完成文件的方式对于想要检查某些子目录中是否有更改的人(例如,当diff输出可能为空时完成)更有用.如果链接到某个配置变量(默认为当前行为),则可能会被接受.此外,缩进应该适应标准(参见Junio C Hamano的答案).

我可能会采取另一种方式,但不能在不久的将来保证这一点.如果其他人想要这样做,请随意接受我的代码,更改并再次提交.