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