Code

Support bash completion of refs/remote.
[git.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 #
29 __gitdir ()
30 {
31         echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}"
32 }
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 }
46 __git_refs ()
47 {
48         local cmd i is_hash=y dir="${1:-$(__gitdir)}"
49         if [ -d "$dir" ]; then
50                 if [ -e "$dir/HEAD" ]; then echo HEAD; fi
51                 for i in $(git --git-dir="$dir" \
52                         for-each-ref --format='%(refname)' \
53                         refs/tags refs/heads refs/remotes); do
54                         case "$i" in
55                                 refs/tags/*)    echo "${i#refs/tags/}" ;;
56                                 refs/heads/*)   echo "${i#refs/heads/}" ;;
57                                 refs/remotes/*) echo "${i#refs/remotes/}" ;;
58                                 *)              echo "$i" ;;
59                         esac
60                 done
61                 return
62         fi
63         for i in $(git-ls-remote "$dir" 2>/dev/null); do
64                 case "$is_hash,$i" in
65                 y,*) is_hash=n ;;
66                 n,*^{}) is_hash=y ;;
67                 n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
68                 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
69                 n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;;
70                 n,*) is_hash=y; echo "$i" ;;
71                 esac
72         done
73 }
75 __git_refs2 ()
76 {
77         local cmd i is_hash=y dir="${1:-$(__gitdir)}"
78         if [ -d "$dir" ]; then
79                 cmd=git-peek-remote
80         else
81                 cmd=git-ls-remote
82         fi
83         for i in $($cmd "$dir" 2>/dev/null); do
84                 case "$is_hash,$i" in
85                 y,*) is_hash=n ;;
86                 n,*^{}) is_hash=y ;;
87                 n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;;
88                 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;;
89                 n,*) is_hash=y; echo "$i:$i" ;;
90                 esac
91         done
92 }
94 __git_remotes ()
95 {
96         local i ngoff IFS=$'\n' d="$(__gitdir)"
97         shopt -q nullglob || ngoff=1
98         shopt -s nullglob
99         for i in "$d/remotes"/*; do
100                 echo ${i#$d/remotes/}
101         done
102         [ "$ngoff" ] && shopt -u nullglob
103         for i in $(git --git-dir="$d" repo-config --list); do
104                 case "$i" in
105                 remote.*.url=*)
106                         i="${i#remote.}"
107                         echo "${i/.url=*/}"
108                         ;;
109                 esac
110         done
113 __git_merge_strategies ()
115         sed -n "/^all_strategies='/{
116                 s/^all_strategies='//
117                 s/'//
118                 p
119                 q
120                 }" "$(git --exec-path)/git-merge"
123 __git_complete_file ()
125         local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
126         case "$cur" in
127         ?*:*)
128                 ref="${cur%%:*}"
129                 cur="${cur#*:}"
130                 case "$cur" in
131                 ?*/*)
132                         pfx="${cur%/*}"
133                         cur="${cur##*/}"
134                         ls="$ref:$pfx"
135                         pfx="$pfx/"
136                         ;;
137                 *)
138                         ls="$ref"
139                         ;;
140             esac
141                 COMPREPLY=($(compgen -P "$pfx" \
142                         -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
143                                 | sed '/^100... blob /s,^.*     ,,
144                                        /^040000 tree /{
145                                            s,^.*        ,,
146                                            s,$,/,
147                                        }
148                                        s/^.*    //')" \
149                         -- "$cur"))
150                 ;;
151         *)
152                 COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
153                 ;;
154         esac
157 __git_complete_revlist ()
159         local pfx cur="${COMP_WORDS[COMP_CWORD]}"
160         case "$cur" in
161         *...*)
162                 pfx="${cur%...*}..."
163                 cur="${cur#*...}"
164                 COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
165                 ;;
166         *..*)
167                 pfx="${cur%..*}.."
168                 cur="${cur#*..}"
169                 COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
170                 ;;
171         *)
172                 COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
173                 ;;
174         esac
177 __git_commands ()
179         local i IFS=" "$'\n'
180         for i in $(git help -a|egrep '^ ')
181         do
182                 case $i in
183                 check-ref-format) : plumbing;;
184                 commit-tree)      : plumbing;;
185                 convert-objects)  : plumbing;;
186                 cvsserver)        : daemon;;
187                 daemon)           : daemon;;
188                 fetch-pack)       : plumbing;;
189                 hash-object)      : plumbing;;
190                 http-*)           : transport;;
191                 index-pack)       : plumbing;;
192                 local-fetch)      : plumbing;;
193                 mailinfo)         : plumbing;;
194                 mailsplit)        : plumbing;;
195                 merge-*)          : plumbing;;
196                 mktree)           : plumbing;;
197                 mktag)            : plumbing;;
198                 pack-objects)     : plumbing;;
199                 pack-redundant)   : plumbing;;
200                 pack-refs)        : plumbing;;
201                 parse-remote)     : plumbing;;
202                 patch-id)         : plumbing;;
203                 peek-remote)      : plumbing;;
204                 read-tree)        : plumbing;;
205                 receive-pack)     : plumbing;;
206                 rerere)           : plumbing;;
207                 rev-list)         : plumbing;;
208                 rev-parse)        : plumbing;;
209                 runstatus)        : plumbing;;
210                 sh-setup)         : internal;;
211                 shell)            : daemon;;
212                 send-pack)        : plumbing;;
213                 show-index)       : plumbing;;
214                 ssh-*)            : transport;;
215                 stripspace)       : plumbing;;
216                 symbolic-ref)     : plumbing;;
217                 unpack-file)      : plumbing;;
218                 unpack-objects)   : plumbing;;
219                 update-ref)       : plumbing;;
220                 update-server-info) : daemon;;
221                 upload-archive)   : plumbing;;
222                 upload-pack)      : plumbing;;
223                 write-tree)       : plumbing;;
224                 *) echo $i;;
225                 esac
226         done
229 __git_aliases ()
231         local i IFS=$'\n'
232         for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
233                 case "$i" in
234                 alias.*)
235                         i="${i#alias.}"
236                         echo "${i/=*/}"
237                         ;;
238                 esac
239         done
242 __git_aliased_command ()
244         local word cmdline=$(git --git-dir="$(__gitdir)" \
245                 repo-config --get "alias.$1")
246         for word in $cmdline; do
247                 if [ "${word##-*}" ]; then
248                         echo $word
249                         return
250                 fi
251         done
254 _git_branch ()
256         local cur="${COMP_WORDS[COMP_CWORD]}"
257         COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
260 _git_cat_file ()
262         local cur="${COMP_WORDS[COMP_CWORD]}"
263         case "${COMP_WORDS[0]},$COMP_CWORD" in
264         git-cat-file*,1)
265                 COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
266                 ;;
267         git,2)
268                 COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
269                 ;;
270         *)
271                 __git_complete_file
272                 ;;
273         esac
276 _git_checkout ()
278         local cur="${COMP_WORDS[COMP_CWORD]}"
279         COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
282 _git_cherry_pick ()
284         local cur="${COMP_WORDS[COMP_CWORD]}"
285         case "$cur" in
286         --*)
287                 COMPREPLY=($(compgen -W "
288                         --edit --no-commit
289                         " -- "$cur"))
290                 ;;
291         *)
292                 COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
293                 ;;
294         esac
297 _git_diff ()
299         __git_complete_file
302 _git_diff_tree ()
304         local cur="${COMP_WORDS[COMP_CWORD]}"
305         COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
308 _git_fetch ()
310         local cur="${COMP_WORDS[COMP_CWORD]}"
312         case "${COMP_WORDS[0]},$COMP_CWORD" in
313         git-fetch*,1)
314                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
315                 ;;
316         git,2)
317                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
318                 ;;
319         *)
320                 case "$cur" in
321                 *:*)
322                         cur="${cur#*:}"
323                         COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
324                         ;;
325                 *)
326                         local remote
327                         case "${COMP_WORDS[0]}" in
328                         git-fetch) remote="${COMP_WORDS[1]}" ;;
329                         git)       remote="${COMP_WORDS[2]}" ;;
330                         esac
331                         COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
332                         ;;
333                 esac
334                 ;;
335         esac
338 _git_format_patch ()
340         local cur="${COMP_WORDS[COMP_CWORD]}"
341         case "$cur" in
342         --*)
343                 COMPREPLY=($(compgen -W "
344                         --stdout --attach --thread
345                         --output-directory
346                         --numbered --start-number
347                         --keep-subject
348                         --signoff
349                         --in-reply-to=
350                         --full-index --binary
351                         " -- "$cur"))
352                 return
353                 ;;
354         esac
355         __git_complete_revlist
358 _git_ls_remote ()
360         local cur="${COMP_WORDS[COMP_CWORD]}"
361         COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
364 _git_ls_tree ()
366         __git_complete_file
369 _git_log ()
371         local cur="${COMP_WORDS[COMP_CWORD]}"
372         case "$cur" in
373         --pretty=*)
374                 COMPREPLY=($(compgen -W "
375                         oneline short medium full fuller email raw
376                         " -- "${cur##--pretty=}"))
377                 return
378                 ;;
379         --*)
380                 COMPREPLY=($(compgen -W "
381                         --max-count= --max-age= --since= --after=
382                         --min-age= --before= --until=
383                         --root --not --topo-order --date-order
384                         --no-merges
385                         --abbrev-commit --abbrev=
386                         --relative-date
387                         --author= --committer= --grep=
388                         --all-match
389                         --pretty= --name-status --name-only
390                         " -- "$cur"))
391                 return
392                 ;;
393         esac
394         __git_complete_revlist
397 _git_merge ()
399         local cur="${COMP_WORDS[COMP_CWORD]}"
400         case "$cur" in
401         --*)
402                 COMPREPLY=($(compgen -W "
403                         --no-commit --no-summary --squash --strategy
404                         " -- "$cur"))
405                 return
406         esac
407         case "${COMP_WORDS[COMP_CWORD-1]}" in
408         -s|--strategy)
409                 COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
410                 return
411         esac
412         COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
415 _git_merge_base ()
417         local cur="${COMP_WORDS[COMP_CWORD]}"
418         COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
421 _git_name_rev ()
423         local cur="${COMP_WORDS[COMP_CWORD]}"
424         COMPREPLY=($(compgen -W "--tags --all --stdin" -- "$cur"))
427 _git_pull ()
429         local cur="${COMP_WORDS[COMP_CWORD]}"
431         case "${COMP_WORDS[0]},$COMP_CWORD" in
432         git-pull*,1)
433                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
434                 ;;
435         git,2)
436                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
437                 ;;
438         *)
439                 local remote
440                 case "${COMP_WORDS[0]}" in
441                 git-pull)  remote="${COMP_WORDS[1]}" ;;
442                 git)       remote="${COMP_WORDS[2]}" ;;
443                 esac
444                 COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
445                 ;;
446         esac
449 _git_push ()
451         local cur="${COMP_WORDS[COMP_CWORD]}"
453         case "${COMP_WORDS[0]},$COMP_CWORD" in
454         git-push*,1)
455                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
456                 ;;
457         git,2)
458                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
459                 ;;
460         *)
461                 case "$cur" in
462                 *:*)
463                         local remote
464                         case "${COMP_WORDS[0]}" in
465                         git-push)  remote="${COMP_WORDS[1]}" ;;
466                         git)       remote="${COMP_WORDS[2]}" ;;
467                         esac
468                         cur="${cur#*:}"
469                         COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
470                         ;;
471                 *)
472                         COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
473                         ;;
474                 esac
475                 ;;
476         esac
479 _git_rebase ()
481         local cur="${COMP_WORDS[COMP_CWORD]}"
482         if [ -d .dotest ]; then
483                 COMPREPLY=($(compgen -W "
484                         --continue --skip --abort
485                         " -- "$cur"))
486                 return
487         fi
488         case "$cur" in
489         --*)
490                 COMPREPLY=($(compgen -W "
491                         --onto --merge --strategy
492                         " -- "$cur"))
493                 return
494         esac
495         case "${COMP_WORDS[COMP_CWORD-1]}" in
496         -s|--strategy)
497                 COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur"))
498                 return
499         esac
500         COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
503 _git_reset ()
505         local cur="${COMP_WORDS[COMP_CWORD]}"
506         local opt="--mixed --hard --soft"
507         COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
510 _git ()
512         local i c=1 command __git_dir
514         while [ $c -lt $COMP_CWORD ]; do
515                 i="${COMP_WORDS[c]}"
516                 case "$i" in
517                 --git-dir=*) __git_dir="${i#--git-dir=}" ;;
518                 --bare)      __git_dir="." ;;
519                 --version|--help|-p|--paginate) ;;
520                 *) command="$i"; break ;;
521                 esac
522                 c=$((++c))
523         done
525         if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
526                 COMPREPLY=($(compgen -W "
527                         --git-dir= --version --exec-path
528                         $(__git_commands)
529                         $(__git_aliases)
530                         " -- "${COMP_WORDS[COMP_CWORD]}"))
531                 return;
532         fi
534         local expansion=$(__git_aliased_command "$command")
535         [ "$expansion" ] && command="$expansion"
537         case "$command" in
538         branch)      _git_branch ;;
539         cat-file)    _git_cat_file ;;
540         checkout)    _git_checkout ;;
541         cherry-pick) _git_cherry_pick ;;
542         diff)        _git_diff ;;
543         diff-tree)   _git_diff_tree ;;
544         fetch)       _git_fetch ;;
545         format-patch) _git_format_patch ;;
546         log)         _git_log ;;
547         ls-remote)   _git_ls_remote ;;
548         ls-tree)     _git_ls_tree ;;
549         merge)       _git_merge;;
550         merge-base)  _git_merge_base ;;
551         name-rev)    _git_name_rev ;;
552         pull)        _git_pull ;;
553         push)        _git_push ;;
554         rebase)      _git_rebase ;;
555         reset)       _git_reset ;;
556         show)        _git_log ;;
557         show-branch) _git_log ;;
558         whatchanged) _git_log ;;
559         *)           COMPREPLY=() ;;
560         esac
563 _gitk ()
565         local cur="${COMP_WORDS[COMP_CWORD]}"
566         COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
569 complete -o default -o nospace -F _git git
570 complete -o default            -F _gitk gitk
571 complete -o default            -F _git_branch git-branch
572 complete -o default -o nospace -F _git_cat_file git-cat-file
573 complete -o default            -F _git_checkout git-checkout
574 complete -o default            -F _git_cherry_pick git-cherry-pick
575 complete -o default -o nospace -F _git_diff git-diff
576 complete -o default            -F _git_diff_tree git-diff-tree
577 complete -o default -o nospace -F _git_fetch git-fetch
578 complete -o default -o nospace -F _git_format_patch git-format-patch
579 complete -o default -o nospace -F _git_log git-log
580 complete -o default            -F _git_ls_remote git-ls-remote
581 complete -o default -o nospace -F _git_ls_tree git-ls-tree
582 complete -o default            -F _git_merge git-merge
583 complete -o default            -F _git_merge_base git-merge-base
584 complete -o default            -F _git_name_rev git-name-rev
585 complete -o default -o nospace -F _git_pull git-pull
586 complete -o default -o nospace -F _git_push git-push
587 complete -o default            -F _git_rebase git-rebase
588 complete -o default            -F _git_reset git-reset
589 complete -o default            -F _git_log git-show
590 complete -o default -o nospace -F _git_log git-show-branch
591 complete -o default -o nospace -F _git_log git-whatchanged
593 # The following are necessary only for Cygwin, and only are needed
594 # when the user has tab-completed the executable name and consequently
595 # included the '.exe' suffix.
597 if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
598 complete -o default -o nospace -F _git git.exe
599 complete -o default            -F _git_branch git-branch.exe
600 complete -o default -o nospace -F _git_cat_file git-cat-file.exe
601 complete -o default -o nospace -F _git_diff git-diff.exe
602 complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
603 complete -o default -o nospace -F _git_format_patch git-format-patch.exe
604 complete -o default -o nospace -F _git_log git-log.exe
605 complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
606 complete -o default            -F _git_merge_base git-merge-base.exe
607 complete -o default            -F _git_name_rev git-name-rev.exe
608 complete -o default -o nospace -F _git_push git-push.exe
609 complete -o default -o nospace -F _git_log git-show.exe
610 complete -o default -o nospace -F _git_log git-show-branch.exe
611 complete -o default -o nospace -F _git_log git-whatchanged.exe
612 fi