14

This is related to Disable auto-completion of remote branches in Git Bash?.

Anyone knows how to do the same with zsh?

Community
  • 1
  • 1
Galder Zamarreño
  • 5,027
  • 2
  • 26
  • 34

5 Answers5

12
zstyle :completion::complete:git-checkout:argument-rest:headrefs command "git for-each-ref --format='%(refname)' refs/heads 2>/dev/null"

Explanation:

Typing git checkout <Control-x><h> invokes _complete_help which exposes the internals of how zsh's completion system would act if you pressed TAB in the current context (instead of pressing <Control-x><h>). From this it is possible to see that zsh would invoke the __git_heads function to complete names of git branch heads. If you then type which __git_heads, you can see that these branch head names are obtained via:

_call_program headrefs git for-each-ref --format='"%(refname)"' refs/heads refs/remotes 2>/dev/null

Luckily for us, _call_program is designed specifically to allow the user to change the default behaviour. So the above zstyle command instructs zsh to use an alternative git for-each-ref ... invocation instead of the built-in one, and you can see that in the invocation above, I removed the refs/remotes parameter. The first parameter to zstyle is the completion context, and here it means "whenever the completion system is requesting completion for the headrefs tag when the user is completing an argument for git checkout. So this zstyle will only affect git checkout, and not any other git sub-commands.

Adam Spiers
  • 17,397
  • 5
  • 46
  • 65
  • How would one split the remote and local into two separate sections in the auto-complete? E.g. I'd love to have the special heads (`HEAD`, `ORIG_HEAD`, `FETCH_HEAD`, etc), then local branches, then remote branches. It's non-obvious to me how that would be done. If it's easy to expand your answer, that would be swell. If not, I'll open a new question. – Bo Jeanes Jan 14 '14 at 01:05
  • There's *probably* a way to do that - after all, there is a grouping mechanism (search for `group-name` and `group-order` in the manual) but I don't know off-hand how to split the various heads out into these groups - so probably worth a separate question. – Adam Spiers Jan 14 '14 at 11:15
  • 1
    Anyone know how to get this to work with prezto? Presumable, the command would start with `':prezto:module:completion:git-checkout`, but I haven't been able to figure out the rest. – Jimothy Mar 05 '19 at 14:47
4

By typing git checkout <Ctrl-X><H> you see a bunch of tags, some which seem relevant are:

$ git checkout
tags in context :completion::complete:git-checkout:argument-rest:
    remote-branch-names-noprefix              (__git_describe_branch __git_describe_commit __git_remote_branch_names_noprefix _git-checkout _git) 
    heads-remote                              (__git_describe_branch __git_describe_commit __git_heads_remote __git_heads __git_commits __git_tree_ishs _git-checkout _git) 
    [...]

At first sight, we need to change remote-branch-names-noprefix's behavior to stop providing remote branch names with no prefix.

To double check, let's see what entries these tags are associated with, use:

$ zstyle ':completion:*' group-name ''
$ zstyle ':completion:*' format 'Completing "%d":'
$ git checkout T<Tab>
Completing "remote branch name":
T3522-plugins_and_stuff  T7482
Completing "local head":
T7626-async

In the parenthesis following the tag names above, there is a chain of commands which led to an autocomplete entry being generated for that tag. In remote-branch-names-noprefix's chain you can see __git_remote_branch_names_noprefix which seems relevant. Look in /usr/share/zsh/functions/Completion/Unix/_git:

(( $+functions[__git_remote_branch_names_noprefix] )) ||
__git_remote_branch_names_noprefix () {
  declare -a heads

  branch_names=(${${${${(f)"$(_call_program remote-branch-refs-noprefix git for-each-ref --format='"%(refname)"' refs/remotes 2>/dev/null)"}#refs/remotes/}#*/}:#HEAD})
  __git_command_successful $pipestatus || return 1

  __git_describe_commit branch_names remote-branch-names-noprefix 'remote branch name' "$@"
}

You can see how _call_program is used to define remote-branch-refs-noprefix. We want to change this definition in git-checkout's case. By replacing it with "echo", it will stop providing autocomplete entries:

zstyle ':completion::complete:git-checkout:argument-rest:remote-branch-refs-noprefix' command "echo"
aleb
  • 2,490
  • 1
  • 28
  • 46
1

It appears that __git_heads now only checks local branches, but the completion files call __git_refs instead.

I hacked this in by applying this patch to git-completion.bash, which is proxied through to by the zsh _git command:

--- git-completion.bash.old 2015-04-02 16:09:38.000000000 -0700
+++ git-completion.bash     2015-04-02 16:10:24.000000000 -0700
@@ -1032,13 +1032,7 @@
                    "
            ;;
    *)
-           # 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)"
+           __gitcomp_nl "$(__git_heads)"
            ;;
    esac
 }

It's not a perfect solution, but it works for my use cases and makes completion instant instead of 10 seconds.

Xiong Chiamiov
  • 13,076
  • 9
  • 63
  • 101
  • The code seems to have changed a lot since 2015 and the patch won't apply. Could you tell us which function definition this is in, please? – John Y Jan 21 '19 at 10:01
0

No one answer don't help me. Try this:

$ git checkout <Ctrl+X><H>
tags in context :completion::complete:git::
    argument-rest  (_arguments _git)
tags in context :completion::complete:git-checkout::
    argument-rest options  (_arguments _git-checkout _call_function _git)
tags in context :completion::complete:git-checkout:argument-rest:
    remote branches tree-ishs modified-files  (_alternative _git-checkout _call_function _git) 
    remote-branch-names-noprefix              (__git_remote_branch_names_noprefix _alternative _git-checkout _call_function _git) 
    heads commit-tags commit-objects          (_alternative __git_commits __git_tree_ishs _alternative _git-checkout _call_function _git) 
    heads-local                               (__git_heads_local __git_heads _alternative __git_commits __git_tree_ishs _alternative _git-checkout _call_function _git) 
    commit-tags                               (__git_tags_of_type __git_commit_tags _alternative __git_commits __git_tree_ishs _alternative _git-checkout _call_function _git) 
    modified-files                            (__git_files __git_modified_files _alternative _git-checkout _call_function _git)

You can found in this output functions, which generates completion for command. You can override any of this function on your .zshrc. Put this at the very top of config file:

__git_heads_remote() {}

After that, you will not see remote heads on your completion. You can do this for any function.

Artur Eshenbrener
  • 1,850
  • 2
  • 17
  • 24
-2

You can disable auto-completion on git checkout by adding this line to your .zshrc file:

compdef -d git checkout
Christopher
  • 42,720
  • 11
  • 81
  • 99
  • 1
    I was looking for a way that avoided auto-completion of remote branches. I'd like to have auto-complete of local branches though. – Galder Zamarreño Sep 05 '12 at 16:06
  • @GalderZamarreño Afraid that's beyond the scope of my zsh knowledge; might try the zsh list; they seem like helpful folks. – Christopher Sep 05 '12 at 16:42