10

ファイル名の補完をサポートする bash 補完スクリプトはありますか? 私は主にmercurialを使用しており、次のように入力できます。

hg diff test/test_<tab>

変更されたすべてのテストファイルを表示/完了します。ほとんどのサブコマンドで機能します。つまり、hg add <tab><tab>追跡されていないファイルのみを一覧表示します。本当に便利です。

git contrib の bash スクリプトはこれをサポートしていません。代替手段はありますか、またはコマンドラインで git をどのように操作しますか?

編集 2015

git-completion.bash~1.8.2以降、完全なファイル名の補完をサポート

4

4 に答える 4

13

それでは、Mercurialのbash完了スクリプトがこれをどのように行うかを見てみましょう。

これは重要な部分です:

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

ここで呼ばれます:

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

したがって、これは単にの呼び出しでありhg status -nmar、出力を完了用のファイルのリストとして使用します。

git完了スクリプトに似たようなものをパッチするのはそれほど難しいことではないと思います-__git_diffプレーンファイル名+ブランチ完了を行わず、代わりに呼び出すようにここで変更する必要がありますgit status


コマンド

git status --porcelain | grep '^.[^ ?]' | cut -b 4-

(のgit diff --cached)と

git status --porcelain | grep '^[^ ?]' | cut -b 4-

(for git diff)は正しいものを出力しているようです(名前の変更がない場合)。

ただし、HEAD以外のものと比較する場合はどちらも役に立ちません。

より一般的な方法は、

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

ここでcommit1commit2(そして多分--cached)はすでに与えられたdiffコマンドラインから来ています。


上記で概説したアイデアをbashで実装し、にパッチを適用しましgit-completion.bashた。を変更したくない場合はgit-completion.bash、これら2つの関数をbashファイルに追加し、元のファイルの後にソースを設定しますgit-completion.bash。これで、次のようなコマンドで動作するはずです。

git diff -- <tab>
git diff --cached -- <tab>
git diff HEAD^^ -- <tab>
git diff origin/master master -- <tab>

これをパッチとして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の回答を参照)。

もう一度やり直すかもしれませんが、近い将来これを保証することはできません。他の誰かがやりたい場合は、私のコードを自由に取り、変更して、もう一度送信してください。

于 2011-05-17T18:56:30.987 に答える
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>ます。単純化されているかもしれませんが、簡単な修正としてはうまくいくようです。

于 2013-11-18T16:01:40.973 に答える
0

あなたが望んでいる答えではありませんが、fish (フレンドリーな対話型シェル) がすぐに 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/魚の殻/コミット/c5c59d4acb00674bc37198468b5978f69484c628

次のようなステータスがある場合:

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

ここに画像の説明を入力

入力READMEしてタブを押すだけでも、一致するものだけが挿入されます。フリギンナイス!

于 2016-03-21T23:01:41.333 に答える