bash 탭 완성:git 명령의 단일 탭에 있는 전체 경로?

bash 탭 완성:git 명령의 단일 탭에 있는 전체 경로?

예를 들어 bash에서 git 명령 다음에 파일 경로를 완성하려면 탭을 누를 때마다 파일에 있는 하위 폴더 수에 따라 실제 파일 이름을 완성하기 위해 여러 번 git add눌러야 합니다 .<TAB>

예: 파일을 추가 my/example/file하고 다음을 입력하고 싶습니다.

git add <TAB>
git add my/<TAB>
git add my/example/<TAB>
git add my/example/file

my/example/file이는 변경된 유일한 파일의 경우에도 마찬가지이므로 현재 사용할 수 있는 유일한 탭 완성 옵션입니다. 이 경우 bash는 첫 번째 path 로 전체 경로를 완료할 수도 있지만 <TAB>그렇지 않습니다.

물고기이는 실제로 기본적으로 수행됩니다.

git add <TAB>
git add my/example/file

Bash에서 이 동작을 구성하는 방법이 있습니까?

저는 기본 bash 완성을 사용하여 Ubuntu 20.04를 사용하고 있습니다.

답변1

이를 달성하는 한 가지 방법은 git 완성 스크립트를 복사하고 /usr/share/bash-completion/completions/git전체 ~/.local/share/bash-completion/completions/인덱스 경로 완성을 사용하도록 수정하는 것입니다.

mkdir -p ~/.local/share/bash-completion/completions
cd ~/.local/share/bash-completion/completions

cp /usr/share/bash-completion/completions/git .

# See diff below
patch -lp0 </tmp/index_paths.diff
echo GIT_COMPLETION_FULL_INDEX_PATHS=1 >>~/.bashrc

exec bash

내가 아는 한, 필요한 변경 사항은 다음과 같습니다.

  1. __git_index_files()첫 번째 경로 구성 요소뿐만 아니라 전체 인덱스 경로를 출력하도록 수정하세요 .

  2. 에서는 set을 사용하므로 기본 이름만 출력하므로 __git_complete_index_file()사용을 중지합니다 . 이 옵션은 쉘 인용도 처리하므로 지금은 수동으로 수행하십시오.__gitcomp_file_directCOMPREPLYcompopt -o filenames

__git_complete_index_file, , 및 이외의 다른 여러 git 명령을 완료하는 데 사용되므로 add전체 경로 완성 clean은 해당 명령에서도 작동합니다. 쉘 변수 뒤에 기능을 추가하는 이러한 변경 시도의 차이점은 다음과 같습니다 .commitrmGIT_COMPLETION_FULL_INDEX_PATHS

--- git
+++ git
@@ -39,6 +39,11 @@
 #     When set to "1", do not include "DWIM" suggestions in git-checkout
 #     and git-switch completion (e.g., completing "foo" when "origin/foo"
 #     exists).
+#
+#   GIT_COMPLETION_FULL_INDEX_PATHS
+#
+#     Normally index path completions return only the next path component. When
+#     set to "1", the whole path will be completed.
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -435,6 +440,19 @@
    __gitcomp_nl_append "$@"
 }
 
+# Shell quotes each word and fills the COMPREPLY array.
+# 1: List of newline-separated completion words.
+__gitcomp_quote_direct ()
+{
+   local IFS=$'\n'
+   local quoted="$1"
+   [[ -n $1 ]] && quoted=$(printf '%q\n' $1)
+
+   COMPREPLY=($quoted)
+
+   compopt +o nospace 2>/dev/null || true
+}
+
 # Fills the COMPREPLY array with prefiltered paths without any additional
 # processing.
 # Callers must take care of providing only paths that match the current path
@@ -503,10 +521,12 @@
 __git_index_files ()
 {
    local root="$2" match="$3"
+   local field=1
+   [ "$GIT_COMPLETION_FULL_INDEX_PATHS" = "1" ] && field=0
 
    __git_ls_files_helper "$root" "$1" "$match" |
    awk -F / -v pfx="${2//\\/\\\\}" '{
-       paths[$1] = 1
+       paths[$f] = 1
    }
    END {
        for (p in paths) {
@@ -518,19 +538,13 @@
 
            # The path is quoted.
            p = dequote(p)
-           if (p == "")
-               continue
 
-           # Even when a directory name itself does not contain
-           # any special characters, it will still be quoted if
-           # any of its (stripped) trailing path components do.
-           # Because of this we may have seen the same directory
-           # both quoted and unquoted.
-           if (p in paths)
-               # We have seen the same directory unquoted,
-               # skip it.
-               continue
-           else
+           # When not using full index paths, p in paths is checked
+           # because the dequoted directory name may already be in
+           # paths. This is the case when the directory name itself
+           # does not contain special characters, but a (stripped)
+           # trailing path component does.
+           if (p != "" && (f == 0 || !(p in paths)))
                print pfx p
        }
    }
@@ -573,7 +587,7 @@
            out = out p
 
        return out
-   }'
+   }' "f=$field"
 }
 
 # __git_complete_index_file requires 1 argument:
@@ -595,7 +609,11 @@
        cur_="$dequoted_word"
    esac
 
-   __gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+   if [ "$GIT_COMPLETION_FULL_INDEX_PATHS" = "1" ]; then
+       __gitcomp_quote_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+   else
+       __gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+   fi
 }
 
 # Lists branches from the local repository.

관련 정보