#!/usr/bin/env bash # -*- coding: utf-8 -*- # gitstatus.sh -- produce the current git repo status on STDOUT # Functionally equivalent to 'gitstatus.py', but written in bash (not python). # # Alan K. Stebbens [http://github.com/aks] if [ -z "${__GIT_PROMPT_DIR}" ]; then SOURCE="${BASH_SOURCE[0]}" while [ -h "${SOURCE}" ]; do DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )" SOURCE="$(readlink "${SOURCE}")" [[ $SOURCE != /* ]] && SOURCE="${DIR}/${SOURCE}" done __GIT_PROMPT_DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )" fi if [[ "${__GIT_PROMPT_IGNORE_SUBMODULES}" == "1" ]]; then _ignore_submodules=--ignore-submodules else _ignore_submodules= fi gitstatus=$( LC_ALL=C git status ${_ignore_submodules} --untracked-files=${__GIT_PROMPT_SHOW_UNTRACKED_FILES:-all} --porcelain --branch ) # if the status is fatal, exit now [[ "$?" -ne 0 ]] && exit 0 git_dir="$(git rev-parse --git-dir 2>/dev/null)" [[ -z "$git_dir" ]] && exit 0 __git_prompt_read () { local f="$1" shift test -r "$f" && read "$@" <"$f" } state="" step="" total="" if [ -d "${git_dir}/rebase-merge" ]; then __git_prompt_read "${git_dir}/rebase-merge/msgnum" step __git_prompt_read "${git_dir}/rebase-merge/end" total if [ -f "${git_dir}/rebase-merge/interactive" ]; then state="|REBASE-i" else state="|REBASE-m" fi else if [ -d "${git_dir}/rebase-apply" ]; then __git_prompt_read "${git_dir}/rebase-apply/next" step __git_prompt_read "${git_dir}/rebase-apply/last" total if [ -f "${git_dir}/rebase-apply/rebasing" ]; then state="|REBASE" elif [ -f "${git_dir}/rebase-apply/applying" ]; then state="|AM" else state="|AM/REBASE" fi elif [ -f "${git_dir}/MERGE_HEAD" ]; then state="|MERGING" elif [ -f "${git_dir}/CHERRY_PICK_HEAD" ]; then state="|CHERRY-PICKING" elif [ -f "${git_dir}/REVERT_HEAD" ]; then state="|REVERTING" elif [ -f "${git_dir}/BISECT_LOG" ]; then state="|BISECTING" fi fi if [ -n "$step" ] && [ -n "$total" ]; then state="${state} ${step}/${total}" fi num_staged=0 num_changed=0 num_conflicts=0 num_untracked=0 while IFS='' read -r line || [[ -n "$line" ]]; do status=${line:0:2} while [[ -n $status ]]; do case "$status" in #two fixed character matches, loop finished \#\#) branch_line="${line/\.\.\./^}"; break ;; \?\?) ((num_untracked++)); break ;; U?) ((num_conflicts++)); break;; ?U) ((num_conflicts++)); break;; DD) ((num_conflicts++)); break;; AA) ((num_conflicts++)); break;; #two character matches, first loop ?M) ((num_changed++)) ;; ?D) ((num_changed++)) ;; ?\ ) ;; #single character matches, second loop U) ((num_conflicts++)) ;; \ ) ;; *) ((num_staged++)) ;; esac status=${status:0:(${#status}-1)} done done <<< "$gitstatus" num_stashed=0 if [[ "$__GIT_PROMPT_IGNORE_STASH" != "1" ]]; then stash_file="$( git rev-parse --git-dir )/logs/refs/stash" if [[ -e "${stash_file}" ]]; then while IFS='' read -r wcline || [[ -n "$wcline" ]]; do ((num_stashed++)) done < ${stash_file} fi fi clean=0 if (( num_changed == 0 && num_staged == 0 && num_untracked == 0 && num_stashed == 0 && num_conflicts == 0)) ; then clean=1 fi IFS="^" read -ra branch_fields <<< "${branch_line/\#\# }" branch="${branch_fields[0]}" remote= upstream= if [[ "$branch" == *"Initial commit on"* ]]; then IFS=" " read -ra fields <<< "$branch" branch="${fields[3]}" remote="_NO_REMOTE_TRACKING_" elif [[ "$branch" == *"No commits yet on"* ]]; then IFS=" " read -ra fields <<< "$branch" branch="${fields[4]}" remote="_NO_REMOTE_TRACKING_" elif [[ "$branch" == *"no branch"* ]]; then tag=$( git describe --tags --exact-match ) if [[ -n "$tag" ]]; then branch="$tag" else branch="_PREHASH_$( git rev-parse --short HEAD )" fi else if [[ "${#branch_fields[@]}" -eq 1 ]]; then remote="_NO_REMOTE_TRACKING_" else IFS="[,]" read -ra remote_fields <<< "${branch_fields[1]}" upstream="${remote_fields[0]}" for remote_field in "${remote_fields[@]}"; do if [[ "$remote_field" == "ahead "* ]]; then num_ahead=${remote_field:6} ahead="_AHEAD_${num_ahead}" fi if [[ "$remote_field" == "behind "* ]] || [[ "$remote_field" == " behind "* ]]; then num_behind=${remote_field:7} behind="_BEHIND_${num_behind# }" fi done remote="${behind}${ahead}" fi fi if [[ -z "$remote" ]] ; then remote='.' fi if [[ -z "$upstream" ]] ; then upstream='^' fi printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n" \ "${branch}${state}" \ "$remote" \ "$upstream" \ $num_staged \ $num_conflicts \ $num_changed \ $num_untracked \ $num_stashed \ $clean exit