Thread (9 messages) flat view 9 messages, 2 authors, 2017-02-15

Re: [PATCH v2 2/2] completion: checkout: complete paths when ref given

From: SZEDER Gábor <hidden>
Date: 2017-02-15 03:11:33

On Tue, Feb 14, 2017 at 10:24 PM,  [off-list ref] wrote:
From: Cornelius Weig <redacted>

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.
Refs completion is never attempted for words after the disambiguating
double-dash.

Even when refs completion is attempted, if it is unsuccessful, i.e.
there is no ref that matches the current word to be completed, then
Bash falls back to standard filename completion.  No refs match
'./<TAB>'.

Furthermore, Bash performs filename completion on Alt-/ independently
from any completion function.

Granted, none of these will limit to only modified files...  But that
might be a good thing, see below.
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.
Here you use "modified" in the 'ls-files --modified' sense, but that
doesn't include modifications already staged in the index, see below.
   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.
I'm not sure what you mean here.  Refnames can't contain ':'.
quoted hunk ↗ jump to hunk
Signed-off-by: Cornelius Weig <redacted>
---
 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 ;;
I haven't tried it, but this would trigger on e.g. 'git checkout -b
new-feature <TAB>', wouldn't it?
+                       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"
What about

  $ echo "unintentional change" >>tracked-file && git add -u
  $ git rm important-file
  $ git checkout HEAD <TAB>

?  It seems it will offer neither 'tracked-file' nor 'important-file',
but I think it should offer both.


We have __git_complete_index_file() for a while now, but only use it
for commands that accept only --options and filenames, e.g. 'add',
'clean', 'rm'.  This would be the first case when we would use it for
a command that accept both refs and filenames.  Perhaps similar corner
cases and the easy ways to trigger filename completion are why no one
thought it's worth it.
+                       ;;
+               *)
+                       __git_complete_tree_file "$ref" "$cur"
Well, here you could go all-in, and say that this should complete only
files that are different from the version in $ref, because checking
out files that are still the same is a noop :)
+                       ;;
+               esac
                ;;
        esac
 }
--
2.10.2
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help