Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge pull request #132 from Draiken/master

Updating git.completion.bash
  • Loading branch information...
commit 776b17c46c07b0100c52bd375afe8ff230927dc9 2 parents 5ce8971 + 868fcd0
Travis Swicegood tswicegood authored

Showing 1 changed file with 1,420 additions and 472 deletions. Show diff stats Hide diff stats

  1. +1,420 472 completion/available/git.completion.bash
1,892 completion/available/git.completion.bash
... ... @@ -1,6 +1,6 @@
1 1 #!bash
2 2 #
3   -# bash completion support for core Git.
  3 +# bash/zsh completion support for core Git.
4 4 #
5 5 # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
6 6 # Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
@@ -18,27 +18,48 @@
18 18 # To use these routines:
19 19 #
20 20 # 1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
21   -# 2) Added the following line to your .bashrc:
  21 +# 2) Add the following line to your .bashrc/.zshrc:
22 22 # source ~/.git-completion.sh
23 23 #
24   -# 3) You may want to make sure the git executable is available
25   -# in your PATH before this script is sourced, as some caching
26   -# is performed while the script loads. If git isn't found
27   -# at source time then all lookups will be done on demand,
28   -# which may be slightly slower.
29   -#
30   -# 4) Consider changing your PS1 to also show the current branch:
31   -# PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
  24 +# 3) Consider changing your PS1 to also show the current branch:
  25 +# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
  26 +# ZSH: PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
32 27 #
33 28 # The argument to __git_ps1 will be displayed only if you
34 29 # are currently in a git repository. The %s token will be
35 30 # the name of the current branch.
36 31 #
37   -# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
38   -# value, unstaged (*) and staged (+) changes will be shown next
39   -# to the branch name. You can configure this per-repository
40   -# with the bash.showDirtyState variable, which defaults to true
41   -# once GIT_PS1_SHOWDIRTYSTATE is enabled.
  32 +# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty
  33 +# value, unstaged (*) and staged (+) changes will be shown next
  34 +# to the branch name. You can configure this per-repository
  35 +# with the bash.showDirtyState variable, which defaults to true
  36 +# once GIT_PS1_SHOWDIRTYSTATE is enabled.
  37 +#
  38 +# You can also see if currently something is stashed, by setting
  39 +# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
  40 +# then a '$' will be shown next to the branch name.
  41 +#
  42 +# If you would like to see if there're untracked files, then you can
  43 +# set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're
  44 +# untracked files, then a '%' will be shown next to the branch name.
  45 +#
  46 +# If you would like to see the difference between HEAD and its
  47 +# upstream, set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates
  48 +# you are behind, ">" indicates you are ahead, and "<>"
  49 +# indicates you have diverged. You can further control
  50 +# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated
  51 +# list of values:
  52 +# verbose show number of commits ahead/behind (+/-) upstream
  53 +# legacy don't use the '--count' option available in recent
  54 +# versions of git-rev-list
  55 +# git always compare HEAD to @{upstream}
  56 +# svn always compare HEAD to your SVN upstream
  57 +# By default, __git_ps1 will compare HEAD to your SVN upstream
  58 +# if it can find one, or @{upstream} otherwise. Once you have
  59 +# set GIT_PS1_SHOWUPSTREAM, you can override it on a
  60 +# per-repository basis by setting the bash.showUpstream config
  61 +# variable.
  62 +#
42 63 #
43 64 # To submit patches:
44 65 #
@@ -52,6 +73,10 @@
52 73 # git@vger.kernel.org
53 74 #
54 75
  76 +if [[ -n ${ZSH_VERSION-} ]]; then
  77 + autoload -U +X bashcompinit && bashcompinit
  78 +fi
  79 +
