Created
March 18, 2021 19:57
-
-
Save jayers99/4a7db93e699ff505679faf522c3d03b2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The git prompt's git commands are read-only and should not interfere with | |
# other processes. This environment variable is equivalent to running with `git | |
# --no-optional-locks`, but falls back gracefully for older versions of git. | |
# See git(1) for and git-status(1) for a description of that flag. | |
# | |
# We wrap in a local function instead of exporting the variable directly in | |
# order to avoid interfering with manually-run git commands by the user. | |
function __git_prompt_git() { | |
GIT_OPTIONAL_LOCKS=0 command git "$@" | |
} | |
function git_prompt_info() { | |
# If we are on a folder not tracked by git, get out. | |
# Otherwise, check for hide-info at global and local repository level | |
if ! __git_prompt_git rev-parse --git-dir &> /dev/null \ | |
|| [[ "$(__git_prompt_git config --get oh-my-zsh.hide-info 2>/dev/null)" == 1 ]]; then | |
return 0 | |
fi | |
local ref | |
ref=$(__git_prompt_git symbolic-ref --short HEAD 2> /dev/null) \ | |
|| ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) \ | |
|| return 0 | |
# Use global ZSH_THEME_GIT_SHOW_UPSTREAM=1 for including upstream remote info | |
local upstream | |
if (( ${+ZSH_THEME_GIT_SHOW_UPSTREAM} )); then | |
upstream=$(__git_prompt_git rev-parse --abbrev-ref --symbolic-full-name "@{upstream}" 2>/dev/null) \ | |
&& upstream=" -> ${upstream}" | |
fi | |
echo "${ZSH_THEME_GIT_PROMPT_PREFIX}${ref}${upstream}$(parse_git_dirty)${ZSH_THEME_GIT_PROMPT_SUFFIX}" | |
} | |
# Checks if working tree is dirty | |
function parse_git_dirty() { | |
local STATUS | |
local -a FLAGS | |
FLAGS=('--porcelain') | |
if [[ "$(__git_prompt_git config --get oh-my-zsh.hide-dirty)" != "1" ]]; then | |
if [[ "${DISABLE_UNTRACKED_FILES_DIRTY:-}" == "true" ]]; then | |
FLAGS+='--untracked-files=no' | |
fi | |
case "${GIT_STATUS_IGNORE_SUBMODULES:-}" in | |
git) | |
# let git decide (this respects per-repo config in .gitmodules) | |
;; | |
*) | |
# if unset: ignore dirty submodules | |
# other values are passed to --ignore-submodules | |
FLAGS+="--ignore-submodules=${GIT_STATUS_IGNORE_SUBMODULES:-dirty}" | |
;; | |
esac | |
STATUS=$(__git_prompt_git status ${FLAGS} 2> /dev/null | tail -1) | |
fi | |
if [[ -n $STATUS ]]; then | |
echo "$ZSH_THEME_GIT_PROMPT_DIRTY" | |
else | |
echo "$ZSH_THEME_GIT_PROMPT_CLEAN" | |
fi | |
} | |
# Gets the difference between the local and remote branches | |
function git_remote_status() { | |
local remote ahead behind git_remote_status git_remote_status_detailed | |
remote=${$(__git_prompt_git rev-parse --verify ${hook_com[branch]}@{upstream} --symbolic-full-name 2>/dev/null)/refs\/remotes\/} | |
if [[ -n ${remote} ]]; then | |
ahead=$(__git_prompt_git rev-list ${hook_com[branch]}@{upstream}..HEAD 2>/dev/null | wc -l) | |
behind=$(__git_prompt_git rev-list HEAD..${hook_com[branch]}@{upstream} 2>/dev/null | wc -l) | |
if [[ $ahead -eq 0 ]] && [[ $behind -eq 0 ]]; then | |
git_remote_status="$ZSH_THEME_GIT_PROMPT_EQUAL_REMOTE" | |
elif [[ $ahead -gt 0 ]] && [[ $behind -eq 0 ]]; then | |
git_remote_status="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE" | |
git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE$((ahead))%{$reset_color%}" | |
elif [[ $behind -gt 0 ]] && [[ $ahead -eq 0 ]]; then | |
git_remote_status="$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE" | |
git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE$((behind))%{$reset_color%}" | |
elif [[ $ahead -gt 0 ]] && [[ $behind -gt 0 ]]; then | |
git_remote_status="$ZSH_THEME_GIT_PROMPT_DIVERGED_REMOTE" | |
git_remote_status_detailed="$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_AHEAD_REMOTE$((ahead))%{$reset_color%}$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE_COLOR$ZSH_THEME_GIT_PROMPT_BEHIND_REMOTE$((behind))%{$reset_color%}" | |
fi | |
if [[ -n $ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_DETAILED ]]; then | |
git_remote_status="$ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_PREFIX$remote$git_remote_status_detailed$ZSH_THEME_GIT_PROMPT_REMOTE_STATUS_SUFFIX" | |
fi | |
echo $git_remote_status | |
fi | |
} | |
# Outputs the name of the current branch | |
# Usage example: git pull origin $(git_current_branch) | |
# Using '--quiet' with 'symbolic-ref' will not cause a fatal error (128) if | |
# it's not a symbolic ref, but in a Git repo. | |
function git_current_branch() { | |
local ref | |
ref=$(__git_prompt_git symbolic-ref --quiet HEAD 2> /dev/null) | |
local ret=$? | |
if [[ $ret != 0 ]]; then | |
[[ $ret == 128 ]] && return # no git repo. | |
ref=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) || return | |
fi | |
echo ${ref#refs/heads/} | |
} | |
# Gets the number of commits ahead from remote | |
function git_commits_ahead() { | |
if __git_prompt_git rev-parse --git-dir &>/dev/null; then | |
local commits="$(__git_prompt_git rev-list --count @{upstream}..HEAD 2>/dev/null)" | |
if [[ -n "$commits" && "$commits" != 0 ]]; then | |
echo "$ZSH_THEME_GIT_COMMITS_AHEAD_PREFIX$commits$ZSH_THEME_GIT_COMMITS_AHEAD_SUFFIX" | |
fi | |
fi | |
} | |
# Gets the number of commits behind remote | |
function git_commits_behind() { | |
if __git_prompt_git rev-parse --git-dir &>/dev/null; then | |
local commits="$(__git_prompt_git rev-list --count HEAD..@{upstream} 2>/dev/null)" | |
if [[ -n "$commits" && "$commits" != 0 ]]; then | |
echo "$ZSH_THEME_GIT_COMMITS_BEHIND_PREFIX$commits$ZSH_THEME_GIT_COMMITS_BEHIND_SUFFIX" | |
fi | |
fi | |
} | |
# Outputs if current branch is ahead of remote | |
function git_prompt_ahead() { | |
if [[ -n "$(__git_prompt_git rev-list origin/$(git_current_branch)..HEAD 2> /dev/null)" ]]; then | |
echo "$ZSH_THEME_GIT_PROMPT_AHEAD" | |
fi | |
} | |
# Outputs if current branch is behind remote | |
function git_prompt_behind() { | |
if [[ -n "$(__git_prompt_git rev-list HEAD..origin/$(git_current_branch) 2> /dev/null)" ]]; then | |
echo "$ZSH_THEME_GIT_PROMPT_BEHIND" | |
fi | |
} | |
# Outputs if current branch exists on remote or not | |
function git_prompt_remote() { | |
if [[ -n "$(__git_prompt_git show-ref origin/$(git_current_branch) 2> /dev/null)" ]]; then | |
echo "$ZSH_THEME_GIT_PROMPT_REMOTE_EXISTS" | |
else | |
echo "$ZSH_THEME_GIT_PROMPT_REMOTE_MISSING" | |
fi | |
} | |
# Formats prompt string for current git commit short SHA | |
function git_prompt_short_sha() { | |
local SHA | |
SHA=$(__git_prompt_git rev-parse --short HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" | |
} | |
# Formats prompt string for current git commit long SHA | |
function git_prompt_long_sha() { | |
local SHA | |
SHA=$(__git_prompt_git rev-parse HEAD 2> /dev/null) && echo "$ZSH_THEME_GIT_PROMPT_SHA_BEFORE$SHA$ZSH_THEME_GIT_PROMPT_SHA_AFTER" | |
} | |
function git_prompt_status() { | |
[[ "$(__git_prompt_git config --get oh-my-zsh.hide-status 2>/dev/null)" = 1 ]] && return | |
# Maps a git status prefix to an internal constant | |
# This cannot use the prompt constants, as they may be empty | |
local -A prefix_constant_map | |
prefix_constant_map=( | |
'\?\? ' 'UNTRACKED' | |
'A ' 'ADDED' | |
'M ' 'ADDED' | |
'MM ' 'MODIFIED' | |
' M ' 'MODIFIED' | |
'AM ' 'MODIFIED' | |
' T ' 'MODIFIED' | |
'R ' 'RENAMED' | |
' D ' 'DELETED' | |
'D ' 'DELETED' | |
'UU ' 'UNMERGED' | |
'ahead' 'AHEAD' | |
'behind' 'BEHIND' | |
'diverged' 'DIVERGED' | |
'stashed' 'STASHED' | |
) | |
# Maps the internal constant to the prompt theme | |
local -A constant_prompt_map | |
constant_prompt_map=( | |
'UNTRACKED' "$ZSH_THEME_GIT_PROMPT_UNTRACKED" | |
'ADDED' "$ZSH_THEME_GIT_PROMPT_ADDED" | |
'MODIFIED' "$ZSH_THEME_GIT_PROMPT_MODIFIED" | |
'RENAMED' "$ZSH_THEME_GIT_PROMPT_RENAMED" | |
'DELETED' "$ZSH_THEME_GIT_PROMPT_DELETED" | |
'UNMERGED' "$ZSH_THEME_GIT_PROMPT_UNMERGED" | |
'AHEAD' "$ZSH_THEME_GIT_PROMPT_AHEAD" | |
'BEHIND' "$ZSH_THEME_GIT_PROMPT_BEHIND" | |
'DIVERGED' "$ZSH_THEME_GIT_PROMPT_DIVERGED" | |
'STASHED' "$ZSH_THEME_GIT_PROMPT_STASHED" | |
) | |
# The order that the prompt displays should be added to the prompt | |
local status_constants | |
status_constants=( | |
UNTRACKED ADDED MODIFIED RENAMED DELETED | |
STASHED UNMERGED AHEAD BEHIND DIVERGED | |
) | |
local status_text="$(__git_prompt_git status --porcelain -b 2> /dev/null)" | |
# Don't continue on a catastrophic failure | |
if [[ $? -eq 128 ]]; then | |
return 1 | |
fi | |
# A lookup table of each git status encountered | |
local -A statuses_seen | |
if __git_prompt_git rev-parse --verify refs/stash &>/dev/null; then | |
statuses_seen[STASHED]=1 | |
fi | |
local status_lines | |
status_lines=("${(@f)${status_text}}") | |
# If the tracking line exists, get and parse it | |
if [[ "$status_lines[1]" =~ "^## [^ ]+ \[(.*)\]" ]]; then | |
local branch_statuses | |
branch_statuses=("${(@s/,/)match}") | |
for branch_status in $branch_statuses; do | |
if [[ ! $branch_status =~ "(behind|diverged|ahead) ([0-9]+)?" ]]; then | |
continue | |
fi | |
local last_parsed_status=$prefix_constant_map[$match[1]] | |
statuses_seen[$last_parsed_status]=$match[2] | |
done | |
fi | |
# For each status prefix, do a regex comparison | |
for status_prefix in ${(k)prefix_constant_map}; do | |
local status_constant="${prefix_constant_map[$status_prefix]}" | |
local status_regex=$'(^|\n)'"$status_prefix" | |
if [[ "$status_text" =~ $status_regex ]]; then | |
statuses_seen[$status_constant]=1 | |
fi | |
done | |
# Display the seen statuses in the order specified | |
local status_prompt | |
for status_constant in $status_constants; do | |
if (( ${+statuses_seen[$status_constant]} )); then | |
local next_display=$constant_prompt_map[$status_constant] | |
status_prompt="$next_display$status_prompt" | |
fi | |
done | |
echo $status_prompt | |
} | |
# Outputs the name of the current user | |
# Usage example: $(git_current_user_name) | |
function git_current_user_name() { | |
__git_prompt_git config user.name 2>/dev/null | |
} | |
# Outputs the email of the current user | |
# Usage example: $(git_current_user_email) | |
function git_current_user_email() { | |
__git_prompt_git config user.email 2>/dev/null | |
} | |
# Output the name of the root directory of the git repository | |
# Usage example: $(git_repo_name) | |
function git_repo_name() { | |
local repo_path | |
if repo_path="$(__git_prompt_git rev-parse --show-toplevel 2>/dev/null)" && [[ -n "$repo_path" ]]; then | |
echo ${repo_path:t} | |
fi | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment