Merge branch 'jk/format-patch-quote-special-in-from'
[gitweb.git] / contrib / completion / git-completion.bash
index 68b68d0c78fe2ce7aaa80ff0615573f3bfe04525..0df356decc436fca1ad73ab54ee1c569e06ae5f1 100755 (executable)
@@ -1,6 +1,6 @@
 #!bash
 #
-# bash completion support for core Git.
+# bash/zsh completion support for core Git.
 #
 # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
 # Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
 # To use these routines:
 #
 #    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
-#    2) Added the following line to your .bashrc:
+#    2) Add the following line to your .bashrc/.zshrc:
 #        source ~/.git-completion.sh
 #
 #    3) Consider changing your PS1 to also show the current branch:
-#        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+#         Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
+#         ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
 #
 #       The argument to __git_ps1 will be displayed only if you
 #       are currently in a git repository.  The %s token will be
 #       git@vger.kernel.org
 #
 
+if [[ -n ${ZSH_VERSION-} ]]; then
+       autoload -U +X bashcompinit && bashcompinit
+fi
+
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
 *)   COMP_WORDBREAKS="$COMP_WORDBREAKS:"
@@ -138,11 +143,12 @@ __git_ps1_show_upstream ()
                # get the upstream from the "git-svn-id: ..." in a commit message
                # (git-svn uses essentially the same procedure internally)
                local svn_upstream=($(git log --first-parent -1 \
-                                       --grep="^git-svn-id: \(${svn_url_pattern:2}\)" 2>/dev/null))
+                                       --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
                if [[ 0 -ne ${#svn_upstream[@]} ]]; then
                        svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
                        svn_upstream=${svn_upstream%@*}
-                       for ((n=1; "$n" <= "${#svn_remote[@]}"; ++n)); do
+                       local n_stop="${#svn_remote[@]}"
+                       for ((n=1; n <= n_stop; ++n)); do
                                svn_upstream=${svn_upstream#${svn_remote[$n]}}
                        done
 
@@ -240,6 +246,8 @@ __git_ps1 ()
                                fi
                        elif [ -f "$g/MERGE_HEAD" ]; then
                                r="|MERGING"
+                       elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
+                               r="|CHERRY-PICKING"
                        elif [ -f "$g/BISECT_LOG" ]; then
                                r="|BISECTING"
                        fi
@@ -321,7 +329,135 @@ __gitcomp_1 ()
        done
 }
 
+# The following function is based on code from:
+#
+#   bash_completion - programmable completion functions for bash 3.2+
+#
+#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
+#             © 2009-2010, Bash Completion Maintainers
+#                     <bash-completion-devel@lists.alioth.debian.org>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2, or (at your option)
+#   any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#   The latest version of this software can be obtained here:
+#
+#   http://bash-completion.alioth.debian.org/
+#
+#   RELEASE: 2.x
+
+# This function can be used to access a tokenized list of words
+# on the command line:
+#
+#      __git_reassemble_comp_words_by_ref '=:'
+#      if test "${words_[cword_-1]}" = -w
+#      then
+#              ...
+#      fi
+#
+# The argument should be a collection of characters from the list of
+# word completion separators (COMP_WORDBREAKS) to treat as ordinary
+# characters.
+#
+# This is roughly equivalent to going back in time and setting
+# COMP_WORDBREAKS to exclude those characters.  The intent is to
+# make option types like --date=<type> and <rev>:<path> easy to
+# recognize by treating each shell word as a single token.
+#
+# It is best not to set COMP_WORDBREAKS directly because the value is
+# shared with other completion scripts.  By the time the completion
+# function gets called, COMP_WORDS has already been populated so local
+# changes to COMP_WORDBREAKS have no effect.
+#
+# Output: words_, cword_, cur_.
+
+__git_reassemble_comp_words_by_ref()
+{
+       local exclude i j first
+       # Which word separators to exclude?
+       exclude="${1//[^$COMP_WORDBREAKS]}"
+       cword_=$COMP_CWORD
+       if [ -z "$exclude" ]; then
+               words_=("${COMP_WORDS[@]}")
+               return
+       fi
+       # List of word completion separators has shrunk;
+       # re-assemble words to complete.
+       for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
+               # Append each nonempty word consisting of just
+               # word separator characters to the current word.
+               first=t
+               while
+                       [ $i -gt 0 ] &&
+                       [ -n "${COMP_WORDS[$i]}" ] &&
+                       # word consists of excluded word separators
+                       [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
+               do
+                       # Attach to the previous token,
+                       # unless the previous token is the command name.
+                       if [ $j -ge 2 ] && [ -n "$first" ]; then
+                               ((j--))
+                       fi
+                       first=
+                       words_[$j]=${words_[j]}${COMP_WORDS[i]}
+                       if [ $i = $COMP_CWORD ]; then
+                               cword_=$j
+                       fi
+                       if (($i < ${#COMP_WORDS[@]} - 1)); then
+                               ((i++))
+                       else
+                               # Done.
+                               return
+                       fi
+               done
+               words_[$j]=${words_[j]}${COMP_WORDS[i]}
+               if [ $i = $COMP_CWORD ]; then
+                       cword_=$j
+               fi
+       done
+}
+
 if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
+if [[ -z ${ZSH_VERSION:+set} ]]; then
+_get_comp_words_by_ref ()
+{
+       local exclude cur_ words_ cword_
+       if [ "$1" = "-n" ]; then
+               exclude=$2
+               shift 2
+       fi
+       __git_reassemble_comp_words_by_ref "$exclude"
+       cur_=${words_[cword_]}
+       while [ $# -gt 0 ]; do
+               case "$1" in
+               cur)
+                       cur=$cur_
+                       ;;
+               prev)
+                       prev=${words_[$cword_-1]}
+                       ;;
+               words)
+                       words=("${words_[@]}")
+                       ;;
+               cword)
+                       cword=$cword_
+                       ;;
+               esac
+               shift
+       done
+}
+else
 _get_comp_words_by_ref ()
 {
        while [ $# -gt 0 ]; do
@@ -347,6 +483,7 @@ _get_comp_words_by_ref ()
        done
 }
 fi
+fi
 
 # __gitcomp accepts 1, 2, 3, or 4 arguments
 # generates completion reply with compgen
@@ -408,10 +545,12 @@ __git_tags ()
        done
 }
 
-# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
+# __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments
+# presence of 2nd argument means use the guess heuristic employed
+# by checkout for tracking branches
 __git_refs ()
 {
-       local i is_hash=y dir="$(__gitdir "${1-}")"
+       local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
        local cur format refs
        _get_comp_words_by_ref -n =: cur
        if [ -d "$dir" ]; then
@@ -419,6 +558,7 @@ __git_refs ()
                refs|refs/*)
                        format="refname"
                        refs="${cur%/*}"
+                       track=""
                        ;;
                *)
                        for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
@@ -430,6 +570,21 @@ __git_refs ()
                esac
                git --git-dir="$dir" for-each-ref --format="%($format)" \
                        $refs
+               if [ -n "$track" ]; then
+                       # employ the heuristic used by git checkout
+                       # Try to find a remote branch that matches the completion word
+                       # but only output if the branch name is unique
+                       local ref entry
+                       git --git-dir="$dir" for-each-ref --shell --format="ref=%(refname:short)" \
+                               "refs/remotes/" | \
+                       while read entry; do
+                               eval "$entry"
+                               ref="${ref#*/}"
+                               if [[ "$ref" == "$cur"* ]]; then
+                                       echo "$ref"
+                               fi
+                       done | uniq -u
+               fi
                return
        fi
        for i in $(git ls-remote "$dir" 2>/dev/null); do
@@ -509,11 +664,14 @@ __git_compute_merge_strategies ()
        : ${__git_merge_strategies:=$(__git_list_merge_strategies)}
 }
 
-__git_complete_file ()
+__git_complete_revlist_file ()
 {
        local pfx ls ref cur
        _get_comp_words_by_ref -n =: cur
        case "$cur" in
+       *..?*:*)
+               return
+               ;;
        ?*:*)
                ref="${cur%%:*}"
                cur="${cur#*:}"
@@ -527,7 +685,7 @@ __git_complete_file ()
                *)
                        ls="$ref"
                        ;;
-           esac
+               esac
 
                case "$COMP_WORDBREAKS" in
                *:*) : great ;;
