contrib / completion / git-completion.bashon commit Merge git://git.kernel.org/pub/scm/gitk/gitk (659db3f)
   1#
   2# bash completion support for core Git.
   3#
   4# Copyright (C) 2006 Shawn Pearce
   5# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
   6#
   7# The contained completion routines provide support for completing:
   8#
   9#    *) local and remote branch names
  10#    *) local and remote tag names
  11#    *) .git/remotes file names
  12#    *) git 'subcommands'
  13#    *) tree paths within 'ref:path/to/file' expressions
  14#
  15# To use these routines:
  16#
  17#    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
  18#    2) Added the following line to your .bashrc:
  19#        source ~/.git-completion.sh
  20#
  21
  22__gitdir ()
  23{
  24        echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}"
  25}
  26
  27__git_refs ()
  28{
  29        local cmd i is_hash=y dir="${1:-$(__gitdir)}"
  30        if [ -d "$dir" ]; then
  31                cmd=git-peek-remote
  32        else
  33                cmd=git-ls-remote
  34        fi
  35        for i in $($cmd "$dir" 2>/dev/null); do
  36                case "$is_hash,$i" in
  37                y,*) is_hash=n ;;
  38                n,*^{}) is_hash=y ;;
  39                n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
  40                n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
  41                n,*) is_hash=y; echo "$i" ;;
  42                esac
  43        done
  44}
  45
  46__git_refs2 ()
  47{
  48        local cmd i is_hash=y dir="${1:-$(__gitdir)}"
  49        if [ -d "$dir" ]; then
  50                cmd=git-peek-remote
  51        else
  52                cmd=git-ls-remote
  53        fi
  54        for i in $($cmd "$dir" 2>/dev/null); do
  55                case "$is_hash,$i" in
  56                y,*) is_hash=n ;;
  57                n,*^{}) is_hash=y ;;
  58                n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;;
  59                n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;;
  60                n,*) is_hash=y; echo "$i:$i" ;;
  61                esac
  62        done
  63}
  64
  65__git_remotes ()
  66{
  67        local i ngoff IFS=$'\n' d="$(__gitdir)"
  68        shopt -q nullglob || ngoff=1
  69        shopt -s nullglob
  70        for i in "$d/remotes"/*; do
  71                echo ${i#$d/remotes/}
  72        done
  73        [ "$ngoff" ] && shopt -u nullglob
  74        for i in $(git --git-dir="$d" repo-config --list); do
  75                case "$i" in
  76                remote.*.url=*)
  77                        i="${i#remote.}"
  78                        echo "${i/.url=*/}"
  79                        ;;
  80                esac
  81        done
  82}
  83
  84__git_complete_file ()
  85{
  86        local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
  87        case "$cur" in
  88        ?*:*)
  89                ref="${cur%%:*}"
  90                cur="${cur#*:}"
  91                case "$cur" in
  92                ?*/*)
  93                        pfx="${cur%/*}"
  94                        cur="${cur##*/}"
  95                        ls="$ref:$pfx"
  96                        pfx="$pfx/"
  97                        ;;
  98                *)
  99                        ls="$ref"
 100                        ;;
 101            esac
 102                COMPREPLY=($(compgen -P "$pfx" \
 103                        -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
 104                                | sed '/^100... blob /s,^.*     ,,
 105                                       /^040000 tree /{
 106                                           s,^.*        ,,
 107                                           s,$,/,
 108                                       }
 109                                       s/^.*    //')" \
 110                        -- "$cur"))
 111                ;;
 112        *)
 113                COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 114                ;;
 115        esac
 116}
 117
 118__git_aliases ()
 119{
 120        local i IFS=$'\n'
 121        for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
 122                case "$i" in
 123                alias.*)
 124                        i="${i#alias.}"
 125                        echo "${i/=*/}"
 126                        ;;
 127                esac
 128        done
 129}
 130
 131__git_aliased_command ()
 132{
 133        local word cmdline=$(git --git-dir="$(__gitdir)" \
 134                repo-config --get "alias.$1")
 135        for word in $cmdline; do
 136                if [ "${word##-*}" ]; then
 137                        echo $word
 138                        return
 139                fi
 140        done
 141}
 142
 143_git_branch ()
 144{
 145        local cur="${COMP_WORDS[COMP_CWORD]}"
 146        COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
 147}
 148
 149_git_cat_file ()
 150{
 151        local cur="${COMP_WORDS[COMP_CWORD]}"
 152        case "${COMP_WORDS[0]},$COMP_CWORD" in
 153        git-cat-file*,1)
 154                COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
 155                ;;
 156        git,2)
 157                COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
 158                ;;
 159        *)
 160                __git_complete_file
 161                ;;
 162        esac
 163}
 164
 165_git_checkout ()
 166{
 167        local cur="${COMP_WORDS[COMP_CWORD]}"
 168        COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
 169}
 170
 171_git_diff ()
 172{
 173        __git_complete_file
 174}
 175
 176_git_diff_tree ()
 177{
 178        local cur="${COMP_WORDS[COMP_CWORD]}"
 179        COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
 180}
 181
 182_git_fetch ()
 183{
 184        local cur="${COMP_WORDS[COMP_CWORD]}"
 185
 186        case "${COMP_WORDS[0]},$COMP_CWORD" in
 187        git-fetch*,1)
 188                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 189                ;;
 190        git,2)
 191                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 192                ;;
 193        *)
 194                case "$cur" in
 195                *:*)
 196                        cur="${cur#*:}"
 197                        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 198                        ;;
 199                *)
 200                        local remote
 201                        case "${COMP_WORDS[0]}" in
 202                        git-fetch) remote="${COMP_WORDS[1]}" ;;
 203                        git)       remote="${COMP_WORDS[2]}" ;;
 204                        esac
 205                        COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
 206                        ;;
 207                esac
 208                ;;
 209        esac
 210}
 211
 212_git_ls_remote ()
 213{
 214        local cur="${COMP_WORDS[COMP_CWORD]}"
 215        COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 216}
 217
 218_git_ls_tree ()
 219{
 220        __git_complete_file
 221}
 222
 223_git_log ()
 224{
 225        local pfx cur="${COMP_WORDS[COMP_CWORD]}"
 226        case "$cur" in
 227        *...*)
 228                pfx="${cur%...*}..."
 229                cur="${cur#*...}"
 230                COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
 231                ;;
 232        *..*)
 233                pfx="${cur%..*}.."
 234                cur="${cur#*..}"
 235                COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
 236                ;;
 237        *)
 238                COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 239                ;;
 240        esac
 241}
 242
 243_git_merge_base ()
 244{
 245        local cur="${COMP_WORDS[COMP_CWORD]}"
 246        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 247}
 248
 249_git_pull ()
 250{
 251        local cur="${COMP_WORDS[COMP_CWORD]}"
 252
 253        case "${COMP_WORDS[0]},$COMP_CWORD" in
 254        git-pull*,1)
 255                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 256                ;;
 257        git,2)
 258                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 259                ;;
 260        *)
 261                local remote
 262                case "${COMP_WORDS[0]}" in
 263                git-pull)  remote="${COMP_WORDS[1]}" ;;
 264                git)       remote="${COMP_WORDS[2]}" ;;
 265                esac
 266                COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
 267                ;;
 268        esac
 269}
 270
 271_git_push ()
 272{
 273        local cur="${COMP_WORDS[COMP_CWORD]}"
 274
 275        case "${COMP_WORDS[0]},$COMP_CWORD" in
 276        git-push*,1)
 277                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 278                ;;
 279        git,2)
 280                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 281                ;;
 282        *)
 283                case "$cur" in
 284                *:*)
 285                        local remote
 286                        case "${COMP_WORDS[0]}" in
 287                        git-push)  remote="${COMP_WORDS[1]}" ;;
 288                        git)       remote="${COMP_WORDS[2]}" ;;
 289                        esac
 290                        cur="${cur#*:}"
 291                        COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
 292                        ;;
 293                *)
 294                        COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
 295                        ;;
 296                esac
 297                ;;
 298        esac
 299}
 300
 301_git_reset ()
 302{
 303        local cur="${COMP_WORDS[COMP_CWORD]}"
 304        local opt="--mixed --hard --soft"
 305        COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
 306}
 307
 308_git_show ()
 309{
 310        local cur="${COMP_WORDS[COMP_CWORD]}"
 311        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 312}
 313
 314_git ()
 315{
 316        local i c=1 command __git_dir
 317
 318        while [ $c -lt $COMP_CWORD ]; do
 319                i="${COMP_WORDS[c]}"
 320                case "$i" in
 321                --git-dir=*) __git_dir="${i#--git-dir=}" ;;
 322                --bare)      __git_dir="." ;;
 323                --version|--help|-p|--paginate) ;;
 324                *) command="$i"; break ;;
 325                esac
 326                c=$((++c))
 327        done
 328
 329        if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
 330                COMPREPLY=($(compgen \
 331                        -W "--git-dir= --version \
 332                                $(git help -a|egrep '^ ') \
 333                            $(__git_aliases)" \
 334                        -- "${COMP_WORDS[COMP_CWORD]}"))
 335                return;
 336        fi
 337
 338        local expansion=$(__git_aliased_command "$command")
 339        [ "$expansion" ] && command="$expansion"
 340
 341        case "$command" in
 342        branch)      _git_branch ;;
 343        cat-file)    _git_cat_file ;;
 344        checkout)    _git_checkout ;;
 345        diff)        _git_diff ;;
 346        diff-tree)   _git_diff_tree ;;
 347        fetch)       _git_fetch ;;
 348        log)         _git_log ;;
 349        ls-remote)   _git_ls_remote ;;
 350        ls-tree)     _git_ls_tree ;;
 351        merge-base)  _git_merge_base ;;
 352        pull)        _git_pull ;;
 353        push)        _git_push ;;
 354        reset)       _git_reset ;;
 355        show)        _git_show ;;
 356        show-branch) _git_log ;;
 357        whatchanged) _git_log ;;
 358        *)           COMPREPLY=() ;;
 359        esac
 360}
 361
 362_gitk ()
 363{
 364        local cur="${COMP_WORDS[COMP_CWORD]}"
 365        COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
 366}
 367
 368complete -o default -o nospace -F _git git
 369complete -o default            -F _gitk gitk
 370complete -o default            -F _git_branch git-branch
 371complete -o default -o nospace -F _git_cat_file git-cat-file
 372complete -o default            -F _git_checkout git-checkout
 373complete -o default -o nospace -F _git_diff git-diff
 374complete -o default            -F _git_diff_tree git-diff-tree
 375complete -o default -o nospace -F _git_fetch git-fetch
 376complete -o default -o nospace -F _git_log git-log
 377complete -o default            -F _git_ls_remote git-ls-remote
 378complete -o default -o nospace -F _git_ls_tree git-ls-tree
 379complete -o default            -F _git_merge_base git-merge-base
 380complete -o default -o nospace -F _git_pull git-pull
 381complete -o default -o nospace -F _git_push git-push
 382complete -o default            -F _git_reset git-reset
 383complete -o default            -F _git_show git-show
 384complete -o default -o nospace -F _git_log git-show-branch
 385complete -o default -o nospace -F _git_log git-whatchanged
 386
 387# The following are necessary only for Cygwin, and only are needed
 388# when the user has tab-completed the executable name and consequently
 389# included the '.exe' suffix.
 390#
 391if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
 392complete -o default -o nospace -F _git git.exe
 393complete -o default            -F _git_branch git-branch.exe
 394complete -o default -o nospace -F _git_cat_file git-cat-file.exe
 395complete -o default -o nospace -F _git_diff git-diff.exe
 396complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
 397complete -o default -o nospace -F _git_log git-log.exe
 398complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
 399complete -o default            -F _git_merge_base git-merge-base.exe
 400complete -o default -o nospace -F _git_push git-push.exe
 401complete -o default -o nospace -F _git_log git-show-branch.exe
 402complete -o default -o nospace -F _git_log git-whatchanged.exe
 403fi