dot_git="" cwd="" remote="" in_current_dir() { local wd="$(pwd)" if [[ "$wd" == $cwd ]]; then cwd="$wd" return 0 else cwd="$wd" return 1 fi } debug_print() { local debug=$1 local message=$2 if [[ $debug == "debug" ]]; then echo $message fi } dot_git() { if in_current_dir && [[ -n "$dot_git" ]]; then # cache dot_git to save calls to rev-parse echo $dot_git elif [ -d .git ]; then dot_git=".git" echo $dot_git else dot_git="$(git rev-parse --git-dir 2>/dev/null)" echo $dot_git fi } is_repo() { if [[ -n "$(dot_git)" ]]; then return 0 else return 1 fi } git_root() { if [ -d .git ]; then echo "$(pwd)" else echo "$(git rev-parse --show-toplevel 2>/dev/null)" fi } record_timestamp() { if is_repo; then touch "$(dot_git)/lastupdatetime" fi } timestamp() { if is_repo; then echo "$(stat -f%m "$(dot_git)/lastupdatetime")" fi } time_now() { echo "$(date +%s)" } time_to_update() { if is_repo; then local timesincelastupdate="$(($(time_now) - $(timestamp)))" local fiveminutes="$((5 * 60))" if (( "$timesincelastupdate" > "$5minutes" )); then # time to update return 0 (which is true) return 0 else # not time to update return 1 (which is false) return 1 fi else return 1 fi } fetch_async() { local debug="$1" if time_to_update; then debug_print $debug "Starting fetch" fetch $debug & else debug_print $debug "Didn't fetch" fi } fetch() { local debug="$1" git fetch debug_print $debug "Finished fetch" } commit_short_sha() { if is_repo; then echo "$(git rev-parse --short HEAD)" fi } branch_name() { if is_repo; then name="$(git symbolic-ref --short HEAD 2>/dev/null)" retcode="$?" if [[ "$retcode" == "0" ]]; then echo "$name" else return 1 fi fi } branch_ref() { if is_repo; then echo "$(branch_name || commit_short_sha)" fi } readable_branch_name() { if is_repo; then echo "$(branch_name || echo "detached@$(commit_short_sha)")" fi } is_tracking_remote() { if [[ -n "$(remote_branch_name)" ]]; then return 0 else return 1 fi } remote_branch_name() { if is_repo; then local remoteBranch="$(git for-each-ref --format='%(upstream:short)' refs/heads | grep "$(branch_name)")" if [[ -n $remoteBranch ]]; then echo $remoteBranch return 0 else return 1 fi fi } commits_behind_of_remote() { if is_tracking_remote; then set -- set -- $(git rev-list --left-right --count $(remote_branch_name)...HEAD) behind=$1 ahead=$2 set -- echo $behind else echo "0" fi } commits_ahead_of_remote() { if is_tracking_remote; then set -- set -- $(git rev-list --left-right --count $(remote_branch_name)...HEAD) behind=$1 ahead=$2 set -- echo $ahead else echo "0" fi } remote_behind_of_master() { if is_tracking_remote; then set -- set -- $(git rev-list --left-right --count origin/master...$(remote_branch_name)) behind=$1 ahead=$2 set -- echo $behind else echo "0" fi } remote_ahead_of_master() { if is_tracking_remote; then set -- set -- $(git rev-list --left-right --count origin/master...$(remote_branch_name)) behind=$1 ahead=$2 set -- echo $ahead else echo "0" fi } porcelain_status() { echo "$(git status --porcelain 2>/dev/null)" } count_from_porcelain() { if is_repo; then current_status="$(porcelain_status)" pattern="$1" echo "$(echo "$current_status" | grep -p "$pattern" | wc -l | grep -oEi '[0-9][0-9]*')" else echo "0" fi } untracked_files() { echo "$(count_from_porcelain "?? ")" } staged_added_changes() { echo "$(count_from_porcelain "A[A|M|C|D|U|R ] ")" } staged_modified_changes() { echo "$(count_from_porcelain "M[A|M|C|D|U|R ] ")" } staged_deleted_changes() { echo "$(count_from_porcelain "D[A|M|C|D|U|R ] ")" } staged_renamed_changes() { echo "$(count_from_porcelain "R[A|M|C|D|U|R ] ")" } unstaged_modified_changes() { echo "$(count_from_porcelain "[A|M|C|D|U|R ]M ")" } unstaged_deleted_changes() { echo "$(count_from_porcelain "[A|M|C|D|U|R ]D ")" } conflicted_by_us_changes() { echo "$(count_from_porcelain "[A|M|C|D|R ]U ")" } conflicted_by_them_changes() { echo "$(count_from_porcelain "U[A|M|C|D|R ] ")" } conflicted_both_changes() { echo "$(count_from_porcelain "UU ")" }