Add current branch in PS1 support to git-completion.bash.
[git] / contrib / completion / git-completion.bash
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
475 complete -o default -o nospace -F _git git
476 complete -o default            -F _gitk gitk
477 complete -o default            -F _git_branch git-branch
478 complete -o default -o nospace -F _git_cat_file git-cat-file
479 complete -o default            -F _git_checkout git-checkout
480 complete -o default -o nospace -F _git_diff git-diff
481 complete -o default            -F _git_diff_tree git-diff-tree
482 complete -o default -o nospace -F _git_fetch git-fetch
483 complete -o default -o nospace -F _git_log git-log
484 complete -o default            -F _git_ls_remote git-ls-remote
485 complete -o default -o nospace -F _git_ls_tree git-ls-tree
486 complete -o default            -F _git_merge git-merge
487 complete -o default            -F _git_merge_base git-merge-base
488 complete -o default            -F _git_name_rev git-name-rev
489 complete -o default -o nospace -F _git_pull git-pull
490 complete -o default -o nospace -F _git_push git-push
491 complete -o default            -F _git_reset git-reset
492 complete -o default            -F _git_show git-show
493 complete -o default -o nospace -F _git_log git-show-branch
494 complete -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 #
500 if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
501 complete -o default -o nospace -F _git git.exe
502 complete -o default            -F _git_branch git-branch.exe
503 complete -o default -o nospace -F _git_cat_file git-cat-file.exe
504 complete -o default -o nospace -F _git_diff git-diff.exe
505 complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
506 complete -o default -o nospace -F _git_log git-log.exe
507 complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
508 complete -o default            -F _git_merge_base git-merge-base.exe
509 complete -o default            -F _git_name_rev git-name-rev.exe
510 complete -o default -o nospace -F _git_push git-push.exe
511 complete -o default -o nospace -F _git_log git-show-branch.exe
512 complete -o default -o nospace -F _git_log git-whatchanged.exe
513 fi