contrib / completion / git-completion.bashon commit Teach bash how to complete git-format-patch. (f53352f)
   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_complete_revlist ()
 148{
 149        local pfx cur="${COMP_WORDS[COMP_CWORD]}"
 150        case "$cur" in
 151        *...*)
 152                pfx="${cur%...*}..."
 153                cur="${cur#*...}"
 154                COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
 155                ;;
 156        *..*)
 157                pfx="${cur%..*}.."
 158                cur="${cur#*..}"
 159                COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
 160                ;;
 161        *)
 162                COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 163                ;;
 164        esac
 165}
 166
 167__git_commands ()
 168{
 169        local i IFS=" "$'\n'
 170        for i in $(git help -a|egrep '^ ')
 171        do
 172                case $i in
 173                check-ref-format) : plumbing;;
 174                commit-tree)      : plumbing;;
 175                convert-objects)  : plumbing;;
 176                cvsserver)        : daemon;;
 177                daemon)           : daemon;;
 178                fetch-pack)       : plumbing;;
 179                hash-object)      : plumbing;;
 180                http-*)           : transport;;
 181                index-pack)       : plumbing;;
 182                local-fetch)      : plumbing;;
 183                mailinfo)         : plumbing;;
 184                mailsplit)        : plumbing;;
 185                merge-*)          : plumbing;;
 186                mktree)           : plumbing;;
 187                mktag)            : plumbing;;
 188                pack-objects)     : plumbing;;
 189                pack-redundant)   : plumbing;;
 190                pack-refs)        : plumbing;;
 191                parse-remote)     : plumbing;;
 192                patch-id)         : plumbing;;
 193                peek-remote)      : plumbing;;
 194                read-tree)        : plumbing;;
 195                receive-pack)     : plumbing;;
 196                rerere)           : plumbing;;
 197                rev-list)         : plumbing;;
 198                rev-parse)        : plumbing;;
 199                runstatus)        : plumbing;;
 200                sh-setup)         : internal;;
 201                shell)            : daemon;;
 202                send-pack)        : plumbing;;
 203                show-index)       : plumbing;;
 204                ssh-*)            : transport;;
 205                stripspace)       : plumbing;;
 206                symbolic-ref)     : plumbing;;
 207                unpack-file)      : plumbing;;
 208                unpack-objects)   : plumbing;;
 209                update-ref)       : plumbing;;
 210                update-server-info) : daemon;;
 211                upload-archive)   : plumbing;;
 212                upload-pack)      : plumbing;;
 213                write-tree)       : plumbing;;
 214                *) echo $i;;
 215                esac
 216        done
 217}
 218
 219__git_aliases ()
 220{
 221        local i IFS=$'\n'
 222        for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
 223                case "$i" in
 224                alias.*)
 225                        i="${i#alias.}"
 226                        echo "${i/=*/}"
 227                        ;;
 228                esac
 229        done
 230}
 231
 232__git_aliased_command ()
 233{
 234        local word cmdline=$(git --git-dir="$(__gitdir)" \
 235                repo-config --get "alias.$1")
 236        for word in $cmdline; do
 237                if [ "${word##-*}" ]; then
 238                        echo $word
 239                        return
 240                fi
 241        done
 242}
 243
 244_git_branch ()
 245{
 246        local cur="${COMP_WORDS[COMP_CWORD]}"
 247        COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
 248}
 249
 250_git_cat_file ()
 251{
 252        local cur="${COMP_WORDS[COMP_CWORD]}"
 253        case "${COMP_WORDS[0]},$COMP_CWORD" in
 254        git-cat-file*,1)
 255                COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
 256                ;;
 257        git,2)
 258                COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
 259                ;;
 260        *)
 261                __git_complete_file
 262                ;;
 263        esac
 264}
 265
 266_git_checkout ()
 267{
 268        local cur="${COMP_WORDS[COMP_CWORD]}"
 269        COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
 270}
 271
 272_git_diff ()
 273{
 274        __git_complete_file
 275}
 276
 277_git_diff_tree ()
 278{
 279        local cur="${COMP_WORDS[COMP_CWORD]}"
 280        COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
 281}
 282
 283_git_fetch ()
 284{
 285        local cur="${COMP_WORDS[COMP_CWORD]}"
 286
 287        case "${COMP_WORDS[0]},$COMP_CWORD" in
 288        git-fetch*,1)
 289                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 290                ;;
 291        git,2)
 292                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 293                ;;
 294        *)
 295                case "$cur" in
 296                *:*)
 297                        cur="${cur#*:}"
 298                        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 299                        ;;
 300                *)
 301                        local remote
 302                        case "${COMP_WORDS[0]}" in
 303                        git-fetch) remote="${COMP_WORDS[1]}" ;;
 304                        git)       remote="${COMP_WORDS[2]}" ;;
 305                        esac
 306                        COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
 307                        ;;
 308                esac
 309                ;;
 310        esac
 311}
 312
 313_git_format_patch ()
 314{
 315        local cur="${COMP_WORDS[COMP_CWORD]}"
 316        case "$cur" in
 317        --*)
 318                COMPREPLY=($(compgen -W "
 319                        --stdout --attach --thread
 320                        --output-directory
 321                        --numbered --start-number
 322                        --keep-subject
 323                        --signoff
 324                        --in-reply-to=
 325                        --full-index --binary
 326                        " -- "$cur"))
 327                return
 328                ;;
 329        esac
 330        __git_complete_revlist
 331}
 332
 333_git_ls_remote ()
 334{
 335        local cur="${COMP_WORDS[COMP_CWORD]}"
 336        COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 337}
 338
 339_git_ls_tree ()
 340{
 341        __git_complete_file
 342}
 343
 344_git_log ()
 345{
 346        __git_complete_revlist
 347}
 348
 349_git_merge ()
 350{
 351        local cur="${COMP_WORDS[COMP_CWORD]}"
 352        case "$cur" in
 353        --*)
 354                COMPREPLY=($(compgen -W "
 355                        --no-commit --no-summary --squash
 356                        " -- "$cur"))
 357                return
 358        esac
 359        if [ $COMP_CWORD -gt 1 -a X-s = "X${COMP_WORDS[COMP_CWORD-1]}" ]
 360        then
 361                COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
 362        else
 363                COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 364        fi
 365}
 366
 367_git_merge_base ()
 368{
 369        local cur="${COMP_WORDS[COMP_CWORD]}"
 370        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 371}
 372
 373_git_name_rev ()
 374{
 375        local cur="${COMP_WORDS[COMP_CWORD]}"
 376        COMPREPLY=($(compgen -W "--tags --all --stdin" -- "$cur"))
 377}
 378
 379_git_pull ()
 380{
 381        local cur="${COMP_WORDS[COMP_CWORD]}"
 382
 383        case "${COMP_WORDS[0]},$COMP_CWORD" in
 384        git-pull*,1)
 385                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 386                ;;
 387        git,2)
 388                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 389                ;;
 390        *)
 391                local remote
 392                case "${COMP_WORDS[0]}" in
 393                git-pull)  remote="${COMP_WORDS[1]}" ;;
 394                git)       remote="${COMP_WORDS[2]}" ;;
 395                esac
 396                COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
 397                ;;
 398        esac
 399}
 400
 401_git_push ()
 402{
 403        local cur="${COMP_WORDS[COMP_CWORD]}"
 404
 405        case "${COMP_WORDS[0]},$COMP_CWORD" in
 406        git-push*,1)
 407                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 408                ;;
 409        git,2)
 410                COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
 411                ;;
 412        *)
 413                case "$cur" in
 414                *:*)
 415                        local remote
 416                        case "${COMP_WORDS[0]}" in
 417                        git-push)  remote="${COMP_WORDS[1]}" ;;
 418                        git)       remote="${COMP_WORDS[2]}" ;;
 419                        esac
 420                        cur="${cur#*:}"
 421                        COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
 422                        ;;
 423                *)
 424                        COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
 425                        ;;
 426                esac
 427                ;;
 428        esac
 429}
 430
 431_git_reset ()
 432{
 433        local cur="${COMP_WORDS[COMP_CWORD]}"
 434        local opt="--mixed --hard --soft"
 435        COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
 436}
 437
 438_git_show ()
 439{
 440        local cur="${COMP_WORDS[COMP_CWORD]}"
 441        COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 442}
 443
 444_git ()
 445{
 446        local i c=1 command __git_dir
 447
 448        while [ $c -lt $COMP_CWORD ]; do
 449                i="${COMP_WORDS[c]}"
 450                case "$i" in
 451                --git-dir=*) __git_dir="${i#--git-dir=}" ;;
 452                --bare)      __git_dir="." ;;
 453                --version|--help|-p|--paginate) ;;
 454                *) command="$i"; break ;;
 455                esac
 456                c=$((++c))
 457        done
 458
 459        if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
 460                COMPREPLY=($(compgen -W "
 461                        --git-dir= --version --exec-path
 462                        $(__git_commands)
 463                        $(__git_aliases)
 464                        " -- "${COMP_WORDS[COMP_CWORD]}"))
 465                return;
 466        fi
 467
 468        local expansion=$(__git_aliased_command "$command")
 469        [ "$expansion" ] && command="$expansion"
 470
 471        case "$command" in
 472        branch)      _git_branch ;;
 473        cat-file)    _git_cat_file ;;
 474        checkout)    _git_checkout ;;
 475        diff)        _git_diff ;;
 476        diff-tree)   _git_diff_tree ;;
 477        fetch)       _git_fetch ;;
 478        format-patch) _git_format_patch ;;
 479        log)         _git_log ;;
 480        ls-remote)   _git_ls_remote ;;
 481        ls-tree)     _git_ls_tree ;;
 482        merge)       _git_merge;;
 483        merge-base)  _git_merge_base ;;
 484        name-rev)    _git_name_rev ;;
 485        pull)        _git_pull ;;
 486        push)        _git_push ;;
 487        reset)       _git_reset ;;
 488        show)        _git_show ;;
 489        show-branch) _git_log ;;
 490        whatchanged) _git_log ;;
 491        *)           COMPREPLY=() ;;
 492        esac
 493}
 494
 495_gitk ()
 496{
 497        local cur="${COMP_WORDS[COMP_CWORD]}"
 498        COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
 499}
 500
 501complete -o default -o nospace -F _git git
 502complete -o default            -F _gitk gitk
 503complete -o default            -F _git_branch git-branch
 504complete -o default -o nospace -F _git_cat_file git-cat-file
 505complete -o default            -F _git_checkout git-checkout
 506complete -o default -o nospace -F _git_diff git-diff
 507complete -o default            -F _git_diff_tree git-diff-tree
 508complete -o default -o nospace -F _git_fetch git-fetch
 509complete -o default -o nospace -F _git_format_patch git-format-patch
 510complete -o default -o nospace -F _git_log git-log
 511complete -o default            -F _git_ls_remote git-ls-remote
 512complete -o default -o nospace -F _git_ls_tree git-ls-tree
 513complete -o default            -F _git_merge git-merge
 514complete -o default            -F _git_merge_base git-merge-base
 515complete -o default            -F _git_name_rev git-name-rev
 516complete -o default -o nospace -F _git_pull git-pull
 517complete -o default -o nospace -F _git_push git-push
 518complete -o default            -F _git_reset git-reset
 519complete -o default            -F _git_show git-show
 520complete -o default -o nospace -F _git_log git-show-branch
 521complete -o default -o nospace -F _git_log git-whatchanged
 522
 523# The following are necessary only for Cygwin, and only are needed
 524# when the user has tab-completed the executable name and consequently
 525# included the '.exe' suffix.
 526#
 527if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
 528complete -o default -o nospace -F _git git.exe
 529complete -o default            -F _git_branch git-branch.exe
 530complete -o default -o nospace -F _git_cat_file git-cat-file.exe
 531complete -o default -o nospace -F _git_diff git-diff.exe
 532complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
 533complete -o default -o nospace -F _git_format_patch git-format-patch.exe
 534complete -o default -o nospace -F _git_log git-log.exe
 535complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
 536complete -o default            -F _git_merge_base git-merge-base.exe
 537complete -o default            -F _git_name_rev git-name-rev.exe
 538complete -o default -o nospace -F _git_push git-push.exe
 539complete -o default -o nospace -F _git_log git-show-branch.exe
 540complete -o default -o nospace -F _git_log git-whatchanged.exe
 541fi