@@ -552,17 +710,6 @@ __git_complete_file ()
                                       s/^.*    //')" \
                        -- "$cur"))
                ;;
-       *)
-               __gitcomp "$(__git_refs)"
-               ;;
-       esac
-}
-
-__git_complete_revlist ()
-{
-       local pfx cur
-       _get_comp_words_by_ref -n =: cur
-       case "$cur" in
        *...*)
                pfx="${cur%...*}..."
                cur="${cur#*...}"
@@ -579,6 +726,17 @@ __git_complete_revlist ()
        esac
 }
 
+
+__git_complete_file ()
+{
+       __git_complete_revlist_file
+}
+
+__git_complete_revlist ()
+{
+       __git_complete_revlist_file
+}
+
 __git_complete_remote_or_refspec ()
 {
        local cur words cword
@@ -744,7 +902,6 @@ __git_list_porcelain_commands ()
                quiltimport)      : import;;
                read-tree)        : plumbing;;
                receive-pack)     : plumbing;;
-               reflog)           : plumbing;;
                remote-*)         : transport;;
                repo-config)      : deprecated;;
                rerere)           : plumbing;;
@@ -783,6 +940,19 @@ __git_compute_porcelain_commands ()
        : ${__git_porcelain_commands:=$(__git_list_porcelain_commands)}
 }
 
+__git_pretty_aliases ()
+{
+       local i IFS=$'\n'
+       for i in $(git --git-dir="$(__gitdir)" config --get-regexp "pretty\..*" 2>/dev/null); do
+               case "$i" in
+               pretty.*)
+                       i="${i#pretty.}"
+                       echo "${i/ */}"
+                       ;;
+               esac
+       done
+}
+
 __git_aliases ()
 {
        local i IFS=$'\n'
@@ -945,12 +1115,16 @@ _git_bisect ()
        local subcommands="start bad good skip reset visualize replay log run"
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
        if [ -z "$subcommand" ]; then
-               __gitcomp "$subcommands"
+               if [ -f "$(__gitdir)"/BISECT_START ]; then
+                       __gitcomp "$subcommands"
+               else
+                       __gitcomp "replay start"
+               fi
                return
        fi
 
        case "$subcommand" in
-       bad|good|reset|skip)
+       bad|good|reset|skip|start)
                __gitcomp "$(__git_refs)"
                ;;
        *)
@@ -1030,7 +1204,13 @@ _git_checkout ()
                        "
                ;;
        *)
-               __gitcomp "$(__git_refs)"
+               # check if --track, --no-track, or --no-guess was specified
+               # if so, disable DWIM mode
+               local flags="--track --no-track --no-guess" track=1
+               if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
+                       track=''
+               fi
+               __gitcomp "$(__git_refs '' $track)"
                ;;
        esac
 }
@@ -1173,17 +1353,17 @@ _git_diff ()
        case "$cur" in
        --*)
                __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
-                       --base --ours --theirs
+                       --base --ours --theirs --no-index
                        $__git_diff_common_options
                        "
                return
                ;;
        esac
-       __git_complete_file
+       __git_complete_revlist_file
 }
 
 __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
-                       tkdiff vimdiff gvimdiff xxdiff araxis p4merge
+                       tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
 "
 
 _git_difftool ()