55 80 case "$COMP_WORDBREAKS" in
56 81 *:*) : great ;;
57 82 *) COMP_WORDBREAKS="$COMP_WORDBREAKS:"
@@ -62,7 +87,7 @@ esac
62 87 __gitdir ()
63 88 {
64 89 if [ -z "${1-}" ]; then
65   - if [ -n "$__git_dir" ]; then
  90 + if [ -n "${__git_dir-}" ]; then
66 91 echo "$__git_dir"
67 92 elif [ -d .git ]; then
68 93 echo .git
@@ -76,73 +101,219 @@ __gitdir ()
76 101 fi
77 102 }
78 103
  104 +# stores the divergence from upstream in $p
  105 +# used by GIT_PS1_SHOWUPSTREAM
  106 +__git_ps1_show_upstream ()
  107 +{
  108 + local key value
  109 + local svn_remote=() svn_url_pattern count n
  110 + local upstream=git legacy="" verbose=""
  111 +
  112 + # get some config options from git-config
  113 + local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
  114 + while read -r key value; do
  115 + case "$key" in
  116 + bash.showupstream)
  117 + GIT_PS1_SHOWUPSTREAM="$value"
  118 + if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
  119 + p=""
  120 + return
  121 + fi
  122 + ;;
  123 + svn-remote.*.url)
  124 + svn_remote[ $((${#svn_remote[@]} + 1)) ]="$value"
  125 + svn_url_pattern+="\\|$value"
  126 + upstream=svn+git # default upstream is SVN if available, else git
  127 + ;;
  128 + esac
  129 + done <<< "$output"
  130 +
  131 + # parse configuration values
  132 + for option in ${GIT_PS1_SHOWUPSTREAM}; do
  133 + case "$option" in
  134 + git|svn) upstream="$option" ;;
  135 + verbose) verbose=1 ;;
  136 + legacy) legacy=1 ;;
  137 + esac
  138 + done
  139 +
  140 + # Find our upstream
  141 + case "$upstream" in
  142 + git) upstream="@{upstream}" ;;
  143 + svn*)
  144 + # get the upstream from the "git-svn-id: ..." in a commit message
  145 + # (git-svn uses essentially the same procedure internally)
  146 + local svn_upstream=($(git log --first-parent -1 \
  147 + --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
  148 + if [[ 0 -ne ${#svn_upstream[@]} ]]; then
  149 + svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
  150 + svn_upstream=${svn_upstream%@*}
  151 + local n_stop="${#svn_remote[@]}"
  152 + for ((n=1; n <= n_stop; ++n)); do
  153 + svn_upstream=${svn_upstream#${svn_remote[$n]}}
  154 + done
  155 +
  156 + if [[ -z "$svn_upstream" ]]; then
  157 + # default branch name for checkouts with no layout:
  158 + upstream=${GIT_SVN_ID:-git-svn}
  159 + else
  160 + upstream=${svn_upstream#/}
  161 + fi
  162 + elif [[ "svn+git" = "$upstream" ]]; then
  163 + upstream="@{upstream}"
  164 + fi
  165 + ;;
  166 + esac
  167 +
  168 + # Find how many commits we are ahead/behind our upstream
  169 + if [[ -z "$legacy" ]]; then
  170 + count="$(git rev-list --count --left-right \
  171 + "$upstream"...HEAD 2>/dev/null)"
  172 + else
  173 + # produce equivalent output to --count for older versions of git
  174 + local commits
  175 + if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
  176 + then
  177 + local commit behind=0 ahead=0
  178 + for commit in $commits
  179 + do
  180 + case "$commit" in
  181 + "<"*) let ++behind
  182 + ;;
  183 + *) let ++ahead
  184 + ;;
  185 + esac
  186 + done
  187 + count="$behind $ahead"
  188 + else
  189 + count=""
  190 + fi
  191 + fi
  192 +
  193 + # calculate the result
  194 + if [[ -z "$verbose" ]]; then
  195 + case "$count" in
  196 + "") # no upstream
  197 + p="" ;;
  198 + "0 0") # equal to upstream
  199 + p="=" ;;
  200 + "0 "*) # ahead of upstream
  201 + p=">" ;;
  202 + *" 0") # behind upstream
  203 + p="<" ;;
  204 + *) # diverged from upstream
  205 + p="<>" ;;
  206 + esac
  207 + else
  208 + case "$count" in
  209 + "") # no upstream
  210 + p="" ;;
  211 + "0 0") # equal to upstream
  212 + p=" u=" ;;
  213 + "0 "*) # ahead of upstream
  214 + p=" u+${count#0 }" ;;
  215 + *" 0") # behind upstream
  216 + p=" u-${count% 0}" ;;
  217 + *) # diverged from upstream
  218 + p=" u+${count#* }-${count% *}" ;;
  219 + esac
  220 + fi
  221 +
  222 +}
  223 +
  224 +
79 225 # __git_ps1 accepts 0 or 1 arguments (i.e., format string)
80 226 # returns text to add to bash PS1 prompt (includes branch name)
81 227 __git_ps1 ()
82 228 {
83   - local g="$(git rev-parse --git-dir 2>/dev/null)"
  229 + local g="$(__gitdir)"
84 230 if [ -n "$g" ]; then
85   - local r
86   - local b
87   - if [ -d "$g/rebase-apply" ]
88   - then
89   - if test -f "$g/rebase-apply/rebasing"
90   - then
91   - r="|REBASE"
92   - elif test -f "$g/rebase-apply/applying"
93   - then
94   - r="|AM"
95   - else
96   - r="|AM/REBASE"
97   - fi
98   - b="$(git symbolic-ref HEAD 2>/dev/null)"
99   - elif [ -f "$g/rebase-merge/interactive" ]
100   - then
  231 + local r=""
  232 + local b=""
  233 + if [ -f "$g/rebase-merge/interactive" ]; then
101 234 r="|REBASE-i"
102 235 b="$(cat "$g/rebase-merge/head-name")"
103   - elif [ -d "$g/rebase-merge" ]
104   - then
  236 + elif [ -d "$g/rebase-merge" ]; then
105 237 r="|REBASE-m"
106 238 b="$(cat "$g/rebase-merge/head-name")"
107   - elif [ -f "$g/MERGE_HEAD" ]
108   - then
109   - r="|MERGING"
110   - b="$(git symbolic-ref HEAD 2>/dev/null)"
111 239 else
112   - if [ -f "$g/BISECT_LOG" ]
113   - then
114   - r="|BISECTING"
115   - fi
116   - if ! b="$(git symbolic-ref HEAD 2>/dev/null)"
117   - then
118   - if ! b="$(git describe --exact-match HEAD 2>/dev/null)"
119   - then
120   - b="$(cut -c1-7 "$g/HEAD")..."
  240 + if [ -d "$g/rebase-apply" ]; then
  241 + if [ -f "$g/rebase-apply/rebasing" ]; then
  242 + r="|REBASE"
  243 + elif [ -f "$g/rebase-apply/applying" ]; then
  244 + r="|AM"
  245 + else
  246 + r="|AM/REBASE"
121 247 fi
  248 + elif [ -f "$g/MERGE_HEAD" ]; then
  249 + r="|MERGING"
  250 + elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
  251 + r="|CHERRY-PICKING"
  252 + elif [ -f "$g/BISECT_LOG" ]; then
  253 + r="|BISECTING"
122 254 fi
  255 +
  256 + b="$(git symbolic-ref HEAD 2>/dev/null)" || {
  257 +
  258 + b="$(
  259 + case "${GIT_PS1_DESCRIBE_STYLE-}" in
  260 + (contains)
  261 + git describe --contains HEAD ;;
  262 + (branch)
  263 + git describe --contains --all HEAD ;;
  264 + (describe)
  265 + git describe HEAD ;;
  266 + (* | default)
  267 + git describe --tags --exact-match HEAD ;;
  268 + esac 2>/dev/null)" ||
  269 +
  270 + b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." ||
  271 + b="unknown"
  272 + b="($b)"
  273 + }
