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