@@ -1331,7 +1511,7 @@ _git_help ()
                ;;
        esac
        __git_compute_all_commands
-       __gitcomp "$__git_all_commands
+       __gitcomp "$__git_all_commands $(__git_aliases)
                attributes cli core-tutorial cvs-migration
                diffcore gitk glossary hooks ignore modules
                repository-layout tutorial tutorial-2
@@ -1397,12 +1577,14 @@ __git_log_common_options="
        --max-count=
        --max-age= --since= --after=
        --min-age= --until= --before=
+       --min-parents= --max-parents=
+       --no-min-parents --no-max-parents
 "
 # Options that go well for log and gitk (not shortlog)
 __git_log_gitk_options="
        --dense --sparse --full-history
        --simplify-merges --simplify-by-decoration
-       --left-right
+       --left-right --notes --no-notes
 "
 # Options that go well for log and shortlog (not gitk)
 __git_log_shortlog_options="
@@ -1426,12 +1608,12 @@ _git_log ()
        _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --pretty=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--pretty=}"
                return
                ;;
        --format=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--format=}"
                return
                ;;
@@ -1529,20 +1711,51 @@ _git_name_rev ()
 
 _git_notes ()
 {
-       local subcommands="edit show"
-       local words cword
-       _get_comp_words_by_ref -n =: words cword
-       if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
-               __gitcomp "$subcommands"
-               return
-       fi
+       local subcommands='add append copy edit list prune remove show'
+       local subcommand="$(__git_find_on_cmdline "$subcommands")"
+       local cur words cword
+       _get_comp_words_by_ref -n =: cur words cword
 
-       case "${words[cword-1]}" in
-       -m|-F)
-               COMPREPLY=()
+       case "$subcommand,$cur" in
+       ,--*)
+               __gitcomp '--ref'
+               ;;
+       ,*)
+               case "${words[cword-1]}" in
+               --ref)
+                       __gitcomp "$(__git_refs)"
+                       ;;
+               *)
+                       __gitcomp "$subcommands --ref"
+                       ;;
+               esac
+               ;;
+       add,--reuse-message=*|append,--reuse-message=*)
+               __gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}"
+               ;;
+       add,--reedit-message=*|append,--reedit-message=*)
+               __gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}"
+               ;;
+       add,--*|append,--*)
+               __gitcomp '--file= --message= --reedit-message=
+                               --reuse-message='
+               ;;
+       copy,--*)
+               __gitcomp '--stdin'
+               ;;
+       prune,--*)
+               __gitcomp '--dry-run --verbose'
+               ;;
+       prune,*)
                ;;
        *)
-               __gitcomp "$(__git_refs)"
+               case "${words[cword-1]}" in
+               -m|-F)
+                       ;;
+               *)
+                       __gitcomp "$(__git_refs)"
+                       ;;
+               esac
                ;;
        esac
 }
@@ -1620,6 +1833,18 @@ _git_rebase ()
        __gitcomp "$(__git_refs)"
 }
 
+_git_reflog ()
+{
+       local subcommands="show delete expire"
+       local subcommand="$(__git_find_on_cmdline "$subcommands")"
+
+       if [ -z "$subcommand" ]; then
+               __gitcomp "$subcommands"
+       else
+               __gitcomp "$(__git_refs)"
+       fi
+}
+
 __git_send_email_confirm_options="always never auto cc compose"
 __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
 
@@ -1855,30 +2080,50 @@ _git_config ()
                ;;
        esac
        __gitcomp "
-               add.ignore-errors
+               add.ignoreErrors
+               advice.commitBeforeMerge
+               advice.detachedHead
+               advice.implicitIdentity
+               advice.pushNonFastForward
+               advice.resolveConflict
+               advice.statusHints
                alias.
+               am.keepcr
                apply.ignorewhitespace
                apply.whitespace
                branch.autosetupmerge
                branch.autosetuprebase