123 274 fi
124 275
125   - local w
126   - local i
  276 + local w=""
  277 + local i=""
  278 + local s=""
  279 + local u=""
  280 + local c=""
  281 + local p=""
127 282
128   - if test -n "$GIT_PS1_SHOWDIRTYSTATE"; then
129   - if test "$(git config --bool bash.showDirtyState)" != "false"; then
130   - git diff --no-ext-diff --ignore-submodules \
131   - --quiet --exit-code || w="*"
132   - if git rev-parse --quiet --verify HEAD >/dev/null; then
133   - git diff-index --cached --quiet \
134   - --ignore-submodules HEAD -- || i="+"
135   - else
136   - i="#"
  283 + if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then
  284 + if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then
  285 + c="BARE:"
  286 + else
  287 + b="GIT_DIR!"
  288 + fi
  289 + elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
  290 + if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
  291 + if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
  292 + git diff --no-ext-diff --quiet --exit-code || w="*"
  293 + if git rev-parse --quiet --verify HEAD >/dev/null; then
  294 + git diff-index --cached --quiet HEAD -- || i="+"
  295 + else
  296 + i="#"
  297 + fi
137 298 fi
138 299 fi
139   - fi
  300 + if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
  301 + git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
  302 + fi
140 303
141   - if [ -n "${1-}" ]; then
142   - printf "$1" "${b##refs/heads/}$w$i$r"
143   - else
144   - printf " (%s)" "${b##refs/heads/}$w$i$r"
  304 + if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
  305 + if [ -n "$(git ls-files --others --exclude-standard)" ]; then
  306 + u="%"
  307 + fi
  308 + fi
  309 +
  310 + if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
  311 + __git_ps1_show_upstream
  312 + fi
145 313 fi
  314 +
  315 + local f="$w$i$s$u"
  316 + printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p"
