a740d05e28ead1925134c63f140785a0013a30c9
   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#    3) Consider changing your PS1 to also show the current branch:
  22#        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
  23#
  24#       The argument to __git_ps1 will be displayed only if you
  25#       are currently in a git repository.  The %s token will be
  26#       the name of the current branch.
  27#
  28
  29__gitdir ()
  30{
  31        echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}"
  32}
  33
  34__git_ps1 ()
  35{
  36        local b="$(git symbolic-ref HEAD 2>/dev/null)"
  37        if [ -n "$b" ]; then
  38                if [ -n "$1" ]; then
  39                        printf "$1" "${b##refs/heads/}"
  40                else
  41                        printf " (%s)" "${b##refs/heads/}"
  42                fi
  43        fi
  44}
  45
  46__git_refs ()
  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/}" ;;
  59                n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
  60                n,*) is_hash=y; echo "$i" ;;
  61                esac
  62        done
  63}
  64
  65__git_refs2 ()
  66{
  67        local cmd i is_hash=y dir="${1:-$(__gitdir)}"
  68        if [ -d "$dir" ]; then
  69                cmd=git-peek-remote
  70        else
  71                cmd=git-ls-remote
  72        fi
  73        for i in $($cmd "$dir" 2>/dev/null); do
  74                case "$is_hash,$i" in
  75                y,*) is_hash=n ;;
  76                n,*^{}) is_hash=y ;;
  77                n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;;
  78                n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;;
  79                n,*) is_hash=y; echo "$i:$i" ;;
  80                esac
  81        done
  82}
  83
  84__git_remotes ()
  85{
  86        local i ngoff IFS=$'\n' d="$(__gitdir)"
  87        shopt -q nullglob || ngoff=1
  88        shopt -s nullglob
  89        for i in "$d/remotes"/*; do
  90                echo ${i#$d/remotes/}
  91        done
  92        [ "$ngoff" ] && shopt -u nullglob
  93        for i in $(git --git-dir="$d" repo-config --list); do
  94                case "$i" in
  95                remote.*.url=*)
  96                        i="${i#remote.}"
  97                        echo "${i/.url=*/}"
  98                        ;;
  99                esac
 100        done
 101}
 102
 103__git_merge_strategies ()
 104{
 105        sed -n "/^all_strategies='/{
 106                s/^all_strategies='//
 107                s/'//
 108                p
 109                q
 110                }" "$(git --exec-path)/git-merge"
 111}
 112
 113__git_complete_file ()
 114{
 115        local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
 116        case "$cur" in
 117        ?*:*)
 118                ref="${cur%%:*}"
 119                cur="${cur#*:}"
 120                case "$cur" in
 121                ?*/*)
 122                        pfx="${cur%/*}"
 123                        cur="${cur##*/}"
 124                        ls="$ref:$pfx"
 125                        pfx="$pfx/"
 126                        ;;
 127                *)
 128                        ls="$ref"
 129                        ;;
 130            esac
 131                COMPREPLY=($(compgen -P "$pfx" \
 132                        -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
 133                                | sed '/^100... blob /s,^.*     ,,
 134                                       /^040000 tree /{
 135                                           s,^.*        ,,
 136                                           s,$,/,
 137                                       }
 138                                       s/^.*    //')" \
 139                        -- "$cur"))
 140                ;;
 141        *)
 142                COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 143                ;;
 144        esac
 145}
 146
 147__git_commands ()
 148{
 149        local i IFS=" "$'\n'
 150        for i in $(git help -a|egrep '^ ')
 151        do
 152                case $i in
 153                check-ref-format) : plumbing;;
 154                commit-tree)      : plumbing;;
 155                convert-objects)  : plumbing;;
 156                cvsserver)        : daemon;;
 157                daemon)           : daemon;;
 158                fetch-pack)       : plumbing;;
 159                hash-object)      : plumbing;;
 160                http-*)           : transport;;
 161                index-pack)       : plumbing;;
 162                local-fetch)      : plumbing;;
 163                mailinfo)         : plumbing;;
 164                mailsplit)        : plumbing;;
 165                merge-*)          : plumbing;;
 166                mktree)           : plumbing;;
 167                mktag)            : plumbing;;
 168                pack-objects)     : plumbing;;
 169                pack-redundant)   : plumbing;;
 170                pack-refs)        : plumbing;;
 171                parse-remote)     : plumbing;;
 172                patch-id)         : plumbing;;
 173                peek-remote)      : plumbing;;
 174                read-tree)        : plumbing;;
 175                receive-pack)     : plumbing;;
 176                rerere)           : plumbing;;
 177                rev-list)         : plumbing;;
 178                rev-parse)        : plumbing;;
 179                runstatus)        : plumbing;;
 180                sh-setup)         : internal;;
 181                shell)            : daemon;;
 182                send-pack)        : plumbing;;
 183                show-index)       : plumbing;;
 184                ssh-*)            : transport;;
 185                stripspace)       : plumbing;;
 186                symbolic-ref)     : plumbing;;
 187                unpack-file)      : plumbing;;
 188                unpack-objects)   : plumbing;;
 189                update-ref)       : plumbing;;
 190                update-server-info) : daemon;;
 191                upload-archive)   : plumbing;;
 192                upload-pack)      : plumbing;;
 193                write-tree)       : plumbing;;
 194                *) echo $i;;
 195                esac
 196        done
 197}
 198
 199__git_aliases ()
 200{
 201        local i IFS=$'\n'
 202        for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
 203                case "$i" in
 204                alias.*)
 205                        i="${i#alias.}"
 206                        echo "${i/=*/}"
 207                        ;;
 208                esac
 209        done
 210}
 211
 212__git_aliased_command ()
 213{
 214        local word cmdline=$(git --git-dir="$(__gitdir)" \
 215                repo-config --get "alias.$1")
 216        for word in $cmdline; do
 217                if [ "${word##-*}" ]; then
 218                        echo $word
 219                        return
 220                fi
 221        done
 222}
 223
 224_git_branch ()
 225{
 226        local cur="${COMP_WORDS[COMP_CWORD]}"
 227        COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
 228}
 229
 230_git_cat_file ()
 231{
 232        local cur="${COMP_WORDS[COMP_CWORD]}"
 233        case "${COMP_WORDS[0]},$COMP_CWORD" in
 234        git-cat-file*,1)
 235                COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
 236                ;;
 237        git,2)
 238                COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
 239                ;;
 240        *)
 241                __git_complete_file
 242                ;;
 243        esac
 244}
 245
 246_git_checkout ()
 247{
 248        local cur="${COMP_WORDS[COMP_CWORD]}"
 249        COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
 250}
 251
 252_git_diff ()
 253{
 254        __git_complete_file
 255}
 256
 257_git_diff_tree ()
 258{
 259        local cur="${COMP_WORDS[COMP_CWORD]}"
 260        COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
 261}
 262
 263_git_fetch ()
 264{
 265        local cur="${COMP_WORDS[COMP_CWORD]}"
 266
 267        case "${COMP_WORDS[0]},$COMP_CWORD" in
 268        git-fetch*,1)
 269                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 270                ;;
 271        git,2)
 272                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 273                ;;
 274        *)
 275                case "$cur" in
 276                *:*)
 277                        cur="${cur#*:}"
 278                        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 279                        ;;
 280                *)
 281                        local remote
 282                        case "${COMP_WORDS[0]}" in
 283                        git-fetch) remote="${COMP_WORDS[1]}" ;;
 284                        git)       remote="${COMP_WORDS[2]}" ;;
 285                        esac
 286                        COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
 287                        ;;
 288                esac
 289                ;;
 290        esac
 291}
 292
 293_git_ls_remote ()
 294{
 295        local cur="${COMP_WORDS[COMP_CWORD]}"
 296        COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 297}
 298
 299_git_ls_tree ()
 300{
 301        __git_complete_file
 302}
 303
 304_git_log ()
 305{
 306        local pfx cur="${COMP_WORDS[COMP_CWORD]}"
 307        case "$cur" in
 308        *...*)
 309                pfx="${cur%...*}..."
 310                cur="${cur#*...}"
 311                COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
 312                ;;
 313        *..*)
 314                pfx="${cur%..*}.."
 315                cur="${cur#*..}"
 316                COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
 317                ;;
 318        *)
 319                COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 320                ;;
 321        esac
 322}
 323
 324_git_merge ()
 325{
 326        local cur="${COMP_WORDS[COMP_CWORD]}"
 327        case "$cur" in
 328        --*)
 329                COMPREPLY=($(compgen -W "
 330                        --no-commit --no-summary --squash
 331                        " -- "$cur"))
 332                return
 333        esac
 334        if [ $COMP_CWORD -gt 1 -a X-s = "X${COMP_WORDS[COMP_CWORD-1]}" ]
 335        then
 336                COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
 337        else
 338                COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 339        fi
 340}
 341
 342_git_merge_base ()
 343{
 344        local cur="${COMP_WORDS[COMP_CWORD]}"
 345        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 346}
 347
 348_git_name_rev ()
 349{
 350        local cur="${COMP_WORDS[COMP_CWORD]}"
 351        COMPREPLY=($(compgen -W "--tags --all --stdin" -- "$cur"))
 352}
 353
 354_git_pull ()
 355{
 356        local cur="${COMP_WORDS[COMP_CWORD]}"
 357
 358        case "${COMP_WORDS[0]},$COMP_CWORD" in
 359        git-pull*,1)
 360                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 361                ;;
 362        git,2)
 363                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 364                ;;
 365        *)
 366                local remote
 367                case "${COMP_WORDS[0]}" in
 368                git-pull)  remote="${COMP_WORDS[1]}" ;;
 369                git)       remote="${COMP_WORDS[2]}" ;;
 370                esac
 371                COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
 372                ;;
 373        esac
 374}
 375
 376_git_push ()
 377{
 378        local cur="${COMP_WORDS[COMP_CWORD]}"
 379
 380        case "${COMP_WORDS[0]},$COMP_CWORD" in
 381        git-push*,1)
 382                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 383                ;;
 384        git,2)
 385                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 386                ;;
 387        *)
 388                case "$cur" in
 389                *:*)
 390                        local remote
 391                        case "${COMP_WORDS[0]}" in
 392                        git-push)  remote="${COMP_WORDS[1]}" ;;
 393                        git)       remote="${COMP_WORDS[2]}" ;;
 394                        esac
 395                        cur="${cur#*:}"
 396                        COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
 397                        ;;
 398                *)
 399                        COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
 400                        ;;
 401                esac
 402                ;;
 403        esac
 404}
 405
 406_git_reset ()
 407{
 408        local cur="${COMP_WORDS[COMP_CWORD]}"
 409        local opt="--mixed --hard --soft"
 410        COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
 411}
 412
 413_git_show ()
 414{
 415        local cur="${COMP_WORDS[COMP_CWORD]}"
 416        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 417}
 418
 419_git ()
 420{
 421        local i c=1 command __git_dir
 422
 423        while [ $c -lt $COMP_CWORD ]; do
 424                i="${COMP_WORDS[c]}"
 425                case "$i" in
 426                --git-dir=*) __git_dir="${i#--git-dir=}" ;;
 427                --bare)      __git_dir="." ;;
 428                --version|--help|-p|--paginate) ;;
 429                *) command="$i"; break ;;
 430                esac
 431                c=$((++c))
 432        done
 433
 434        if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
 435                COMPREPLY=($(compgen -W "
 436                        --git-dir= --version --exec-path
 437                        $(__git_commands)
 438                        $(__git_aliases)
 439                        " -- "${COMP_WORDS[COMP_CWORD]}"))
 440                return;
 441        fi
 442
 443        local expansion=$(__git_aliased_command "$command")
 444        [ "$expansion" ] && command="$expansion"
 445
 446        case "$command" in
 447        branch)      _git_branch ;;
 448        cat-file)    _git_cat_file ;;
 449        checkout)    _git_checkout ;;
 450        diff)        _git_diff ;;
 451        diff-tree)   _git_diff_tree ;;
 452        fetch)       _git_fetch ;;
 453        log)         _git_log ;;
 454        ls-remote)   _git_ls_remote ;;
 455        ls-tree)     _git_ls_tree ;;
 456        merge)       _git_merge;;
 457        merge-base)  _git_merge_base ;;
 458        name-rev)    _git_name_rev ;;
 459        pull)        _git_pull ;;
 460        push)        _git_push ;;
 461        reset)       _git_reset ;;
 462        show)        _git_show ;;
 463        show-branch) _git_log ;;
 464        whatchanged) _git_log ;;
 465        *)           COMPREPLY=() ;;
 466        esac
 467}
 468
 469_gitk ()
 470{
 471        local cur="${COMP_WORDS[COMP_CWORD]}"
 472        COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
 473}
 474
 475complete -o default -o nospace -F _git git
 476complete -o default            -F _gitk gitk
 477complete -o default            -F _git_branch git-branch
 478complete -o default -o nospace -F _git_cat_file git-cat-file
 479complete -o default            -F _git_checkout git-checkout
 480complete -o default -o nospace -F _git_diff git-diff
 481complete -o default            -F _git_diff_tree git-diff-tree
 482complete -o default -o nospace -F _git_fetch git-fetch
 483complete -o default -o nospace -F _git_log git-log
 484complete -o default            -F _git_ls_remote git-ls-remote
 485complete -o default -o nospace -F _git_ls_tree git-ls-tree
 486complete -o default            -F _git_merge git-merge
 487complete -o default            -F _git_merge_base git-merge-base
 488complete -o default            -F _git_name_rev git-name-rev
 489complete -o default -o nospace -F _git_pull git-pull
 490complete -o default -o nospace -F _git_push git-push
 491complete -o default            -F _git_reset git-reset
 492complete -o default            -F _git_show git-show
 493complete -o default -o nospace -F _git_log git-show-branch
 494complete -o default -o nospace -F _git_log git-whatchanged
 495
 496# The following are necessary only for Cygwin, and only are needed
 497# when the user has tab-completed the executable name and consequently
 498# included the '.exe' suffix.
 499#
 500if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
 501complete -o default -o nospace -F _git git.exe
 502complete -o default            -F _git_branch git-branch.exe
 503complete -o default -o nospace -F _git_cat_file git-cat-file.exe
 504complete -o default -o nospace -F _git_diff git-diff.exe
 505complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
 506complete -o default -o nospace -F _git_log git-log.exe
 507complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
 508complete -o default            -F _git_merge_base git-merge-base.exe
 509complete -o default            -F _git_name_rev git-name-rev.exe
 510complete -o default -o nospace -F _git_push git-push.exe
 511complete -o default -o nospace -F _git_log git-show-branch.exe
 512complete -o default -o nospace -F _git_log git-whatchanged.exe
 513fi