2011-05-17 66 views
9

是否有支持文件名完成的bash完成脚本?我使用的主要是mercurial,在那里我可以键入:Git bash完成与文件名支持?

hg diff test/test_<tab> 

它会显示/完成所有修改后的测试文件。它适用于大多数子命令,即hg add <tab><tab>只会列出未跟踪的文件。它非常方便。

来自git contrib seam的bash脚本不支持这个。有没有其他的选择,或者你如何在命令行上使用git?

编辑2015年

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

+0

我通常首先使用'git status',然后知道要为'git diff'输入什么内容。 (但大多数情况下,我使用'gitk'查看差异。) – 2011-05-17 18:35:46

回答

13

所以,让我们看到了水银的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)似乎输出正确的事情(如果没有改名)。

尽管如此,它们在区分HEAD以外的任何东西时都没有用处。

一个更普遍的方式是使用

git diff --relative --name-only [--cached] [commit1] [commit2]] 

其中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> 

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 
} 

更新:貌似这个补丁不以这种形式通缉,因为当前的方式来完成的文件是更有益需要检查某个子目录是否有变化的人(例如,在差异输出可能为空时完成)。如果链接到某个配置变量(默认为当前行为),则可能会被接受。此外,缩进应适应标准(请参阅Junio C Hamano的答案)。

我可能会再试一试,但不能保证在不久的将来。如果其他人想要这样做,请随时取走我的代码,更改并重新提交。

3

这解决了git diff <tab>问题对我来说,把在的.bashrc如下:

alias gid='git diff' 
__gdiff() { 
    local cur prev opts 
    COMPREPLY=() 
    cur="${COMP_WORDS[COMP_CWORD]}" 
    prev="${COMP_WORDS[COMP_CWORD-1]}" 
    opts=$(git status --porcelain | grep '^.[^ ?]' | cut -b 4-) 

    case "${prev}" in 
     gid) 
      COMPREPLY=($(compgen -W "${opts}" -- ${cur})) 
      ;; 
    esac 
} 
complete -F __gdiff gid 

然后做gid <tab>,而不是git diff <tab>。它可能会被简化,但似乎可以很好地解决问题。

0

不是你想要的答案,但我想让你知道很快鱼(友好的交互式shell)会给你开箱即用的git文件名完成支持。它目前很快就会发布2.3.0版本。

https://github.com/fish-shell/fish-shell/issues/901
https://github.com/fish-shell/fish-shell/pull/2364
https://github.com/fish-shell/fish-shell/commit/c5c59d4acb00674bc37198468b5978f69484c628

如果你有一个这样的状态:

$ git status 
modified: ../README.md 
$ git add <tab> 
:/README.md 

enter image description here

您也可以只输入README,打标签,它会插入它你是否唯一匹配。 Friggin不错!

+0

请参阅我的2015年更新中的帖子:“git-completion.bash支持完整的文件名完成自〜1.8.2” – olt 2016-03-23 15:11:10

+0

啊,很酷,谢谢。 – 2016-03-24 15:08:54