146 317 fi
147 318 }
148 319
@@ -159,15 +330,177 @@ __gitcomp_1 ()
159 330 done
160 331 }
161 332
162   -# __gitcomp accepts 1, 2, 3, or 4 arguments
163   -# generates completion reply with compgen
  333 +# The following function is based on code from:
  334 +#
  335 +# bash_completion - programmable completion functions for bash 3.2+
  336 +#
  337 +# Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
  338 +# © 2009-2010, Bash Completion Maintainers
  339 +# <bash-completion-devel@lists.alioth.debian.org>
  340 +#
  341 +# This program is free software; you can redistribute it and/or modify
  342 +# it under the terms of the GNU General Public License as published by
  343 +# the Free Software Foundation; either version 2, or (at your option)
  344 +# any later version.
  345 +#
  346 +# This program is distributed in the hope that it will be useful,
  347 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
  348 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  349 +# GNU General Public License for more details.
  350 +#
  351 +# You should have received a copy of the GNU General Public License
  352 +# along with this program; if not, write to the Free Software Foundation,
  353 +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  354 +#
  355 +# The latest version of this software can be obtained here:
  356 +#
  357 +# http://bash-completion.alioth.debian.org/
  358 +#
  359 +# RELEASE: 2.x
  360 +
  361 +# This function can be used to access a tokenized list of words
  362 +# on the command line:
  363 +#
  364 +# __git_reassemble_comp_words_by_ref '=:'
  365 +# if test "${words_[cword_-1]}" = -w
  366 +# then
  367 +# ...
  368 +# fi
  369 +#
  370 +# The argument should be a collection of characters from the list of
  371 +# word completion separators (COMP_WORDBREAKS) to treat as ordinary
  372 +# characters.
  373 +#
  374 +# This is roughly equivalent to going back in time and setting
  375 +# COMP_WORDBREAKS to exclude those characters. The intent is to
  376 +# make option types like --date=<type> and <rev>:<path> easy to
  377 +# recognize by treating each shell word as a single token.
  378 +#
  379 +# It is best not to set COMP_WORDBREAKS directly because the value is
  380 +# shared with other completion scripts. By the time the completion
  381 +# function gets called, COMP_WORDS has already been populated so local
  382 +# changes to COMP_WORDBREAKS have no effect.
  383 +#
  384 +# Output: words_, cword_, cur_.
  385 +
  386 +__git_reassemble_comp_words_by_ref()
  387 +{
  388 + local exclude i j first
  389 + # Which word separators to exclude?
  390 + exclude="${1//[^$COMP_WORDBREAKS]}"
  391 + cword_=$COMP_CWORD
  392 + if [ -z "$exclude" ]; then
  393 + words_=("${COMP_WORDS[@]}")
  394 + return
  395 + fi
  396 + # List of word completion separators has shrunk;
  397 + # re-assemble words to complete.
  398 + for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
  399 + # Append each nonempty word consisting of just
  400 + # word separator characters to the current word.
  401 + first=t
  402 + while
  403 + [ $i -gt 0 ] &&
  404 + [ -n "${COMP_WORDS[$i]}" ] &&
  405 + # word consists of excluded word separators
  406 + [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
  407 + do
  408 + # Attach to the previous token,
  409 + # unless the previous token is the command name.
  410 + if [ $j -ge 2 ] && [ -n "$first" ]; then
  411 + ((j--))
  412 + fi
  413 + first=
  414 + words_[$j]=${words_[j]}${COMP_WORDS[i]}
  415 + if [ $i = $COMP_CWORD ]; then
  416 + cword_=$j
  417 + fi
  418 + if (($i < ${#COMP_WORDS[@]} - 1)); then
  419 + ((i++))
  420 + else
  421 + # Done.
  422 + return
  423 + fi
  424 + done
  425 + words_[$j]=${words_[j]}${COMP_WORDS[i]}
  426 + if [ $i = $COMP_CWORD ]; then
  427 + cword_=$j
  428 + fi
  429 + done
  430 +}
  431 +
  432 +if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
  433 +if [[ -z ${ZSH_VERSION:+set} ]]; then
  434 +_get_comp_words_by_ref ()
  435 +{
  436 + local exclude cur_ words_ cword_
  437 + if [ "$1" = "-n" ]; then
  438 + exclude=$2
  439 + shift 2
  440 + fi
  441 + __git_reassemble_comp_words_by_ref "$exclude"
  442 + cur_=${words_[cword_]}
  443 + while [ $# -gt 0 ]; do
  444 + case "$1" in
  445 + cur)
  446 + cur=$cur_
  447 + ;;
  448 + prev)
  449 + prev=${words_[$cword_-1]}
  450 + ;;
  451 + words)
  452 + words=("${words_[@]}")
  453 + ;;
  454 + cword)
  455 + cword=$cword_
  456 + ;;
  457 + esac
  458 + shift
  459 + done
  460 +}
  461 +else
  462 +_get_comp_words_by_ref ()
  463 +{
  464 + while [ $# -gt 0 ]; do
  465 + case "$1" in
  466 + cur)
  467 + cur=${COMP_WORDS[COMP_CWORD]}
  468 + ;;
  469 + prev)
  470 + prev=${COMP_WORDS[COMP_CWORD-1]}
  471 + ;;
  472 + words)
  473 + words=("${COMP_WORDS[@]}")
  474 + ;;
  475 + cword)
  476 + cword=$COMP_CWORD
  477 + ;;
  478 + -n)
  479 + # assume COMP_WORDBREAKS is already set sanely
  480 + shift
  481 + ;;
  482 + esac
  483 + shift
  484 + done
  485 +}
  486 +fi
  487 +fi
  488 +
  489 +# Generates completion reply with compgen, appending a space to possible
  490 +# completion words, if necessary.
  491 +# It accepts 1 to 4 arguments:
  492 +# 1: List of possible completion words.
  493 +# 2: A prefix to be added to each possible completion word (optional).
  494 +# 3: Generate possible completion matches for this word (optional).
  495 +# 4: A suffix to be appended to each possible completion word (optional).
164 496 __gitcomp ()
165 497 {
166   - local cur="${COMP_WORDS[COMP_CWORD]}"
  498 + local cur_="$cur"
  499 +
167 500 if [ $# -gt 2 ]; then
168   - cur="$3"
  501 + cur_="$3"
169 502 fi
170   - case "$cur" in
  503 + case "$cur_" in
171 504 --*=)
172 505 COMPREPLY=()
173 506 ;;
@@ -175,80 +508,118 @@ __gitcomp ()
175 508 local IFS=$'\n'
176 509 COMPREPLY=($(compgen -P "${2-}" \
177 510 -W "$(__gitcomp_1 "${1-}" "${4-}")" \
178   - -- "$cur"))
  511 + -- "$cur_"))
