1 # Exposes Git repository information via the $git_info associative array.
4 # Sorin Ionescu <sorin.ionescu@gmail.com>
7 # Gets the Git special action (am, bisect, cherry, merge, rebase).
8 # Borrowed from vcs_info and edited.
11 local git_dir
="$(git-dir)"
13 local bisect_formatted
14 local cherry_pick_formatted
15 local cherry_pick_sequence_formatted
17 local rebase_formatted
18 local rebase_interactive_formatted
19 local rebase_merge_formatted
22 "${git_dir}/rebase-apply" \
24 "${git_dir}/../.dotest"
26 if [[ -d "$action_dir" ]] ; then
27 zstyle
-s ':git:info:action:apply' format
'apply_formatted' || apply_formatted
='apply'
28 zstyle
-s ':git:info:action:rebase' format
'rebase_formatted' || rebase_formatted
='rebase'
30 if [[ -f "${action_dir}/rebasing" ]] ; then
31 print
"$rebase_formatted"
32 elif [[ -f "${action_dir}/applying" ]] ; then
33 print
"$apply_formatted"
35 print
"${rebase_formatted}/${apply_formatted}"
43 "${git_dir}/rebase-merge/interactive" \
44 "${git_dir}/.dotest-merge/interactive"
46 if [[ -f "$action_dir" ]]; then
47 zstyle
-s ':git:info:action:rebase-interactive' format
'rebase_interactive_formatted' || rebase_interactive_formatted
='rebase-interactive'
48 print
"$rebase_interactive_formatted"
54 "${git_dir}/rebase-merge" \
55 "${git_dir}/.dotest-merge"
57 if [[ -d "$action_dir" ]]; then
58 zstyle
-s ':git:info:action:rebase-merge' format
'rebase_merge_formatted' || rebase_merge_formatted
='rebase-merge'
59 print
"$rebase_merge_formatted"
64 if [[ -f "${git_dir}/MERGE_HEAD" ]]; then
65 zstyle
-s ':git:info:action:merge' format
'merge_formatted' || merge_formatted
='merge'
66 print
"$merge_formatted"
70 if [[ -f "${git_dir}/CHERRY_PICK_HEAD" ]]; then
71 if [[ -d "${git_dir}/sequencer" ]] ; then
72 zstyle
-s ':git:info:action:cherry-pick-sequence' format
'cherry_pick_sequence_formatted' || cherry_pick_sequence_formatted
='cherry-pick-sequence'
73 print
"$cherry_pick_sequence_formatted"
75 zstyle
-s ':git:info:action:cherry-pick' format
'cherry_pick_formatted' || cherry_pick_formatted
='cherry-pick'
76 print
"$cherry_pick_formatted"
82 if [[ -f "${git_dir}/BISECT_LOG" ]]; then
83 zstyle
-s ':git:info:action:bisect' format
'bisect_formatted' || bisect_formatted
='bisect'
84 print
"$bisect_formatted"
91 # Gets the Git status information.
93 # Extended globbing is needed to parse repository status.
99 local action_formatted
102 local added_formatted
104 local ahead_and_behind
105 local ahead_and_behind_cmd
107 local ahead_formatted
108 local ahead_or_behind
111 local behind_formatted
114 local branch_formatted
117 local clean_formatted
120 local commit_formatted
123 local deleted_formatted
126 local dirty_formatted
127 local ignore_submodules
130 local indexed_formatted
131 local -A info_formats
134 local modified_format
135 local modified_formatted
137 local position_format
138 local position_formatted
142 local remote_formatted
145 local renamed_formatted
148 local stashed_formatted
152 local unindexed_format
153 local unindexed_formatted
155 local unmerged_format
156 local unmerged_formatted
158 local untracked_format
159 local untracked_formatted
161 # Clean up previous $git_info.
165 # Return if not inside a Git repository work tree.
166 if [ "$(git rev-parse --is-inside-work-tree 2> /dev/null)" != 'true' ]; then
170 if (( $# > 0 )); then
171 if [[ "$1" == [Oo
][Nn
] ]]; then
172 git config
--bool prompt.showinfo true
173 elif [[ "$1" == [Oo
][Ff
][Ff
] ]]; then
174 git config
--bool prompt.showinfo false
176 print
"usage: $0 [ on | off ]" >&2
181 # Ignore submodule status.
182 zstyle
-s ':git:status:ignore' submodules
'ignore_submodules'
185 zstyle
-s ':git:info:commit' format
'commit_format'
186 if [[ -n "$commit_format" ]]; then
187 commit
="$(git rev-parse HEAD 2> /dev/null)"
188 if [[ -n "$commit" ]]; then
189 zformat
-f commit_formatted
"$commit_format" "c:$commit"
194 zstyle
-s ':git:info:stashed' format
'stashed_format'
195 if [[ -n "$stashed_format" && -f "$(git-dir)/refs/stash" ]]; then
196 stashed
="$(git stash list 2> /dev/null | wc -l | awk '{print $1}')"
197 if [[ -n "$stashed" ]]; then
198 zformat
-f stashed_formatted
"$stashed_format" "S:$stashed"
203 zstyle
-s ':git:info:action' format
'action_format'
204 if [[ -n "$action_format" ]]; then
205 action
="$(_git-action)"
206 if [[ -n "$action" ]]; then
207 zformat
-f action_formatted
"$action_format" "s:$action"
212 branch
="${$(git symbolic-ref HEAD 2> /dev/null)#refs/heads/}"
215 zstyle
-s ':git:info:branch' format
'branch_format'
216 if [[ -n "$branch" && -n "$branch_format" ]]; then
217 zformat
-f branch_formatted
"$branch_format" "b:$branch"
221 zstyle
-s ':git:info:position' format
'position_format'
222 if [[ -z "$branch" && -n "$position_format" ]]; then
223 position
="$(git describe --contains --all HEAD 2> /dev/null)"
224 if [[ -n "$position" ]]; then
225 zformat
-f position_formatted
"$position_format" "p:$position"
230 zstyle
-s ':git:info:remote' format
'remote_format'
231 if [[ -n "$branch" && -n "$remote_format" ]]; then
232 # Gets the remote name.
233 remote_cmd
='git rev-parse --symbolic-full-name --verify HEAD@{upstream}'
234 remote
="${$(${(z)remote_cmd} 2> /dev/null)##refs/remotes/}"
235 if [[ -n "$remote" ]]; then
236 zformat
-f remote_formatted
"$remote_format" "R:$remote"
240 zstyle
-s ':git:info:ahead' format
'ahead_format'
241 zstyle
-s ':git:info:behind' format
'behind_format'
242 if [[ -n "$branch" && ( -n "$ahead_format" || -n "$behind_format" ) ]]; then
243 # Gets the commit difference counts between local and remote.
244 ahead_and_behind_cmd
='git rev-list --count --left-right HEAD...@{upstream}'
246 # Get ahead and behind counts.
247 ahead_and_behind
="$(${(z)ahead_and_behind_cmd} 2> /dev/null)"
250 if [[ -n "$ahead_format" ]]; then
251 ahead
="$ahead_and_behind[(w)1]"
252 if (( ahead
> 0 )); then
253 zformat
-f ahead_formatted
"$ahead_format" "A:$ahead"
258 if [[ -n "$behind_format" ]]; then
259 behind
="$ahead_and_behind[(w)2]"
260 if (( behind
> 0 )); then
261 zformat
-f behind_formatted
"$behind_format" "B:$behind"
267 if ! zstyle
-t ':git:info' verbose
; then
269 zstyle
-s ':git:info:indexed' format
'indexed_format'
270 if [[ -n "$indexed_format" ]]; then
277 --ignore-submodules=${ignore_submodules:-none} \
283 if (( indexed
> 0 )); then
284 zformat
-f indexed_formatted
"$indexed_format" "i:$indexed"
289 zstyle
-s ':git:info:unindexed' format
'unindexed_format'
290 if [[ -n "$unindexed_format" ]]; then
296 --ignore-submodules=${ignore_submodules:-none} \
301 if (( unindexed
> 0 )); then
302 zformat
-f unindexed_formatted
"$unindexed_format" "I:$unindexed"
307 zstyle
-s ':git:info:untracked' format
'untracked_format'
308 if [[ -n "$untracked_format" ]]; then
318 if (( untracked
> 0 )); then
319 zformat
-f untracked_formatted
"$untracked_format" "u:$untracked"
323 (( dirty
= indexed
+ unindexed
+ untracked
))
325 # Use porcelain status for easy parsing.
326 status_cmd
="git status --porcelain --ignore-submodules=${ignore_submodules:-none}"
328 # Get current status.
329 while IFS
=$
'\n' read line
; do
330 # Count added, deleted, modified, renamed, unmerged, untracked, dirty.
331 # T (type change) is undocumented, see http://git.io/FnpMGw.
332 # For a table of scenarii, see http://i.imgur.com/2YLu1.png.
333 [[ "$line" == ([ACDMT
][\ MT
]|[ACMT
]D
)\
* ]] && (( added
++ ))
334 [[ "$line" == [\ ACMRT
]D\
* ]] && (( deleted
++ ))
335 [[ "$line" == ?
[MT
]\
* ]] && (( modified
++ ))
336 [[ "$line" == R?\
* ]] && (( renamed
++ ))
337 [[ "$line" == (AA
|DD
|U?
|?U
)\
* ]] && (( unmerged
++ ))
338 [[ "$line" == \?\?\
* ]] && (( untracked
++ ))
340 done < <(${(z)status_cmd} 2> /dev
/null
)
343 if (( added
> 0 )); then
344 zstyle
-s ':git:info:added' format
'added_format'
345 zformat
-f added_formatted
"$added_format" "a:$added"
349 if (( deleted
> 0 )); then
350 zstyle
-s ':git:info:deleted' format
'deleted_format'
351 zformat
-f deleted_formatted
"$deleted_format" "d:$deleted"
355 if (( modified
> 0 )); then
356 zstyle
-s ':git:info:modified' format
'modified_format'
357 zformat
-f modified_formatted
"$modified_format" "m:$modified"
361 if (( renamed
> 0 )); then
362 zstyle
-s ':git:info:renamed' format
'renamed_format'
363 zformat
-f renamed_formatted
"$renamed_format" "r:$renamed"
367 if (( unmerged
> 0 )); then
368 zstyle
-s ':git:info:unmerged' format
'unmerged_format'
369 zformat
-f unmerged_formatted
"$unmerged_format" "U:$unmerged"
373 if (( untracked
> 0 )); then
374 zstyle
-s ':git:info:untracked' format
'untracked_format'
375 zformat
-f untracked_formatted
"$untracked_format" "u:$untracked"
379 # Format dirty and clean.
380 if (( dirty
> 0 )); then
381 zstyle
-s ':git:info:dirty' format
'dirty_format'
382 zformat
-f dirty_formatted
"$dirty_format" "D:$dirty"
384 zstyle
-s ':git:info:clean' format
'clean_formatted'
388 zstyle
-a ':git:info:keys' format
'info_formats'
389 for info_format
in ${(k)info_formats}; do
390 zformat
-f REPLY
"$info_formats[$info_format]" \
391 "a:$added_formatted" \
392 "A:$ahead_formatted" \
393 "B:$behind_formatted" \
394 "b:$branch_formatted" \
395 "C:$clean_formatted" \
396 "c:$commit_formatted" \
397 "d:$deleted_formatted" \
398 "D:$dirty_formatted" \
399 "i:$indexed_formatted" \
400 "I:$unindexed_formatted" \
401 "m:$modified_formatted" \
402 "p:$position_formatted" \
403 "R:$remote_formatted" \
404 "r:$renamed_formatted" \
405 "s:$action_formatted" \
406 "S:$stashed_formatted" \
407 "U:$unmerged_formatted" \
408 "u:$untracked_formatted"
409 git_info
[$info_format]="$REPLY"