]>
Commit | Line | Data |
---|---|---|
690d8824 JH |
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 | # | |
d3d717a4 SP |
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 | # | |
690d8824 | 28 | |
873537fa SP |
29 | __gitdir () |
30 | { | |
31 | echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}" | |
32 | } | |
33 | ||
d3d717a4 SP |
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 | ||
690d8824 JH |
46 | __git_refs () |
47 | { | |
873537fa SP |
48 | local cmd i is_hash=y dir="${1:-$(__gitdir)}" |
49 | if [ -d "$dir" ]; then | |
690d8824 JH |
50 | cmd=git-peek-remote |
51 | else | |
52 | cmd=git-ls-remote | |
53 | fi | |
873537fa | 54 | for i in $($cmd "$dir" 2>/dev/null); do |
690d8824 JH |
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 | { | |
873537fa SP |
67 | local cmd i is_hash=y dir="${1:-$(__gitdir)}" |
68 | if [ -d "$dir" ]; then | |
690d8824 JH |
69 | cmd=git-peek-remote |
70 | else | |
71 | cmd=git-ls-remote | |
72 | fi | |
873537fa | 73 | for i in $($cmd "$dir" 2>/dev/null); do |
690d8824 JH |
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 | { | |
873537fa | 86 | local i ngoff IFS=$'\n' d="$(__gitdir)" |
56fc25f2 | 87 | shopt -q nullglob || ngoff=1 |
690d8824 | 88 | shopt -s nullglob |
873537fa SP |
89 | for i in "$d/remotes"/*; do |
90 | echo ${i#$d/remotes/} | |
690d8824 | 91 | done |
56fc25f2 | 92 | [ "$ngoff" ] && shopt -u nullglob |
873537fa | 93 | for i in $(git --git-dir="$d" repo-config --list); do |
56fc25f2 SP |
94 | case "$i" in |
95 | remote.*.url=*) | |
96 | i="${i#remote.}" | |
97 | echo "${i/.url=*/}" | |
98 | ;; | |
99 | esac | |
100 | done | |
690d8824 JH |
101 | } |
102 | ||
4ad91321 SP |
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 | ||
690d8824 JH |
113 | __git_complete_file () |
114 | { | |
a79c6551 | 115 | local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}" |
690d8824 JH |
116 | case "$cur" in |
117 | ?*:*) | |
a79c6551 SP |
118 | ref="${cur%%:*}" |
119 | cur="${cur#*:}" | |
690d8824 JH |
120 | case "$cur" in |
121 | ?*/*) | |
a79c6551 SP |
122 | pfx="${cur%/*}" |
123 | cur="${cur##*/}" | |
690d8824 JH |
124 | ls="$ref:$pfx" |
125 | pfx="$pfx/" | |
126 | ;; | |
127 | *) | |
128 | ls="$ref" | |
129 | ;; | |
130 | esac | |
131 | COMPREPLY=($(compgen -P "$pfx" \ | |
873537fa | 132 | -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \ |
690d8824 JH |
133 | | sed '/^100... blob /s,^.* ,, |
134 | /^040000 tree /{ | |
135 | s,^.* ,, | |
136 | s,$,/, | |
137 | } | |
138 | s/^.* //')" \ | |
139 | -- "$cur")) | |
140 | ;; | |
141 | *) | |
873537fa | 142 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
143 | ;; |
144 | esac | |
145 | } | |
146 | ||
f53352fb SP |
147 | __git_complete_revlist () |
148 | { | |
149 | local pfx cur="${COMP_WORDS[COMP_CWORD]}" | |
150 | case "$cur" in | |
151 | *...*) | |
152 | pfx="${cur%...*}..." | |
153 | cur="${cur#*...}" | |
154 | COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur")) | |
155 | ;; | |
156 | *..*) | |
157 | pfx="${cur%..*}.." | |
158 | cur="${cur#*..}" | |
159 | COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur")) | |
160 | ;; | |
161 | *) | |
162 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) | |
163 | ;; | |
164 | esac | |
165 | } | |
166 | ||
f2bb9f88 SP |
167 | __git_commands () |
168 | { | |
169 | local i IFS=" "$'\n' | |
170 | for i in $(git help -a|egrep '^ ') | |
171 | do | |
172 | case $i in | |
173 | check-ref-format) : plumbing;; | |
174 | commit-tree) : plumbing;; | |
175 | convert-objects) : plumbing;; | |
176 | cvsserver) : daemon;; | |
177 | daemon) : daemon;; | |
178 | fetch-pack) : plumbing;; | |
179 | hash-object) : plumbing;; | |
180 | http-*) : transport;; | |
181 | index-pack) : plumbing;; | |
182 | local-fetch) : plumbing;; | |
183 | mailinfo) : plumbing;; | |
184 | mailsplit) : plumbing;; | |
185 | merge-*) : plumbing;; | |
186 | mktree) : plumbing;; | |
187 | mktag) : plumbing;; | |
188 | pack-objects) : plumbing;; | |
189 | pack-redundant) : plumbing;; | |
190 | pack-refs) : plumbing;; | |
191 | parse-remote) : plumbing;; | |
192 | patch-id) : plumbing;; | |
193 | peek-remote) : plumbing;; | |
194 | read-tree) : plumbing;; | |
195 | receive-pack) : plumbing;; | |
196 | rerere) : plumbing;; | |
197 | rev-list) : plumbing;; | |
198 | rev-parse) : plumbing;; | |
199 | runstatus) : plumbing;; | |
200 | sh-setup) : internal;; | |
201 | shell) : daemon;; | |
202 | send-pack) : plumbing;; | |
203 | show-index) : plumbing;; | |
204 | ssh-*) : transport;; | |
205 | stripspace) : plumbing;; | |
206 | symbolic-ref) : plumbing;; | |
207 | unpack-file) : plumbing;; | |
208 | unpack-objects) : plumbing;; | |
209 | update-ref) : plumbing;; | |
210 | update-server-info) : daemon;; | |
211 | upload-archive) : plumbing;; | |
212 | upload-pack) : plumbing;; | |
213 | write-tree) : plumbing;; | |
214 | *) echo $i;; | |
215 | esac | |
216 | done | |
217 | } | |
218 | ||
367dce2a DS |
219 | __git_aliases () |
220 | { | |
56fc25f2 | 221 | local i IFS=$'\n' |
873537fa | 222 | for i in $(git --git-dir="$(__gitdir)" repo-config --list); do |
56fc25f2 SP |
223 | case "$i" in |
224 | alias.*) | |
225 | i="${i#alias.}" | |
226 | echo "${i/=*/}" | |
227 | ;; | |
228 | esac | |
229 | done | |
367dce2a DS |
230 | } |
231 | ||
232 | __git_aliased_command () | |
233 | { | |
873537fa SP |
234 | local word cmdline=$(git --git-dir="$(__gitdir)" \ |
235 | repo-config --get "alias.$1") | |
367dce2a DS |
236 | for word in $cmdline; do |
237 | if [ "${word##-*}" ]; then | |
238 | echo $word | |
239 | return | |
240 | fi | |
241 | done | |
242 | } | |
243 | ||
690d8824 JH |
244 | _git_branch () |
245 | { | |
246 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 247 | COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur")) |
690d8824 JH |
248 | } |
249 | ||
250 | _git_cat_file () | |
251 | { | |
252 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
253 | case "${COMP_WORDS[0]},$COMP_CWORD" in | |
254 | git-cat-file*,1) | |
255 | COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur")) | |
256 | ;; | |
257 | git,2) | |
258 | COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur")) | |
259 | ;; | |
260 | *) | |
261 | __git_complete_file | |
262 | ;; | |
263 | esac | |
264 | } | |
265 | ||
266 | _git_checkout () | |
267 | { | |
268 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 269 | COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur")) |
690d8824 JH |
270 | } |
271 | ||
272 | _git_diff () | |
273 | { | |
274 | __git_complete_file | |
275 | } | |
276 | ||
277 | _git_diff_tree () | |
278 | { | |
279 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 280 | COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur")) |
690d8824 JH |
281 | } |
282 | ||
283 | _git_fetch () | |
284 | { | |
285 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
286 | ||
287 | case "${COMP_WORDS[0]},$COMP_CWORD" in | |
288 | git-fetch*,1) | |
289 | COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) | |
290 | ;; | |
291 | git,2) | |
292 | COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) | |
293 | ;; | |
294 | *) | |
295 | case "$cur" in | |
296 | *:*) | |
a79c6551 | 297 | cur="${cur#*:}" |
873537fa | 298 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
299 | ;; |
300 | *) | |
301 | local remote | |
302 | case "${COMP_WORDS[0]}" in | |
303 | git-fetch) remote="${COMP_WORDS[1]}" ;; | |
304 | git) remote="${COMP_WORDS[2]}" ;; | |
305 | esac | |
306 | COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur")) | |
307 | ;; | |
308 | esac | |
309 | ;; | |
310 | esac | |
311 | } | |
312 | ||
f53352fb SP |
313 | _git_format_patch () |
314 | { | |
315 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
316 | case "$cur" in | |
317 | --*) | |
318 | COMPREPLY=($(compgen -W " | |
319 | --stdout --attach --thread | |
320 | --output-directory | |
321 | --numbered --start-number | |
322 | --keep-subject | |
323 | --signoff | |
324 | --in-reply-to= | |
325 | --full-index --binary | |
326 | " -- "$cur")) | |
327 | return | |
328 | ;; | |
329 | esac | |
330 | __git_complete_revlist | |
331 | } | |
332 | ||
690d8824 JH |
333 | _git_ls_remote () |
334 | { | |
335 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
336 | COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) | |
337 | } | |
338 | ||
339 | _git_ls_tree () | |
340 | { | |
341 | __git_complete_file | |
342 | } | |
343 | ||
344 | _git_log () | |
345 | { | |
f53352fb | 346 | __git_complete_revlist |
690d8824 JH |
347 | } |
348 | ||
4ad91321 SP |
349 | _git_merge () |
350 | { | |
351 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
352 | case "$cur" in | |
353 | --*) | |
354 | COMPREPLY=($(compgen -W " | |
355 | --no-commit --no-summary --squash | |
356 | " -- "$cur")) | |
357 | return | |
358 | esac | |
359 | if [ $COMP_CWORD -gt 1 -a X-s = "X${COMP_WORDS[COMP_CWORD-1]}" ] | |
360 | then | |
361 | COMPREPLY=($(compgen -W "$(__git_merge_strategies)" -- "$cur")) | |
362 | else | |
363 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) | |
364 | fi | |
365 | } | |
366 | ||
690d8824 JH |
367 | _git_merge_base () |
368 | { | |
369 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 370 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
371 | } |
372 | ||
d33909bf SP |
373 | _git_name_rev () |
374 | { | |
375 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
376 | COMPREPLY=($(compgen -W "--tags --all --stdin" -- "$cur")) | |
377 | } | |
378 | ||
690d8824 JH |
379 | _git_pull () |
380 | { | |
381 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
382 | ||
383 | case "${COMP_WORDS[0]},$COMP_CWORD" in | |
384 | git-pull*,1) | |
385 | COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) | |
386 | ;; | |
387 | git,2) | |
388 | COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) | |
389 | ;; | |
390 | *) | |
391 | local remote | |
392 | case "${COMP_WORDS[0]}" in | |
393 | git-pull) remote="${COMP_WORDS[1]}" ;; | |
394 | git) remote="${COMP_WORDS[2]}" ;; | |
395 | esac | |
396 | COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur")) | |
397 | ;; | |
398 | esac | |
399 | } | |
400 | ||
401 | _git_push () | |
402 | { | |
403 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
404 | ||
405 | case "${COMP_WORDS[0]},$COMP_CWORD" in | |
406 | git-push*,1) | |
407 | COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) | |
408 | ;; | |
409 | git,2) | |
410 | COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur")) | |
411 | ;; | |
412 | *) | |
413 | case "$cur" in | |
414 | *:*) | |
415 | local remote | |
416 | case "${COMP_WORDS[0]}" in | |
417 | git-push) remote="${COMP_WORDS[1]}" ;; | |
418 | git) remote="${COMP_WORDS[2]}" ;; | |
419 | esac | |
a79c6551 | 420 | cur="${cur#*:}" |
690d8824 JH |
421 | COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur")) |
422 | ;; | |
423 | *) | |
873537fa | 424 | COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur")) |
690d8824 JH |
425 | ;; |
426 | esac | |
427 | ;; | |
428 | esac | |
429 | } | |
430 | ||
67e78c3b SP |
431 | _git_reset () |
432 | { | |
433 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
434 | local opt="--mixed --hard --soft" | |
873537fa | 435 | COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur")) |
67e78c3b SP |
436 | } |
437 | ||
690d8824 JH |
438 | _git_show () |
439 | { | |
440 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 441 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
442 | } |
443 | ||
444 | _git () | |
445 | { | |
873537fa SP |
446 | local i c=1 command __git_dir |
447 | ||
448 | while [ $c -lt $COMP_CWORD ]; do | |
449 | i="${COMP_WORDS[c]}" | |
450 | case "$i" in | |
451 | --git-dir=*) __git_dir="${i#--git-dir=}" ;; | |
452 | --bare) __git_dir="." ;; | |
453 | --version|--help|-p|--paginate) ;; | |
454 | *) command="$i"; break ;; | |
455 | esac | |
456 | c=$((++c)) | |
457 | done | |
458 | ||
459 | if [ $c -eq $COMP_CWORD -a -z "$command" ]; then | |
f2bb9f88 SP |
460 | COMPREPLY=($(compgen -W " |
461 | --git-dir= --version --exec-path | |
462 | $(__git_commands) | |
463 | $(__git_aliases) | |
464 | " -- "${COMP_WORDS[COMP_CWORD]}")) | |
873537fa SP |
465 | return; |
466 | fi | |
367dce2a | 467 | |
873537fa SP |
468 | local expansion=$(__git_aliased_command "$command") |
469 | [ "$expansion" ] && command="$expansion" | |
367dce2a | 470 | |
873537fa SP |
471 | case "$command" in |
472 | branch) _git_branch ;; | |
473 | cat-file) _git_cat_file ;; | |
474 | checkout) _git_checkout ;; | |
475 | diff) _git_diff ;; | |
476 | diff-tree) _git_diff_tree ;; | |
477 | fetch) _git_fetch ;; | |
f53352fb | 478 | format-patch) _git_format_patch ;; |
873537fa SP |
479 | log) _git_log ;; |
480 | ls-remote) _git_ls_remote ;; | |
481 | ls-tree) _git_ls_tree ;; | |
4ad91321 | 482 | merge) _git_merge;; |
873537fa | 483 | merge-base) _git_merge_base ;; |
d33909bf | 484 | name-rev) _git_name_rev ;; |
873537fa SP |
485 | pull) _git_pull ;; |
486 | push) _git_push ;; | |
487 | reset) _git_reset ;; | |
488 | show) _git_show ;; | |
489 | show-branch) _git_log ;; | |
490 | whatchanged) _git_log ;; | |
491 | *) COMPREPLY=() ;; | |
492 | esac | |
690d8824 JH |
493 | } |
494 | ||
495 | _gitk () | |
496 | { | |
497 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 498 | COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur")) |
690d8824 JH |
499 | } |
500 | ||
501 | complete -o default -o nospace -F _git git | |
502 | complete -o default -F _gitk gitk | |
503 | complete -o default -F _git_branch git-branch | |
504 | complete -o default -o nospace -F _git_cat_file git-cat-file | |
505 | complete -o default -F _git_checkout git-checkout | |
506 | complete -o default -o nospace -F _git_diff git-diff | |
507 | complete -o default -F _git_diff_tree git-diff-tree | |
508 | complete -o default -o nospace -F _git_fetch git-fetch | |
f53352fb | 509 | complete -o default -o nospace -F _git_format_patch git-format-patch |
690d8824 JH |
510 | complete -o default -o nospace -F _git_log git-log |
511 | complete -o default -F _git_ls_remote git-ls-remote | |
512 | complete -o default -o nospace -F _git_ls_tree git-ls-tree | |
4ad91321 | 513 | complete -o default -F _git_merge git-merge |
690d8824 | 514 | complete -o default -F _git_merge_base git-merge-base |
d33909bf | 515 | complete -o default -F _git_name_rev git-name-rev |
690d8824 JH |
516 | complete -o default -o nospace -F _git_pull git-pull |
517 | complete -o default -o nospace -F _git_push git-push | |
67e78c3b | 518 | complete -o default -F _git_reset git-reset |
690d8824 | 519 | complete -o default -F _git_show git-show |
144d33de | 520 | complete -o default -o nospace -F _git_log git-show-branch |
690d8824 JH |
521 | complete -o default -o nospace -F _git_log git-whatchanged |
522 | ||
523 | # The following are necessary only for Cygwin, and only are needed | |
524 | # when the user has tab-completed the executable name and consequently | |
525 | # included the '.exe' suffix. | |
526 | # | |
76c3eb51 | 527 | if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then |
144d33de | 528 | complete -o default -o nospace -F _git git.exe |
dfb96092 | 529 | complete -o default -F _git_branch git-branch.exe |
690d8824 JH |
530 | complete -o default -o nospace -F _git_cat_file git-cat-file.exe |
531 | complete -o default -o nospace -F _git_diff git-diff.exe | |
532 | complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe | |
f53352fb | 533 | complete -o default -o nospace -F _git_format_patch git-format-patch.exe |
690d8824 JH |
534 | complete -o default -o nospace -F _git_log git-log.exe |
535 | complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe | |
536 | complete -o default -F _git_merge_base git-merge-base.exe | |
d33909bf | 537 | complete -o default -F _git_name_rev git-name-rev.exe |
690d8824 | 538 | complete -o default -o nospace -F _git_push git-push.exe |
144d33de | 539 | complete -o default -o nospace -F _git_log git-show-branch.exe |
690d8824 | 540 | complete -o default -o nospace -F _git_log git-whatchanged.exe |
76c3eb51 | 541 | fi |