Bash completion support for remotes in .git/config.
[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
22 __git_refs ()
23 {
24         local cmd i is_hash=y
25         if [ -d "$1" ]; then
26                 cmd=git-peek-remote
27         else
28                 cmd=git-ls-remote
29         fi
30         for i in $($cmd "$1" 2>/dev/null); do
31                 case "$is_hash,$i" in
32                 y,*) is_hash=n ;;
33                 n,*^{}) is_hash=y ;;
34                 n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;;
35                 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;;
36                 n,*) is_hash=y; echo "$i" ;;
37                 esac
38         done
39 }
40
41 __git_refs2 ()
42 {
43         local cmd i is_hash=y
44         if [ -d "$1" ]; then
45                 cmd=git-peek-remote
46         else
47                 cmd=git-ls-remote
48         fi
49         for i in $($cmd "$1" 2>/dev/null); do
50                 case "$is_hash,$i" in
51                 y,*) is_hash=n ;;
52                 n,*^{}) is_hash=y ;;
53                 n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}:${i#refs/tags/}" ;;
54                 n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}:${i#refs/heads/}" ;;
55                 n,*) is_hash=y; echo "$i:$i" ;;
56                 esac
57         done
58 }
59
60 __git_remotes ()
61 {
62         local i ngoff IFS=$'\n'
63         shopt -q nullglob || ngoff=1
64         shopt -s nullglob
65         for i in .git/remotes/*; do
66                 echo ${i#.git/remotes/}
67         done
68         [ "$ngoff" ] && shopt -u nullglob
69         for i in $(git repo-config --list); do
70                 case "$i" in
71                 remote.*.url=*)
72                         i="${i#remote.}"
73                         echo "${i/.url=*/}"
74                         ;;
75                 esac
76         done
77 }
78
79 __git_complete_file ()
80 {
81         local cur="${COMP_WORDS[COMP_CWORD]}"
82         case "$cur" in
83         ?*:*)
84                 local pfx ls ref="$(echo "$cur" | sed 's,:.*$,,')"
85                 cur="$(echo "$cur" | sed 's,^.*:,,')"
86                 case "$cur" in
87                 ?*/*)
88                         pfx="$(echo "$cur" | sed 's,/[^/]*$,,')"
89                         cur="$(echo "$cur" | sed 's,^.*/,,')"
90                         ls="$ref:$pfx"
91                         pfx="$pfx/"
92                         ;;
93                 *)
94                         ls="$ref"
95                         ;;
96             esac
97                 COMPREPLY=($(compgen -P "$pfx" \
98                         -W "$(git-ls-tree "$ls" \
99                                 | sed '/^100... blob /s,^.*     ,,
100                                        /^040000 tree /{
101                                            s,^.*        ,,
102                                            s,$,/,
103                                        }
104                                        s/^.*    //')" \
105                         -- "$cur"))
106                 ;;
107         *)
108                 COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
109                 ;;
110         esac
111 }
112
113 __git_aliases ()
114 {
115         local i IFS=$'\n'
116         for i in $(git repo-config --list); do
117                 case "$i" in
118                 alias.*)
119                         i="${i#alias.}"
120                         echo "${i/=*/}"
121                         ;;
122                 esac
123         done
124 }
125
126 __git_aliased_command ()
127 {
128         local word cmdline=$(git repo-config --get "alias.$1")
129         for word in $cmdline; do
130                 if [ "${word##-*}" ]; then
131                         echo $word
132                         return
133                 fi
134         done
135 }
136
137 _git_branch ()
138 {
139         local cur="${COMP_WORDS[COMP_CWORD]}"
140         COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs .)" -- "$cur"))
141 }
142
143 _git_cat_file ()
144 {
145         local cur="${COMP_WORDS[COMP_CWORD]}"
146         case "${COMP_WORDS[0]},$COMP_CWORD" in
147         git-cat-file*,1)
148                 COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
149                 ;;
150         git,2)
151                 COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
152                 ;;
153         *)
154                 __git_complete_file
155                 ;;
156         esac
157 }
158
159 _git_checkout ()
160 {
161         local cur="${COMP_WORDS[COMP_CWORD]}"
162         COMPREPLY=($(compgen -W "-l -b $(__git_refs .)" -- "$cur"))
163 }
164
165 _git_diff ()
166 {
167         __git_complete_file
168 }
169
170 _git_diff_tree ()
171 {
172         local cur="${COMP_WORDS[COMP_CWORD]}"
173         COMPREPLY=($(compgen -W "-r -p -M $(__git_refs .)" -- "$cur"))
174 }
175
176 _git_fetch ()
177 {
178         local cur="${COMP_WORDS[COMP_CWORD]}"
179
180         case "${COMP_WORDS[0]},$COMP_CWORD" in
181         git-fetch*,1)
182                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
183                 ;;
184         git,2)
185                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
186                 ;;
187         *)
188                 case "$cur" in
189                 *:*)
190                 cur=$(echo "$cur" | sed 's/^.*://')
191                         COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
192                         ;;
193                 *)
194                         local remote
195                         case "${COMP_WORDS[0]}" in
196                         git-fetch) remote="${COMP_WORDS[1]}" ;;
197                         git)       remote="${COMP_WORDS[2]}" ;;
198                         esac
199                         COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
200                         ;;
201                 esac
202                 ;;
203         esac
204 }
205
206 _git_ls_remote ()
207 {
208         local cur="${COMP_WORDS[COMP_CWORD]}"
209         COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
210 }
211
212 _git_ls_tree ()
213 {
214         __git_complete_file
215 }
216
217 _git_log ()
218 {
219         local cur="${COMP_WORDS[COMP_CWORD]}"
220         case "$cur" in
221         *..*)
222                 local pfx=$(echo "$cur" | sed 's/\.\..*$/../')
223                 cur=$(echo "$cur" | sed 's/^.*\.\.//')
224                 COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs .)" -- "$cur"))
225                 ;;
226         *)
227                 COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
228                 ;;
229         esac
230 }
231
232 _git_merge_base ()
233 {
234         local cur="${COMP_WORDS[COMP_CWORD]}"
235         COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
236 }
237
238 _git_pull ()
239 {
240         local cur="${COMP_WORDS[COMP_CWORD]}"
241
242         case "${COMP_WORDS[0]},$COMP_CWORD" in
243         git-pull*,1)
244                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
245                 ;;
246         git,2)
247                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
248                 ;;
249         *)
250                 local remote
251                 case "${COMP_WORDS[0]}" in
252                 git-pull)  remote="${COMP_WORDS[1]}" ;;
253                 git)       remote="${COMP_WORDS[2]}" ;;
254                 esac
255                 COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
256                 ;;
257         esac
258 }
259
260 _git_push ()
261 {
262         local cur="${COMP_WORDS[COMP_CWORD]}"
263
264         case "${COMP_WORDS[0]},$COMP_CWORD" in
265         git-push*,1)
266                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
267                 ;;
268         git,2)
269                 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
270                 ;;
271         *)
272                 case "$cur" in
273                 *:*)
274                         local remote
275                         case "${COMP_WORDS[0]}" in
276                         git-push)  remote="${COMP_WORDS[1]}" ;;
277                         git)       remote="${COMP_WORDS[2]}" ;;
278                         esac
279                 cur=$(echo "$cur" | sed 's/^.*://')
280                         COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
281                         ;;
282                 *)
283                         COMPREPLY=($(compgen -W "$(__git_refs2 .)" -- "$cur"))
284                         ;;
285                 esac
286                 ;;
287         esac
288 }
289
290 _git_reset ()
291 {
292         local cur="${COMP_WORDS[COMP_CWORD]}"
293         local opt="--mixed --hard --soft"
294         COMPREPLY=($(compgen -W "$opt $(__git_refs .)" -- "$cur"))
295 }
296
297 _git_show ()
298 {
299         local cur="${COMP_WORDS[COMP_CWORD]}"
300         COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
301 }
302
303 _git ()
304 {
305         if [ $COMP_CWORD = 1 ]; then
306                 COMPREPLY=($(compgen \
307                         -W "--version $(git help -a|egrep '^ ') \
308                             $(__git_aliases)" \
309                         -- "${COMP_WORDS[COMP_CWORD]}"))
310         else
311                 local command="${COMP_WORDS[1]}"
312                 local expansion=$(__git_aliased_command "$command")
313
314                 if [ "$expansion" ]; then
315                         command="$expansion"
316                 fi
317
318                 case "$command" in
319                 branch)      _git_branch ;;
320                 cat-file)    _git_cat_file ;;
321                 checkout)    _git_checkout ;;
322                 diff)        _git_diff ;;
323                 diff-tree)   _git_diff_tree ;;
324                 fetch)       _git_fetch ;;
325                 log)         _git_log ;;
326                 ls-remote)   _git_ls_remote ;;
327                 ls-tree)     _git_ls_tree ;;
328                 merge-base)  _git_merge_base ;;
329                 pull)        _git_pull ;;
330                 push)        _git_push ;;
331                 reset)       _git_reset ;;
332                 show)        _git_show ;;
333                 show-branch) _git_log ;;
334                 whatchanged) _git_log ;;
335                 *)           COMPREPLY=() ;;
336                 esac
337         fi
338 }
339
340 _gitk ()
341 {
342         local cur="${COMP_WORDS[COMP_CWORD]}"
343         COMPREPLY=($(compgen -W "--all $(__git_refs .)" -- "$cur"))
344 }
345
346 complete -o default -o nospace -F _git git
347 complete -o default            -F _gitk gitk
348 complete -o default            -F _git_branch git-branch
349 complete -o default -o nospace -F _git_cat_file git-cat-file
350 complete -o default            -F _git_checkout git-checkout
351 complete -o default -o nospace -F _git_diff git-diff
352 complete -o default            -F _git_diff_tree git-diff-tree
353 complete -o default -o nospace -F _git_fetch git-fetch
354 complete -o default -o nospace -F _git_log git-log
355 complete -o default            -F _git_ls_remote git-ls-remote
356 complete -o default -o nospace -F _git_ls_tree git-ls-tree
357 complete -o default            -F _git_merge_base git-merge-base
358 complete -o default -o nospace -F _git_pull git-pull
359 complete -o default -o nospace -F _git_push git-push
360 complete -o default            -F _git_reset git-reset
361 complete -o default            -F _git_show git-show
362 complete -o default -o nospace -F _git_log git-show-branch
363 complete -o default -o nospace -F _git_log git-whatchanged
364
365 # The following are necessary only for Cygwin, and only are needed
366 # when the user has tab-completed the executable name and consequently
367 # included the '.exe' suffix.
368 #
369 if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
370 complete -o default -o nospace -F _git git.exe
371 complete -o default            -F _git_branch git-branch.exe
372 complete -o default -o nospace -F _git_cat_file git-cat-file.exe
373 complete -o default -o nospace -F _git_diff git-diff.exe
374 complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
375 complete -o default -o nospace -F _git_log git-log.exe
376 complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
377 complete -o default            -F _git_merge_base git-merge-base.exe
378 complete -o default -o nospace -F _git_push git-push.exe
379 complete -o default -o nospace -F _git_log git-show-branch.exe
380 complete -o default -o nospace -F _git_log git-whatchanged.exe
381 fi