Search code examples
gitbash-completiongit-completion

bash completion for git custom subcommands?


Say I have a git-cc executable in PATH. If git-cc supports --help, then it is easy to provide adequate completion with

complete -F _longopt git-cc

This makes $ git-cc --<TAB> complete (as per help output). But git cc --<TAB> won't complete (even though it runs fine). More importantly if I create a git alias to the custom subcommand, e.g. cc-sensible-defaults = cc --opt1 ..., that also won't work, and in this case simply deleting the space (git-cc instead of git cc) isn't an option.

What to do? I've tried messing around with __git_complete [git-]cc _longopt, but none of the various combinations do anything good. It seems to be for completing bash aliases (like gl = git-log), not sub-commands. The intro in git/git-completion.bash is, as expected, not very helpful, containing the confusing

# If you have a command that is not part of git, but you would still
# like completion, you can use __git_complete:
#
#   __git_complete gl git_log
#
# Or if it's a main command (i.e. git or gitk):
#
#   __git_complete gk gitk

(WTH is _git_log? Did they mean _git_log, which is indeed a function? Is it some convention?)


Solution

  • Update:

    For me, this solution just makes <tab> list all the alternatives every time, no completion, why? I tried _git_jump() { COMPREPLY=(diff merge grep); } and git jump d<tab> but the output is just listing: diff grep merge –  Moberg

    What you have to do, is remove from COMPREPLY the words so that only one that starts with $cur is left. If you give 3, bash will show you the list. If you reduce COMPREPLY=(diff) then it will be auto-completed by Bash.

    Taking inspiration of https://github.com/git/git/blob/master/contrib/completion/git-completion.bash#L2445 , the following works nicely:

    _git_jump() { __gitcomp "diff merge grep" "" "$cur"; }
    

    Or I think it's better to write similar code yourself, not to depend on git:

    _git_jump() { COMPREPLY=( $(compgen -W "diff merge grep" -- "${COMP_WORDS[COMP_CWORD]}") ); }
    

    For me https://devmanual.gentoo.org/tasks-reference/completion/index.html is the best introduction how to do it.


    What to do?

    Just define a function that does the compiletion with leading _git_ prefix.

    # you should rather use COMPREPLY+=(..) or call `__gitcomp` to append
    $ _git_cc() { COMPREPLY=(-a -b); }
    $ git cc <tab>
    -a  -b  
    $ git cc -
    

    See __git_complete_command:

    __git_complete_command () {
        local command="$1"
        local completion_func="_git_${command//-/_}"
        ...
        if __git_have_func $completion_func
            then
                $completion_func
                return 0
    

    I've tried messing around with __git_complete

    As far as I understand the __git_complete it's the other way round - you want a normal command complete like git subcommand. For example:

    $ _git_cc() { COMPREPLY=(-a -b); }
    $ alias mycommand='git cc'
    $ __git_complete mycommand git_cc                  # or __git_complete mycommand _git_cc
    $ mycommand <tab>
    -a  -b  
    $ mycommand -
    

    WTH is _git_log?

    _git_log is a function the generates completion for git log.

    Did they mean _git_log, which is indeed a function?

    Yes. See __git_complete tests for existence of a function with _main suffix or _ prefix or without any prefix/suffix.

    Is it some convention?)

    Yes.