+               browser.
                clean.requireForce
                color.branch
                color.branch.current
                color.branch.local
                color.branch.plain
                color.branch.remote
+               color.decorate.HEAD
+               color.decorate.branch
+               color.decorate.remoteBranch
+               color.decorate.stash
+               color.decorate.tag
                color.diff
                color.diff.commit
                color.diff.frag
+               color.diff.func
                color.diff.meta
                color.diff.new
                color.diff.old
                color.diff.plain
                color.diff.whitespace
                color.grep
-               color.grep.external
+               color.grep.context
+               color.grep.filename
+               color.grep.function
+               color.grep.linenumber
                color.grep.match
+               color.grep.selected
+               color.grep.separator
                color.interactive
+               color.interactive.error
                color.interactive.header
                color.interactive.help
                color.interactive.prompt
@@ -1892,21 +2137,29 @@ _git_config ()
                color.status.untracked
                color.status.updated
                color.ui
+               commit.status
                commit.template
+               core.abbrevguard
+               core.askpass
+               core.attributesfile
                core.autocrlf
                core.bare
+               core.bigFileThreshold
                core.compression
                core.createObject
                core.deltaBaseCacheLimit
                core.editor
+               core.eol
                core.excludesfile
                core.fileMode
                core.fsyncobjectfiles
                core.gitProxy
                core.ignoreCygwinFSTricks
                core.ignoreStat
+               core.ignorecase
                core.logAllRefUpdates
                core.loosecompression
+               core.notesRef
                core.packedGitLimit
                core.packedGitWindowSize
                core.pager
@@ -1916,6 +2169,7 @@ _git_config ()
                core.repositoryFormatVersion
                core.safecrlf
                core.sharedRepository
+               core.sparseCheckout
                core.symlinks
                core.trustctime
                core.warnAmbiguousRefs
@@ -1923,15 +2177,17 @@ _git_config ()
                core.worktree
                diff.autorefreshindex
                diff.external
+               diff.ignoreSubmodules
                diff.mnemonicprefix
+               diff.noprefix
                diff.renameLimit
-               diff.renameLimit.
                diff.renames
                diff.suppressBlankEmpty
                diff.tool
                diff.wordRegex
                difftool.
                difftool.prompt
+               fetch.recurseSubmodules
                fetch.unpackLimit
                format.attach
                format.cc
@@ -1943,6 +2199,8 @@ _git_config ()
                format.subjectprefix
                format.suffix
                format.thread
+               format.to
+               gc.
                gc.aggressiveWindow
                gc.auto
                gc.autopacklimit
@@ -1980,15 +2238,20 @@ _git_config ()
                http.lowSpeedLimit
                http.lowSpeedTime
                http.maxRequests
+               http.minSessions
                http.noEPSV
+               http.postBuffer
                http.proxy
                http.sslCAInfo
                http.sslCAPath
                http.sslCert
+               http.sslCertPasswordProtected
                http.sslKey
                http.sslVerify
+               http.useragent
                i18n.commitEncoding
                i18n.logOutputEncoding
+               imap.authMethod
                imap.folder
                imap.host
                imap.pass
@@ -1997,6 +2260,7 @@ _git_config ()
                imap.sslverify
                imap.tunnel
                imap.user
+               init.templatedir
                instaweb.browser
                instaweb.httpd
                instaweb.local
@@ -2004,19 +2268,29 @@ _git_config ()
                instaweb.port
                interactive.singlekey
                log.date
+               log.decorate
                log.showroot
                mailmap.file
                man.
                man.viewer
+               merge.
                merge.conflictstyle
                merge.log
                merge.renameLimit
+               merge.renormalize
                merge.stat
                merge.tool
                merge.verbosity
                mergetool.
                mergetool.keepBackup
+               mergetool.keepTemporaries
                mergetool.prompt