179 512 ;;
180 513 esac
181 514 }
182 515
183   -# __git_heads accepts 0 or 1 arguments (to pass to __gitdir)
  516 +# Generates completion reply with compgen from newline-separated possible
  517 +# completion words by appending a space to all of them.
  518 +# It accepts 1 to 4 arguments:
  519 +# 1: List of possible completion words, separated by a single newline.
  520 +# 2: A prefix to be added to each possible completion word (optional).
  521 +# 3: Generate possible completion matches for this word (optional).
  522 +# 4: A suffix to be appended to each possible completion word instead of
  523 +# the default space (optional). If specified but empty, nothing is
  524 +# appended.
  525 +__gitcomp_nl ()
  526 +{
  527 + local s=$'\n' IFS=' '$'\t'$'\n'
  528 + local cur_="$cur" suffix=" "
  529 +
  530 + if [ $# -gt 2 ]; then
  531 + cur_="$3"
  532 + if [ $# -gt 3 ]; then
  533 + suffix="$4"
  534 + fi
  535 + fi
  536 +
  537 + IFS=$s
  538 + COMPREPLY=($(compgen -P "${2-}" -S "$suffix" -W "$1" -- "$cur_"))
  539 +}
  540 +
184 541 __git_heads ()
185 542 {
186   - local cmd i is_hash=y dir="$(__gitdir "${1-}")"
  543 + local dir="$(__gitdir)"
187 544 if [ -d "$dir" ]; then
188 545 git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
189 546 refs/heads
190 547 return
191 548 fi
192   - for i in $(git ls-remote "${1-}" 2>/dev/null); do
193   - case "$is_hash,$i" in
194   - y,*) is_hash=n ;;
195   - n,*^{}) is_hash=y ;;
196   - n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
197   - n,*) is_hash=y; echo "$i" ;;
198   - esac
199   - done
200 549 }
201 550
202   -# __git_tags accepts 0 or 1 arguments (to pass to __gitdir)
203 551 __git_tags ()
204 552 {
205   - local cmd i is_hash=y dir="$(__gitdir "${1-}")"
  553 + local dir="$(__gitdir)"
206 554 if [ -d "$dir" ]; then
207 555 git --git-dir="$dir" for-each-ref --format='%(refname:short)' \
208 556 refs/tags
209 557 return
210 558 fi
211   - for i in $(git ls-remote "${1-}" 2>/dev/null); do
212   - case "$is_hash,$i" in
213   - y,*) is_hash=n ;;
214   - n,*^{}) is_hash=y ;;
215   - n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
216   - n,*) is_hash=y; echo "$i" ;;
217   - esac
218   - done
219 559 }
220 560
221   -# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
  561 +# __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments
  562 +# presence of 2nd argument means use the guess heuristic employed
  563 +# by checkout for tracking branches
222 564 __git_refs ()
223 565 {
224   - local i is_hash=y dir="$(__gitdir "${1-}")"
225   - local cur="${COMP_WORDS[COMP_CWORD]}" format refs
  566 + local i hash dir="$(__gitdir "${1-}")" track="${2-}"
  567 + local format refs
226 568 if [ -d "$dir" ]; then
227 569 case "$cur" in
228 570 refs|refs/*)
229 571 format="refname"
230 572 refs="${cur%/*}"
  573 + track=""
231 574 ;;
232 575 *)
233   - if [ -e "$dir/HEAD" ]; then echo HEAD; fi
  576 + for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
  577 + if [ -e "$dir/$i" ]; then echo $i; fi
  578 + done
234 579 format="refname:short"
235 580 refs="refs/tags refs/heads refs/remotes"
236 581 ;;
237 582 esac
238 583 git --git-dir="$dir" for-each-ref --format="%($format)" \
239 584 $refs
  585 + if [ -n "$track" ]; then
  586 + # employ the heuristic used by git checkout
  587 + # Try to find a remote branch that matches the completion word
  588 + # but only output if the branch name is unique
  589 + local ref entry
  590 + git --git-dir="$dir" for-each-ref --shell --format="ref=%(refname:short)" \
  591 + "refs/remotes/" | \
  592 + while read -r entry; do
  593 + eval "$entry"
  594 + ref="${ref#*/}"
  595 + if [[ "$ref" == "$cur"* ]]; then
  596 + echo "$ref"
  597 + fi
  598 + done | uniq -u
  599 + fi
240 600 return
241 601 fi
242   - for i in $(git ls-remote "$dir" 2>/dev/null); do
243   - case "$is_hash,$i" in
244   - y,*) is_hash=n ;;
245   - n,*^{}) is_hash=y ;;
246   - n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
247   - n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
248   - n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
249   - n,*) is_hash=y; echo "$i" ;;
250   - esac
251   - done
  602 + case "$cur" in
  603 + refs|refs/*)
  604 + git ls-remote "$dir" "$cur*" 2>/dev/null | \
  605 + while read -r hash i; do
  606 + case "$i" in
  607 + *^{}) ;;
  608 + *) echo "$i" ;;
  609 + esac
  610 + done
  611 + ;;
  612 + *)
  613 + git ls-remote "$dir" HEAD ORIG_HEAD 'refs/tags/*' 'refs/heads/*' 'refs/remotes/*' 2>/dev/null | \
  614 + while read -r hash i; do
  615 + case "$i" in
  616 + *^{}) ;;
  617 + refs/*) echo "${i#refs/*/}" ;;
  618 + *) echo "$i" ;;
  619 + esac
  620 + done
  621 + ;;
  622 + esac
