From: Cornelius Weig <cornelius.w...@tngtech.com>

Git-checkout completes words starting with '--' as options and other
words as refs. Even after specifying a ref, further words not starting
with '--' are completed as refs, which is invalid for git-checkout.

This commit ensures that after specifying a ref, further non-option
words are completed as paths. Four cases are considered:

 - If the word contains a ':', do not treat it as reference and use
   regular revlist completion.
 - If no ref is found on the command line, complete non-options as refs
   as before.
 - If the ref is HEAD or @, complete only with modified files because
   checking out unmodified files is a noop.
   This case also applies if no ref is given, but '--' is present.
 - If a ref other than HEAD or @ is found, offer only valid paths from
   that revision.

Note that one corner-case is not covered by the current implementation:
if a refname contains a ':' and is followed by '--' the completion would
not recognize the valid refname.

Signed-off-by: Cornelius Weig <cornelius.w...@tngtech.com>
---
 contrib/completion/git-completion.bash | 39 +++++++++++++++++++++++++++-------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/contrib/completion/git-completion.bash 
b/contrib/completion/git-completion.bash
index 4ab119d..df46f62 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1068,7 +1068,7 @@ _git_bundle ()
 
 _git_checkout ()
 {
-       __git_has_doubledash && return
+       local i c=2 ref="" seen_double_dash=""
 
        case "$cur" in
        --conflict=*)
@@ -1081,13 +1081,36 @@ _git_checkout ()
                        "
                ;;
        *)
-               # check if --track, --no-track, or --no-guess was specified
-               # if so, disable DWIM mode
-               local flags="--track --no-track --no-guess" track=1
-               if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
-                       track=''
-               fi
-               __gitcomp_nl "$(__git_refs '' $track)"
+               while [ $c -lt $cword ]; do
+                       i="${words[c]}"
+                       case "$i" in
+                       --) seen_double_dash=1 ;;
+                       -*|?*:*) ;;
+                       *) ref="$i"; break ;;
+                       esac
+                       ((c++))
+               done
+
+               case "$ref,$seen_double_dash,$cur" in
+               ,,*:*)
+                   __git_complete_revlist_file
+                   ;;
+               ,,*)
+                       # check for --track, --no-track, or --no-guess
+                       # if so, disable DWIM mode
+                       local flags="--track --no-track --no-guess" track=1
+                       if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
+                               track=''
+                       fi
+                       __gitcomp_nl "$(__git_refs '' $track)"
+                       ;;
+               ,1,*|@,*|HEAD,*)
+                       __git_complete_index_file "--modified"
+                       ;;
+               *)
+                       __git_complete_tree_file "$ref" "$cur"
+                       ;;
+               esac
                ;;
        esac
 }
-- 
2.10.2

Reply via email to