]>
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 | ||
f2bb9f88 SP |
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 | ||
367dce2a DS |
199 | __git_aliases () |
200 | { | |
56fc25f2 | 201 | local i IFS=$'\n' |
873537fa | 202 | for i in $(git --git-dir="$(__gitdir)" repo-config --list); do |
56fc25f2 SP |
203 | case "$i" in |
204 | alias.*) | |
205 | i="${i#alias.}" | |
206 | echo "${i/=*/}" | |
207 | ;; | |
208 | esac | |
209 | done | |
367dce2a DS |
210 | } |
211 | ||
212 | __git_aliased_command () | |
213 | { | |
873537fa SP |
214 | local word cmdline=$(git --git-dir="$(__gitdir)" \ |
215 | repo-config --get "alias.$1") | |
367dce2a DS |
216 | for word in $cmdline; do |
217 | if [ "${word##-*}" ]; then | |
218 | echo $word | |
219 | return | |
220 | fi | |
221 | done | |
222 | } | |
223 | ||
690d8824 JH |
224 | _git_branch () |
225 | { | |
226 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 227 | COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur")) |
690d8824 JH |
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]}" | |
873537fa | 249 | COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur")) |
690d8824 JH |
250 | } |
251 | ||
252 | _git_diff () | |
253 | { | |
254 | __git_complete_file | |
255 | } | |
256 | ||
257 | _git_diff_tree () | |
258 | { | |
259 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 260 | COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur")) |
690d8824 JH |
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 | *:*) | |
a79c6551 | 277 | cur="${cur#*:}" |
873537fa | 278 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
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 | { | |
e5d5b21f | 306 | local pfx cur="${COMP_WORDS[COMP_CWORD]}" |
690d8824 | 307 | case "$cur" in |
e5d5b21f SP |
308 | *...*) |
309 | pfx="${cur%...*}..." | |
310 | cur="${cur#*...}" | |
311 | COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur")) | |
312 | ;; | |
690d8824 | 313 | *..*) |
e5d5b21f SP |
314 | pfx="${cur%..*}.." |
315 | cur="${cur#*..}" | |
873537fa | 316 | COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
317 | ;; |
318 | *) | |
873537fa | 319 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
320 | ;; |
321 | esac | |
322 | } | |
323 | ||
4ad91321 SP |
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 | ||
690d8824 JH |
342 | _git_merge_base () |
343 | { | |
344 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 345 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
346 | } |
347 | ||
d33909bf SP |
348 | _git_name_rev () |
349 | { | |
350 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
351 | COMPREPLY=($(compgen -W "--tags --all --stdin" -- "$cur")) | |
352 | } | |
353 | ||
690d8824 JH |
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 | |
a79c6551 | 395 | cur="${cur#*:}" |
690d8824 JH |
396 | COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur")) |
397 | ;; | |
398 | *) | |
873537fa | 399 | COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur")) |
690d8824 JH |
400 | ;; |
401 | esac | |
402 | ;; | |
403 | esac | |
404 | } | |
405 | ||
67e78c3b SP |
406 | _git_reset () |
407 | { | |
408 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
409 | local opt="--mixed --hard --soft" | |
873537fa | 410 | COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur")) |
67e78c3b SP |
411 | } |
412 | ||
690d8824 JH |
413 | _git_show () |
414 | { | |
415 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 416 | COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur")) |
690d8824 JH |
417 | } |
418 | ||
419 | _git () | |
420 | { | |
873537fa SP |
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 | |
f2bb9f88 SP |
435 | COMPREPLY=($(compgen -W " |
436 | --git-dir= --version --exec-path | |
437 | $(__git_commands) | |
438 | $(__git_aliases) | |
439 | " -- "${COMP_WORDS[COMP_CWORD]}")) | |
873537fa SP |
440 | return; |
441 | fi | |
367dce2a | 442 | |
873537fa SP |
443 | local expansion=$(__git_aliased_command "$command") |
444 | [ "$expansion" ] && command="$expansion" | |
367dce2a | 445 | |
873537fa SP |
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 ;; | |
4ad91321 | 456 | merge) _git_merge;; |
873537fa | 457 | merge-base) _git_merge_base ;; |
d33909bf | 458 | name-rev) _git_name_rev ;; |
873537fa SP |
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 | |
690d8824 JH |
467 | } |
468 | ||
469 | _gitk () | |
470 | { | |
471 | local cur="${COMP_WORDS[COMP_CWORD]}" | |
873537fa | 472 | COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur")) |
690d8824 JH |
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 | |
4ad91321 | 486 | complete -o default -F _git_merge git-merge |
690d8824 | 487 | complete -o default -F _git_merge_base git-merge-base |
d33909bf | 488 | complete -o default -F _git_name_rev git-name-rev |
690d8824 JH |
489 | complete -o default -o nospace -F _git_pull git-pull |
490 | complete -o default -o nospace -F _git_push git-push | |
67e78c3b | 491 | complete -o default -F _git_reset git-reset |
690d8824 | 492 | complete -o default -F _git_show git-show |
144d33de | 493 | complete -o default -o nospace -F _git_log git-show-branch |
690d8824 JH |
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 | # | |
76c3eb51 | 500 | if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then |
144d33de | 501 | complete -o default -o nospace -F _git git.exe |
dfb96092 | 502 | complete -o default -F _git_branch git-branch.exe |
690d8824 JH |
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 | |
d33909bf | 509 | complete -o default -F _git_name_rev git-name-rev.exe |
690d8824 | 510 | complete -o default -o nospace -F _git_push git-push.exe |
144d33de | 511 | complete -o default -o nospace -F _git_log git-show-branch.exe |
690d8824 | 512 | complete -o default -o nospace -F _git_log git-whatchanged.exe |
76c3eb51 | 513 | fi |