252 623 }
253 624
254 625 # __git_refs2 requires 1 argument (to pass to __git_refs)
@@ -263,46 +634,30 @@ __git_refs2 ()
263 634 # __git_refs_remotes requires 1 argument (to pass to ls-remote)
264 635 __git_refs_remotes ()
265 636 {
266   - local cmd i is_hash=y
267   - for i in $(git ls-remote "$1" 2>/dev/null); do
268   - case "$is_hash,$i" in
269   - n,refs/heads/*)
270   - is_hash=y
271   - echo "$i:refs/remotes/$1/${i#refs/heads/}"
272   - ;;
273   - y,*) is_hash=n ;;
274   - n,*^{}) is_hash=y ;;
275   - n,refs/tags/*) is_hash=y;;
276   - n,*) is_hash=y; ;;
277   - esac
  637 + local i hash
  638 + git ls-remote "$1" 'refs/heads/*' 2>/dev/null | \
  639 + while read -r hash i; do
  640 + echo "$i:refs/remotes/$1/${i#refs/heads/}"
278 641 done
279 642 }
280 643
281 644 __git_remotes ()
282 645 {
283 646 local i ngoff IFS=$'\n' d="$(__gitdir)"
284   - shopt -q nullglob || ngoff=1
285   - shopt -s nullglob
  647 + __git_shopt -q nullglob || ngoff=1
  648 + __git_shopt -s nullglob
286 649 for i in "$d/remotes"/*; do
287 650 echo ${i#$d/remotes/}
288 651 done
289   - [ "$ngoff" ] && shopt -u nullglob
290   - for i in $(git --git-dir="$d" config --list); do
291   - case "$i" in
292   - remote.*.url=*)
293   - i="${i#remote.}"
294   - echo "${i/.url=*/}"
295   - ;;
296   - esac
  652 + [ "$ngoff" ] && __git_shopt -u nullglob
  653 + for i in $(git --git-dir="$d" config --get-regexp 'remote\..*\.url' 2>/dev/null); do
  654 + i="${i#remote.}"
  655 + echo "${i/.url*/}"
297 656 done
298 657 }
299 658
300   -__git_merge_strategies ()
  659 +__git_list_merge_strategies ()
301 660 {
302   - if [ -n "$__git_merge_strategylist" ]; then
303   - echo "$__git_merge_strategylist"
304   - return
305   - fi
306 661 git merge -s help 2>&1 |
307 662 sed -n -e '/[Aa]vailable strategies are: /,/^$/{
308 663 s/\.$//
@@ -312,27 +667,39 @@ __git_merge_strategies ()
312 667 p
313 668 }'
314 669 }
315   -__git_merge_strategylist=
316   -__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)
317 670
318   -__git_complete_file ()
  671 +__git_merge_strategies=
  672 +# 'git merge -s help' (and thus detection of the merge strategy
  673 +# list) fails, unfortunately, if run outside of any git working
  674 +# tree. __git_merge_strategies is set to the empty string in
  675 +# that case, and the detection will be repeated the next time it
  676 +# is needed.
  677 +__git_compute_merge_strategies ()
319 678 {
320   - local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
321   - case "$cur" in
  679 + : ${__git_merge_strategies:=$(__git_list_merge_strategies)}
  680 +}
  681 +
  682 +__git_complete_revlist_file ()
  683 +{
  684 + local pfx ls ref cur_="$cur"
  685 + case "$cur_" in
  686 + *..?*:*)
  687 + return
  688 + ;;
322 689 ?*:*)
323   - ref="${cur%%:*}"
324   - cur="${cur#*:}"
325   - case "$cur" in
  690 + ref="${cur_%%:*}"
  691 + cur_="${cur_#*:}"
  692 + case "$cur_" in
326 693 ?*/*)
327   - pfx="${cur%/*}"
328   - cur="${cur##*/}"
  694 + pfx="${cur_%/*}"
  695 + cur_="${cur_##*/}"
329 696 ls="$ref:$pfx"
330 697 pfx="$pfx/"
331 698 ;;
332 699 *)
333 700 ls="$ref"
334 701 ;;
335   - esac
  702 + esac
336 703
337 704 case "$COMP_WORDBREAKS" in
338 705 *:*) : great ;;
@@ -355,42 +722,127 @@ __git_complete_file ()
355 722 s,$,/,
356 723 }
357 724 s/^.* //')" \
358   - -- "$cur"))
  725 + -- "$cur_"))
  726 + ;;
  727 + *...*)
  728 + pfx="${cur_%...*}..."
  729 + cur_="${cur_#*...}"
  730 + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
  731 + ;;
  732 + *..*)
  733 + pfx="${cur_%..*}.."
  734 + cur_="${cur_#*..}"
  735 + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
359 736 ;;
360 737 *)
361   - __gitcomp "$(__git_refs)"
  738 + __gitcomp_nl "$(__git_refs)"
362 739 ;;
363 740 esac
364 741 }
365 742
  743 +
  744 +__git_complete_file ()
  745 +{
  746 + __git_complete_revlist_file
  747 +}
  748 +
