## vim:ft=zsh ## git support by: Frank Terbeck ## Distributed under the same BSD-ish license as zsh itself. setopt localoptions extendedglob NO_shwordsplit local gitdir gitbase gitbranch gitaction gitunstaged gitstaged gitsha1 gitmisc local -i querystaged queryunstaged local -a git_patches_applied git_patches_unapplied local -A hook_com VCS_INFO_git_getaction () { local gitdir=$1 local tmp for tmp in "${gitdir}/rebase-apply" \ "${gitdir}/rebase" \ "${gitdir}/../.dotest" ; do if [[ -d ${tmp} ]] ; then if [[ -f "${tmp}/rebasing" ]] ; then gitaction="rebase" elif [[ -f "${tmp}/applying" ]] ; then gitaction="am" else gitaction="am/rebase" fi return 0 fi done for tmp in "${gitdir}/rebase-merge/interactive" \ "${gitdir}/.dotest-merge/interactive" ; do if [[ -f "${tmp}" ]] ; then gitaction="rebase-i" return 0 fi done for tmp in "${gitdir}/rebase-merge" \ "${gitdir}/.dotest-merge" ; do if [[ -d "${tmp}" ]] ; then gitaction="rebase-m" return 0 fi done if [[ -f "${gitdir}/MERGE_HEAD" ]] ; then gitaction="merge" return 0 fi if [[ -f "${gitdir}/BISECT_LOG" ]] ; then gitaction="bisect" return 0 fi if [[ -f "${gitdir}/CHERRY_PICK_HEAD" ]] ; then if [[ -d "${gitdir}/sequencer" ]] ; then gitaction=cherry-seq else gitaction=cherry fi return 0 fi if [[ -d "${gitdir}/sequencer" ]] ; then gitaction="cherry-or-revert" return 0 fi return 1 } VCS_INFO_git_getbranch () { local gitdir=$1 tmp actiondir local gitsymref="${vcs_comm[cmd]} symbolic-ref HEAD" actiondir='' for tmp in "${gitdir}/rebase-apply" \ "${gitdir}/rebase" \ "${gitdir}/../.dotest"; do if [[ -d ${tmp} ]]; then actiondir=${tmp} break fi done if [[ -n ${actiondir} ]]; then gitbranch="$(${(z)gitsymref} 2> /dev/null)" [[ -z ${gitbranch} ]] && [[ -r ${actiondir}/head-name ]] \ && gitbranch="$(< ${actiondir}/head-name)" elif [[ -f "${gitdir}/MERGE_HEAD" ]] ; then gitbranch="$(${(z)gitsymref} 2> /dev/null)" [[ -z ${gitbranch} ]] && gitbranch="$(< ${gitdir}/MERGE_HEAD)" elif [[ -d "${gitdir}/rebase-merge" ]] ; then gitbranch="$(< ${gitdir}/rebase-merge/head-name)" elif [[ -d "${gitdir}/.dotest-merge" ]] ; then gitbranch="$(< ${gitdir}/.dotest-merge/head-name)" else gitbranch="$(${(z)gitsymref} 2> /dev/null)" if [[ $? -ne 0 ]] ; then gitbranch="refs/tags/$(${vcs_comm[cmd]} describe --all --exact-match HEAD 2>/dev/null)" if [[ $? -ne 0 ]] ; then gitbranch="${${"$(< $gitdir/HEAD)"}[1,7]}..." fi fi fi return 0 } VCS_INFO_git_handle_patches () { local git_applied_s git_unapplied_s gitmsg git_all git_patches_applied=(${(Oa)git_patches_applied}) git_patches_unapplied=(${(Oa)git_patches_unapplied}) (( git_all = ${#git_patches_applied} + ${#git_patches_unapplied} )) if VCS_INFO_hook 'gen-applied-string' "${git_patches_applied[@]}"; then if (( ${#git_patches_applied} )); then git_applied_s=${git_patches_applied[1]} else git_applied_s="" fi else git_applied_s=${hook_com[applied-string]} fi hook_com=() if VCS_INFO_hook 'gen-unapplied-string' "${git_patches_unapplied[@]}"; then git_patches_unapplied=${#git_patches_unapplied} else git_patches_unapplied=${hook_com[unapplied-string]} fi if (( ${#git_patches_applied} )); then zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" patch-format gitmsg || gitmsg="%p (%n applied)" else zstyle -s ":vcs_info:${vcs}:${usercontext}:${rrn}" nopatch-format gitmsg || gitmsg="no patch applied" fi hook_com=( applied "${git_applied_s}" unapplied "${git_patches_unapplied}" applied-n ${#git_patches_applied} unapplied-n ${#git_patches_unapplied} all-n ${git_all} ) if VCS_INFO_hook 'set-patch-format' "${gitmsg}"; then zformat -f gitmisc "${gitmsg}" "p:${hook_com[applied]}" "u:${hook_com[unapplied]}" \ "n:${#git_patches_applied}" "c:${#git_patches_unapplied}" "a:${git_all}" else gitmisc=${hook_com[patch-replace]} fi hook_com=() } gitdir=${vcs_comm[gitdir]} VCS_INFO_git_getbranch ${gitdir} gitbase=$( ${vcs_comm[cmd]} rev-parse --show-toplevel ) rrn=${gitbase:t} if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" get-revision ; then gitsha1=$(${vcs_comm[cmd]} rev-parse --quiet --verify HEAD) else gitsha1='' fi gitbranch="${gitbranch##refs/[^/]##/}" if [[ -z ${gitdir} ]] || [[ -z ${gitbranch} ]] ; then return 1 fi if zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" "check-for-changes" ; then querystaged=1 queryunstaged=1 elif zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" "check-for-staged-changes" ; then querystaged=1 fi if (( querystaged || queryunstaged )) && \ [[ "$(${vcs_comm[cmd]} rev-parse --is-inside-work-tree 2> /dev/null)" == 'true' ]] ; then # Default: off - these are potentially expensive on big repositories if (( queryunstaged )) ; then ${vcs_comm[cmd]} diff --no-ext-diff --ignore-submodules=dirty --quiet --exit-code || gitunstaged=1 fi if (( querystaged )) ; then if ${vcs_comm[cmd]} rev-parse --quiet --verify HEAD &> /dev/null ; then ${vcs_comm[cmd]} diff-index --cached --quiet --ignore-submodules=dirty HEAD 2> /dev/null (( $? && $? != 128 )) && gitstaged=1 else # empty repository (no commits yet) # 4b825dc642cb6eb9a060e54bf8d69288fbee4904 is the git empty tree. ${vcs_comm[cmd]} diff-index --cached --quiet --ignore-submodules=dirty 4b825dc642cb6eb9a060e54bf8d69288fbee4904 2>/dev/null (( $? && $? != 128 )) && gitstaged=1 fi fi fi VCS_INFO_adjust VCS_INFO_git_getaction ${gitdir} local patchdir=${gitdir}/patches/${gitbranch} if [[ -d $patchdir ]] && [[ -f $patchdir/applied ]] \ && [[ -f $patchdir/unapplied ]] then git_patches_applied=(${(f)"$(< "${patchdir}/applied")"}) git_patches_unapplied=(${(f)"$(< "${patchdir}/unapplied")"}) VCS_INFO_git_handle_patches elif [[ -d "${gitdir}/rebase-merge" ]]; then patchdir="${gitdir}/rebase-merge" local p [[ -f "${patchdir}/done" ]] && for p in ${(f)"$(< "${patchdir}/done")"}; do # remove action git_patches_applied+=("${${(s: :)p}[2,-1]}") done git_patches_unapplied=(${(f)"$(grep -v '^$' "${patchdir}/git-rebase-todo" | grep -v '^#')"}) VCS_INFO_git_handle_patches elif [[ -d "${gitdir}/rebase-apply" ]]; then # Fake patch names for all but current patch patchdir="${gitdir}/rebase-apply" local cur=$(< "${patchdir}/next") local p subject for p in $(seq $(($cur - 1))); do git_patches_applied+=("$(printf "%04d" $p) ?") done subject="${$(< "${patchdir}/msg-clean")[(f)1]}" if [[ -f "${patchdir}/original-commit" ]]; then git_patches_applied+=("$(< ${patchdir}/original-commit) $subject") else git_patches_applied+=("? $subject") fi git_patches_unapplied=($(seq $cur $(< "${patchdir}/last"))) VCS_INFO_git_handle_patches else gitmisc='' fi backend_misc[patches]="${gitmisc}" VCS_INFO_formats "${gitaction}" "${gitbranch}" "${gitbase}" "${gitstaged}" "${gitunstaged}" "${gitsha1}" "${gitmisc}" return 0