2011-05-17 63 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