366 749 __git_complete_revlist ()
367 750 {
368   - local pfx cur="${COMP_WORDS[COMP_CWORD]}"
369   - case "$cur" in
370   - *...*)
371   - pfx="${cur%...*}..."
372   - cur="${cur#*...}"
373   - __gitcomp "$(__git_refs)" "$pfx" "$cur"
  751 + __git_complete_revlist_file
  752 +}
  753 +
  754 +__git_complete_remote_or_refspec ()
  755 +{
  756 + local cur_="$cur" cmd="${words[1]}"
  757 + local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
  758 + while [ $c -lt $cword ]; do
  759 + i="${words[c]}"
  760 + case "$i" in
  761 + --mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
  762 + --all)
  763 + case "$cmd" in
  764 + push) no_complete_refspec=1 ;;
  765 + fetch)
  766 + COMPREPLY=()
  767 + return
  768 + ;;
  769 + *) ;;
  770 + esac
  771 + ;;
  772 + -*) ;;
  773 + *) remote="$i"; break ;;
  774 + esac
  775 + c=$((++c))
  776 + done
  777 + if [ -z "$remote" ]; then
  778 + __gitcomp_nl "$(__git_remotes)"
  779 + return
  780 + fi
  781 + if [ $no_complete_refspec = 1 ]; then
  782 + COMPREPLY=()
  783 + return
  784 + fi
  785 + [ "$remote" = "." ] && remote=
  786 + case "$cur_" in
  787 + *:*)
  788 + case "$COMP_WORDBREAKS" in
  789 + *:*) : great ;;
  790 + *) pfx="${cur_%%:*}:" ;;
  791 + esac
  792 + cur_="${cur_#*:}"
  793 + lhs=0
374 794 ;;
375   - *..*)
376   - pfx="${cur%..*}.."
377   - cur="${cur#*..}"
378   - __gitcomp "$(__git_refs)" "$pfx" "$cur"
  795 + +*)
  796 + pfx="+"
  797 + cur_="${cur_#+}"
379 798 ;;
380   - *)
381   - __gitcomp "$(__git_refs)"
  799 + esac
  800 + case "$cmd" in
  801 + fetch)
  802 + if [ $lhs = 1 ]; then
  803 + __gitcomp_nl "$(__git_refs2 "$remote")" "$pfx" "$cur_"
  804 + else
  805 + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
  806 + fi
  807 + ;;
  808 + pull)
  809 + if [ $lhs = 1 ]; then
  810 + __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_"
  811 + else
  812 + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
  813 + fi
  814 + ;;
  815 + push)
  816 + if [ $lhs = 1 ]; then
  817 + __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_"
  818 + else
  819 + __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_"
  820 + fi
382 821 ;;
383 822 esac
384 823 }
385 824
386   -__git_all_commands ()
  825 +__git_complete_strategy ()
  826 +{
  827 + __git_compute_merge_strategies
  828 + case "$prev" in
  829 + -s|--strategy)
  830 + __gitcomp "$__git_merge_strategies"
  831 + return 0
  832 + esac
  833 + case "$cur" in
  834 + --strategy=*)
  835 + __gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
  836 + return 0
  837 + ;;
  838 + esac
  839 + return 1
  840 +}
  841 +
  842 +__git_list_all_commands ()
387 843 {
388   - if [ -n "$__git_all_commandlist" ]; then
389   - echo "$__git_all_commandlist"
390   - return
391   - fi
392 844 local i IFS=" "$'\n'
393   - for i in $(git help -a|egrep '^ ')
  845 + for i in $(git help -a|egrep '^ [a-zA-Z0-9]')
394 846 do
395 847 case $i in
396 848 *--*) : helper pattern;;
@@ -398,17 +850,18 @@ __git_all_commands ()
398 850 esac
399 851 done
400 852 }
401   -__git_all_commandlist=
402   -__git_all_commandlist="$(__git_all_commands 2>/dev/null)"
403 853
404   -__git_porcelain_commands ()
  854 +__git_all_commands=
  855 +__git_compute_all_commands ()
  856 +{
  857 + : ${__git_all_commands:=$(__git_list_all_commands)}
  858 +}
  859 +
  860 +__git_list_porcelain_commands ()
405 861 {
406   - if [ -n "$__git_porcelain_commandlist" ]; then
407   - echo "$__git_porcelain_commandlist"
408   - return
409   - fi
410 862 local i IFS=" "$'\n'
411   - for i in "help" $(__git_all_commands)
  863 + __git_compute_all_commands
  864 + for i in "help" $__git_all_commands
412 865 do
413 866 case $i in
414 867 *--*) : helper pattern;;
@@ -459,7 +912,7 @@ __git_porcelain_commands ()
459 912 quiltimport) : import;;
460 913 read-tree) : plumbing;;
461 914 receive-pack) : plumbing;;
462   - reflog) : plumbing;;
  915 + remote-*) : transport;;
463 916 repo-config) : deprecated;;
464 917 rerere) : plumbing;;
465 918 rev-list) : plumbing;;
@@ -489,17 +942,35 @@ __git_porcelain_commands ()
489 942 esac
490 943 done
491 944 }
492   -__git_porcelain_commandlist=
493   -__git_porcelain_commandlist="$(__git_porcelain_commands 2>/dev/null)"
  945 +
  946 +__git_porcelain_commands=
  947 +__git_compute_porcelain_commands ()
  948 +{
  949 + __git_compute_all_commands
  950 + : ${__git_porcelain_commands:=$(__git_list_porcelain_commands)}
  951 +}
  952 +
  953 +__git_pretty_aliases ()
  954 +{
  955 + local i IFS=$'\n'
  956 + for i in $(git --git-dir="$(__gitdir)" config --get-regexp "pretty\..*" 2>/dev/null); do
  957 + case "$i" in
  958 + pretty.*)
  959 + i="${i#pretty.}"
  960 + echo "${i/ */}"
  961 + ;;
  962 + esac
  963 + done
  964 +}