+               notes.displayRef
+               notes.rewrite.
+               notes.rewrite.amend
+               notes.rewrite.rebase
+               notes.rewriteMode
+               notes.rewriteRef
                pack.compression
                pack.deltaCacheLimit
                pack.deltaCacheSize
@@ -2027,31 +2301,42 @@ _git_config ()
                pack.window
                pack.windowMemory
                pager.
+               pretty.
                pull.octopus
                pull.twohead
                push.default
+               rebase.autosquash
                rebase.stat
+               receive.autogc
                receive.denyCurrentBranch
+               receive.denyDeleteCurrent
                receive.denyDeletes
                receive.denyNonFastForwards
                receive.fsckObjects
                receive.unpackLimit
+               receive.updateserverinfo
+               remotes.
                repack.usedeltabaseoffset
                rerere.autoupdate
                rerere.enabled
+               sendemail.
                sendemail.aliasesfile
-               sendemail.aliasesfiletype
+               sendemail.aliasfiletype
                sendemail.bcc
                sendemail.cc
                sendemail.cccmd
                sendemail.chainreplyto
                sendemail.confirm
                sendemail.envelopesender
+               sendemail.from
+               sendemail.identity
                sendemail.multiedit
                sendemail.signedoffbycc
+               sendemail.smtpdomain
                sendemail.smtpencryption
                sendemail.smtppass
                sendemail.smtpserver
+               sendemail.smtpserveroption
                sendemail.smtpserverport
                sendemail.smtpuser
                sendemail.suppresscc
@@ -2062,6 +2347,8 @@ _git_config ()
                showbranch.default
                status.relativePaths
                status.showUntrackedFiles
+               status.submodulesummary
+               submodule.
                tar.umask
                transfer.unpackLimit
                url.
@@ -2175,12 +2462,12 @@ _git_show ()
        _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --pretty=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--pretty=}"
                return
                ;;
        --format=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--format=}"
                return
                ;;
@@ -2420,6 +2707,11 @@ _git ()
 {
        local i c=1 command __git_dir
 
+       if [[ -n ${ZSH_VERSION-} ]]; then
+               emulate -L bash
+               setopt KSH_TYPESET
+       fi
+
        local cur words cword
        _get_comp_words_by_ref -n =: cur words cword
        while [ $c -lt $cword ]; do
@@ -2455,17 +2747,22 @@ _git ()
        fi
 
        local completion_func="_git_${command//-/_}"
-       declare -F $completion_func >/dev/null && $completion_func && return
+       declare -f $completion_func >/dev/null && $completion_func && return
 
        local expansion=$(__git_aliased_command "$command")
        if [ -n "$expansion" ]; then
                completion_func="_git_${expansion//-/_}"
-               declare -F $completion_func >/dev/null && $completion_func
+               declare -f $completion_func >/dev/null && $completion_func
        fi
 }
 
 _gitk ()
 {
+       if [[ -n ${ZSH_VERSION-} ]]; then
+               emulate -L bash
+               setopt KSH_TYPESET
+       fi
+
        __git_has_doubledash && return
 
        local cur
@@ -2501,3 +2798,29 @@ if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
 complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
        || complete -o default -o nospace -F _git git.exe
 fi
+
+if [[ -n ${ZSH_VERSION-} ]]; then
+       shopt () {
+               local option
+               if [ $# -ne 2 ]; then
+                       echo "USAGE: $0 (-q|-s|-u) <option>" >&2
+                       return 1
+               fi
+               case "$2" in
+               nullglob)
+                       option="$2"
+                       ;;
+               *)
+                       echo "$0: invalid option: $2" >&2
+                       return 1
+               esac
+               case "$1" in
+               -q)     setopt | grep -q "$option" ;;
+               -u)     unsetopt "$option" ;;
+               -s)     setopt "$option" ;;
+               *)
+                       echo "$0: invalid flag: $1" >&2
+                       return 1
+               esac
+       }
+fi