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 REVERTGLOB=$(shopt -p nullglob)
63 shopt -s nullglob
64 for i in .git/remotes/*; do
65 echo ${i#.git/remotes/}
66 done
67 $REVERTGLOB
68}
69
70__git_complete_file ()
71{
72 local cur="${COMP_WORDS[COMP_CWORD]}"
73 case "$cur" in
74 ?*:*)
75 local pfx ls ref="$(echo "$cur" | sed 's,:.*$,,')"
76 cur="$(echo "$cur" | sed 's,^.*:,,')"
77 case "$cur" in
78 ?*/*)
79 pfx="$(echo "$cur" | sed 's,/[^/]*$,,')"
80 cur="$(echo "$cur" | sed 's,^.*/,,')"
81 ls="$ref:$pfx"
82 pfx="$pfx/"
83 ;;
84 *)
85 ls="$ref"
86 ;;
87 esac
88 COMPREPLY=($(compgen -P "$pfx" \
89 -W "$(git-ls-tree "$ls" \
90 | sed '/^100... blob /s,^.* ,,
91 /^040000 tree /{
92 s,^.* ,,
93 s,$,/,
94 }
95 s/^.* //')" \
96 -- "$cur"))
97 ;;
98 *)
99 COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
100 ;;
101 esac
102}
103
104_git_branch ()
105{
106 local cur="${COMP_WORDS[COMP_CWORD]}"
107 COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs .)" -- "$cur"))
108}
109
110_git_cat_file ()
111{
112 local cur="${COMP_WORDS[COMP_CWORD]}"
113 case "${COMP_WORDS[0]},$COMP_CWORD" in
114 git-cat-file*,1)
115 COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
116 ;;
117 git,2)
118 COMPREPLY=($(compgen -W "-p -t blob tree commit tag" -- "$cur"))
119 ;;
120 *)
121 __git_complete_file
122 ;;
123 esac
124}
125
126_git_checkout ()
127{
128 local cur="${COMP_WORDS[COMP_CWORD]}"
129 COMPREPLY=($(compgen -W "-l -b $(__git_refs .)" -- "$cur"))
130}
131
132_git_diff ()
133{
134 __git_complete_file
135}
136
137_git_diff_tree ()
138{
139 local cur="${COMP_WORDS[COMP_CWORD]}"
140 COMPREPLY=($(compgen -W "-r -p -M $(__git_refs .)" -- "$cur"))
141}
142
143_git_fetch ()
144{
145 local cur="${COMP_WORDS[COMP_CWORD]}"
146
147 case "${COMP_WORDS[0]},$COMP_CWORD" in
148 git-fetch*,1)
149 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
150 ;;
151 git,2)
152 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
153 ;;
154 *)
155 case "$cur" in
156 *:*)
157 cur=$(echo "$cur" | sed 's/^.*://')
158 COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
159 ;;
160 *)
161 local remote
162 case "${COMP_WORDS[0]}" in
163 git-fetch) remote="${COMP_WORDS[1]}" ;;
164 git) remote="${COMP_WORDS[2]}" ;;
165 esac
166 COMPREPLY=($(compgen -W "$(__git_refs2 "$remote")" -- "$cur"))
167 ;;
168 esac
169 ;;
170 esac
171}
172
173_git_ls_remote ()
174{
175 local cur="${COMP_WORDS[COMP_CWORD]}"
176 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
177}
178
179_git_ls_tree ()
180{
181 __git_complete_file
182}
183
184_git_log ()
185{
186 local cur="${COMP_WORDS[COMP_CWORD]}"
187 case "$cur" in
188 *..*)
189 local pfx=$(echo "$cur" | sed 's/\.\..*$/../')
190 cur=$(echo "$cur" | sed 's/^.*\.\.//')
191 COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs .)" -- "$cur"))
192 ;;
193 *)
194 COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
195 ;;
196 esac
197}
198
199_git_merge_base ()
200{
201 local cur="${COMP_WORDS[COMP_CWORD]}"
202 COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
203}
204
205_git_pull ()
206{
207 local cur="${COMP_WORDS[COMP_CWORD]}"
208
209 case "${COMP_WORDS[0]},$COMP_CWORD" in
210 git-pull*,1)
211 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
212 ;;
213 git,2)
214 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
215 ;;
216 *)
217 local remote
218 case "${COMP_WORDS[0]}" in
219 git-pull) remote="${COMP_WORDS[1]}" ;;
220 git) remote="${COMP_WORDS[2]}" ;;
221 esac
222 COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
223 ;;
224 esac
225}
226
227_git_push ()
228{
229 local cur="${COMP_WORDS[COMP_CWORD]}"
230
231 case "${COMP_WORDS[0]},$COMP_CWORD" in
232 git-push*,1)
233 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
234 ;;
235 git,2)
236 COMPREPLY=($(compgen -W "$(__git_remotes)" -- "$cur"))
237 ;;
238 *)
239 case "$cur" in
240 *:*)
241 local remote
242 case "${COMP_WORDS[0]}" in
243 git-push) remote="${COMP_WORDS[1]}" ;;
244 git) remote="${COMP_WORDS[2]}" ;;
245 esac
246 cur=$(echo "$cur" | sed 's/^.*://')
247 COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
248 ;;
249 *)
250 COMPREPLY=($(compgen -W "$(__git_refs2 .)" -- "$cur"))
251 ;;
252 esac
253 ;;
254 esac
255}
256
257_git_show ()
258{
259 local cur="${COMP_WORDS[COMP_CWORD]}"
260 COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
261}
262
263_git ()
264{
265 if [ $COMP_CWORD = 1 ]; then
266 COMPREPLY=($(compgen \
267 -W "--version $(git help -a|egrep '^ ')" \
268 -- "${COMP_WORDS[COMP_CWORD]}"))
269 else
270 case "${COMP_WORDS[1]}" in
271 branch) _git_branch ;;
272 cat-file) _git_cat_file ;;
273 checkout) _git_checkout ;;
274 diff) _git_diff ;;
275 diff-tree) _git_diff_tree ;;
276 fetch) _git_fetch ;;
277 log) _git_log ;;
278 ls-remote) _git_ls_remote ;;
279 ls-tree) _git_ls_tree ;;
280 pull) _git_pull ;;
281 push) _git_push ;;
282 show) _git_show ;;
283 show-branch) _git_log ;;
284 whatchanged) _git_log ;;
285 *) COMPREPLY=() ;;
286 esac
287 fi
288}
289
290_gitk ()
291{
292 local cur="${COMP_WORDS[COMP_CWORD]}"
293 COMPREPLY=($(compgen -W "--all $(__git_refs .)" -- "$cur"))
294}
295
296complete -o default -o nospace -F _git git
297complete -o default -F _gitk gitk
298complete -o default -F _git_branch git-branch
299complete -o default -o nospace -F _git_cat_file git-cat-file
300complete -o default -F _git_checkout git-checkout
301complete -o default -o nospace -F _git_diff git-diff
302complete -o default -F _git_diff_tree git-diff-tree
303complete -o default -o nospace -F _git_fetch git-fetch
304complete -o default -o nospace -F _git_log git-log
305complete -o default -F _git_ls_remote git-ls-remote
306complete -o default -o nospace -F _git_ls_tree git-ls-tree
307complete -o default -F _git_merge_base git-merge-base
308complete -o default -o nospace -F _git_pull git-pull
309complete -o default -o nospace -F _git_push git-push
310complete -o default -F _git_show git-show
311complete -o default -o nospace -F _git_log git-whatchanged
312
313# The following are necessary only for Cygwin, and only are needed
314# when the user has tab-completed the executable name and consequently
315# included the '.exe' suffix.
316#
317complete -o default -o nospace -F _git_cat_file git-cat-file.exe
318complete -o default -o nospace -F _git_diff git-diff.exe
319complete -o default -o nospace -F _git_diff_tree git-diff-tree.exe
320complete -o default -o nospace -F _git_log git-log.exe
321complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
322complete -o default -F _git_merge_base git-merge-base.exe
323complete -o default -o nospace -F _git_push git-push.exe
324complete -o default -o nospace -F _git_log git-whatchanged.exe