494 965
495 966 __git_aliases ()
496 967 {
497 968 local i IFS=$'\n'
498   - for i in $(git --git-dir="$(__gitdir)" config --list); do
  969 + for i in $(git --git-dir="$(__gitdir)" config --get-regexp "alias\..*" 2>/dev/null); do
499 970 case "$i" in
500 971 alias.*)
501 972 i="${i#alias.}"
502   - echo "${i/=*/}"
  973 + echo "${i/ */}"
503 974 ;;
504 975 esac
505 976 done
@@ -511,20 +982,28 @@ __git_aliased_command ()
511 982 local word cmdline=$(git --git-dir="$(__gitdir)" \
512 983 config --get "alias.$1")
513 984 for word in $cmdline; do
514   - if [ "${word##-*}" ]; then
515   - echo $word
  985 + case "$word" in
  986 + \!gitk|gitk)
  987 + echo "gitk"
516 988 return
517   - fi
  989 + ;;
  990 + \!*) : shell command alias ;;
  991 + -*) : option ;;
  992 + *=*) : setting env ;;
  993 + git) : git itself ;;
  994 + *)
  995 + echo "$word"
  996 + return
  997 + esac
518 998 done
519 999 }
520 1000
521   -# __git_find_subcommand requires 1 argument
522   -__git_find_subcommand ()
  1001 +# __git_find_on_cmdline requires 1 argument
  1002 +__git_find_on_cmdline ()
523 1003 {
524 1004 local word subcommand c=1
525   -
526   - while [ $c -lt $COMP_CWORD ]; do
527   - word="${COMP_WORDS[c]}"
  1005 + while [ $c -lt $cword ]; do
  1006 + word="${words[c]}"
528 1007 for subcommand in $1; do
529 1008 if [ "$subcommand" = "$word" ]; then
530 1009 echo "$subcommand"
@@ -538,8 +1017,8 @@ __git_find_subcommand ()
538 1017 __git_has_doubledash ()
539 1018 {
540 1019 local c=1
541   - while [ $c -lt $COMP_CWORD ]; do
542   - if [ "--" = "${COMP_WORDS[c]}" ]; then
  1020 + while [ $c -lt $cword ]; do
  1021 + if [ "--" = "${words[c]}" ]; then
543 1022 return 0
544 1023 fi
545 1024 c=$((++c))
@@ -551,9 +1030,9 @@ __git_whitespacelist="nowarn warn error error-all fix"
551 1030
552 1031 _git_am ()
553 1032 {
554   - local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
  1033 + local dir="$(__gitdir)"
555 1034 if [ -d "$dir"/rebase-apply ]; then
556   - __gitcomp "--skip --resolved --abort"
  1035 + __gitcomp "--skip --continue --resolved --abort"
557 1036 return
558 1037 fi
559 1038 case "$cur" in
@@ -563,8 +1042,10 @@ _git_am ()
563 1042 ;;
564 1043 --*)
565 1044 __gitcomp "
566   - --signoff --utf8 --binary --3way --interactive
567   - --whitespace=
  1045 + --3way --committer-date-is-author-date --ignore-date
  1046 + --ignore-whitespace --ignore-space-change
  1047 + --interactive --keep --no-utf8 --signoff --utf8
  1048 + --whitespace= --scissors
568 1049 "
569 1050 return
570 1051 esac
@@ -573,7 +1054,6 @@ _git_am ()
573 1054
574 1055 _git_apply ()
575 1056 {
576   - local cur="${COMP_WORDS[COMP_CWORD]}"
577 1057 case "$cur" in
578 1058 --whitespace=*)
579 1059 __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
@@ -584,6 +1064,7 @@ _git_apply ()
584 1064 --stat --numstat --summary --check --index
585 1065 --cached --index-info --reverse --reject --unidiff-zero
586 1066 --apply --no-add --exclude=
  1067 + --ignore-whitespace --ignore-space-change
587 1068 --whitespace= --inaccurate-eof --verbose
588 1069 "
589 1070 return
@@ -595,7 +1076,6 @@ _git_add ()
595 1076 {
596 1077 __git_has_doubledash && return
597 1078
598   - local cur="${COMP_WORDS[COMP_CWORD]}"
599 1079 case "$cur" in
600 1080 --*)
601 1081 __gitcomp "
@@ -609,14 +1089,13 @@ _git_add ()
609 1089
610 1090 _git_archive ()
611 1091 {
612   - local cur="${COMP_WORDS[COMP_CWORD]}"
613 1092 case "$cur" in
614 1093 --format=*)
615 1094 __gitcomp "$(git archive --list)" "" "${cur##--format=}"
616 1095 return
617 1096 ;;
618 1097 --remote=*)
619   - __gitcomp "$(__git_remotes)" "" "${cur##--remote=}"
  1098 + __gitcomp_nl "$(__git_remotes)" "" "${cur##--remote=}"
620 1099 return
621 1100 ;;