Refactor git functionality into githelpers.theme.bash
- Add unit tests around git functionalitypull/1018/head
parent
2df93544ca
commit
150e82b221
|
|
@ -55,9 +55,11 @@ do
|
||||||
_load_bash_it_files $file_type
|
_load_bash_it_files $file_type
|
||||||
done
|
done
|
||||||
|
|
||||||
# Load colors first so they can be used in base theme
|
# Load colors and helpers first so they can be used in base theme
|
||||||
# shellcheck source=./themes/colors.theme.bash
|
# shellcheck source=./themes/colors.theme.bash
|
||||||
source "${BASH_IT}/themes/colors.theme.bash"
|
source "${BASH_IT}/themes/colors.theme.bash"
|
||||||
|
# shellcheck source=./themes/githelpers.theme.bash
|
||||||
|
source "${BASH_IT}/themes/githelpers.theme.bash"
|
||||||
# shellcheck source=./themes/base.theme.bash
|
# shellcheck source=./themes/base.theme.bash
|
||||||
source "${BASH_IT}/themes/base.theme.bash"
|
source "${BASH_IT}/themes/base.theme.bash"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,371 @@
|
||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
load ../test_helper
|
||||||
|
load ../../lib/composure
|
||||||
|
|
||||||
|
cite _about _param _example _group _author _version
|
||||||
|
|
||||||
|
load ../../lib/helpers
|
||||||
|
load ../../themes/githelpers.theme
|
||||||
|
load ../../themes/base.theme
|
||||||
|
|
||||||
|
add_commit() {
|
||||||
|
local file_name="general-${RANDOM}"
|
||||||
|
touch "${file_name}"
|
||||||
|
echo "" >> "${file_name}"
|
||||||
|
git add "${file_name}"
|
||||||
|
git commit -m"message"
|
||||||
|
}
|
||||||
|
|
||||||
|
enter_new_git_repo() {
|
||||||
|
repo="$(setup_repo)"
|
||||||
|
pushd "${repo}"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_repo() {
|
||||||
|
upstream="$(mktemp -d)"
|
||||||
|
pushd "$upstream" > /dev/null
|
||||||
|
git init . > /dev/null
|
||||||
|
|
||||||
|
echo "$upstream"
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_repo_with_upstream() {
|
||||||
|
upstream="$(setup_repo)"
|
||||||
|
pushd "$upstream" > /dev/null
|
||||||
|
add_commit > /dev/null
|
||||||
|
git checkout -b branch-two
|
||||||
|
git checkout -b gone-branch
|
||||||
|
git checkout master
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
downstream="$(setup_repo)"
|
||||||
|
pushd "$downstream" > /dev/null
|
||||||
|
add_commit > /dev/null
|
||||||
|
git remote add my-remote "$upstream"
|
||||||
|
git fetch my-remote
|
||||||
|
git branch -u my-remote/master > /dev/null
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
pushd "$upstream" > /dev/null
|
||||||
|
git branch -d gone-branch > /dev/null
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
pushd "$downstream" > /dev/null
|
||||||
|
git fetch my-remote
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
echo "$downstream"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: when tracking a remote branch: it shows the commits ahead and behind' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
|
||||||
|
remote="$(setup_repo)"
|
||||||
|
pushd "$remote"
|
||||||
|
add_commit
|
||||||
|
add_commit
|
||||||
|
popd
|
||||||
|
|
||||||
|
clone="$(mktemp -d)"
|
||||||
|
pushd "$clone"
|
||||||
|
git clone "$remote" clone
|
||||||
|
cd clone
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}"
|
||||||
|
|
||||||
|
add_commit
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} ↑1"
|
||||||
|
|
||||||
|
add_commit
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} ↑2"
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd "$remote"
|
||||||
|
add_commit
|
||||||
|
add_commit
|
||||||
|
add_commit
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd "$clone/clone"
|
||||||
|
git fetch
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} ↑2 ↓3"
|
||||||
|
|
||||||
|
git reset HEAD~2 --hard
|
||||||
|
|
||||||
|
SCM_GIT_BEHIND_CHAR="↓"
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} ↓3"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: when stashes exist: it shows the number of stashes' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
|
||||||
|
enter_new_git_repo
|
||||||
|
add_commit
|
||||||
|
|
||||||
|
touch file
|
||||||
|
git add file
|
||||||
|
git stash
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} {1}"
|
||||||
|
|
||||||
|
touch file2
|
||||||
|
git add file2
|
||||||
|
git stash
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} {2}"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: remote info: when there is no upstream remote: is empty' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
post=" ↑1 ↓1"
|
||||||
|
|
||||||
|
enter_new_git_repo
|
||||||
|
add_commit
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: remote info: when SCM_GIT_SHOW_REMOTE_INFO is true: includes the remote' {
|
||||||
|
pre="\$(_git-friendly-ref) → "
|
||||||
|
eval_pre="master → "
|
||||||
|
post=" ↑1 ↓1"
|
||||||
|
|
||||||
|
repo="$(setup_repo_with_upstream)"
|
||||||
|
pushd "${repo}"
|
||||||
|
|
||||||
|
SCM_GIT_SHOW_REMOTE_INFO=true
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}my-remote${post}"
|
||||||
|
|
||||||
|
git branch -u my-remote/branch-two
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}\$(_git-upstream)${post}"
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "${eval_pre}my-remote/branch-two${post}"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: remote info: when SCM_GIT_SHOW_REMOTE_INFO is auto: includes the remote when more than one remote' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
eval_pre="master"
|
||||||
|
post=" ↑1 ↓1"
|
||||||
|
|
||||||
|
repo="$(setup_repo_with_upstream)"
|
||||||
|
pushd "${repo}"
|
||||||
|
|
||||||
|
SCM_GIT_SHOW_REMOTE_INFO=auto
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}${post}"
|
||||||
|
|
||||||
|
pre="${pre} → "
|
||||||
|
eval_pre="${eval_pre} → "
|
||||||
|
git branch -u my-remote/branch-two
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}\$(_git-upstream-branch)${post}"
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "${eval_pre}branch-two${post}"
|
||||||
|
|
||||||
|
git remote add second-remote "$(mktemp -d)"
|
||||||
|
git branch -u my-remote/master
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}my-remote${post}"
|
||||||
|
|
||||||
|
git branch -u my-remote/branch-two
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}\$(_git-upstream)${post}"
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "${eval_pre}my-remote/branch-two${post}"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: remote info: when SCM_GIT_SHOW_REMOTE_INFO is false: never include the remote' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
eval_pre="master"
|
||||||
|
post=" ↑1 ↓1"
|
||||||
|
|
||||||
|
repo="$(setup_repo_with_upstream)"
|
||||||
|
pushd "${repo}"
|
||||||
|
git remote add second-remote "$(mktemp -d)"
|
||||||
|
git remote add third-remote "$(mktemp -d)"
|
||||||
|
|
||||||
|
SCM_GIT_SHOW_REMOTE_INFO=false
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}${post}"
|
||||||
|
|
||||||
|
pre="${pre} → "
|
||||||
|
eval_pre="${eval_pre} → "
|
||||||
|
git branch -u my-remote/branch-two
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}\$(_git-upstream-branch)${post}"
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "${eval_pre}branch-two${post}"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: remote info: when showing remote info: show if upstream branch is gone' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
post=" ↑1 ↓1"
|
||||||
|
|
||||||
|
repo="$(setup_repo_with_upstream)"
|
||||||
|
pushd "${repo}"
|
||||||
|
|
||||||
|
SCM_GIT_SHOW_REMOTE_INFO=true
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} → my-remote${post}"
|
||||||
|
|
||||||
|
git checkout gone-branch
|
||||||
|
git fetch --prune --all
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} ⇢ my-remote"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git friendly ref: when a branch is checked out: shows that branch' {
|
||||||
|
enter_new_git_repo
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "master"
|
||||||
|
|
||||||
|
git checkout -b second-branch
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "second-branch"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git friendly ref: when a branch is not checked out: shows that branch' {
|
||||||
|
enter_new_git_repo
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "master"
|
||||||
|
|
||||||
|
git checkout -b second-branch
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "second-branch"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git friendly ref: when detached: commit has branch and tag: show a tag' {
|
||||||
|
enter_new_git_repo
|
||||||
|
add_commit
|
||||||
|
git tag first-tag
|
||||||
|
git checkout -b second-branch
|
||||||
|
add_commit
|
||||||
|
git checkout HEAD~1
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "tag:first-tag"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git friendly ref: when detached: commit has branch and no tag: show a branch' {
|
||||||
|
enter_new_git_repo
|
||||||
|
add_commit
|
||||||
|
git checkout -b second-branch
|
||||||
|
add_commit
|
||||||
|
git checkout HEAD~1
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "detached:master"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git friendly ref: when detached with no branch or tag: commit is parent to a named ref: show relative name' {
|
||||||
|
enter_new_git_repo
|
||||||
|
add_commit
|
||||||
|
add_commit
|
||||||
|
git checkout HEAD~1
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "detached:master~1"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git friendly ref: when detached with no branch or tag: commit is not parent to a named ref: show short sha' {
|
||||||
|
enter_new_git_repo
|
||||||
|
add_commit
|
||||||
|
add_commit
|
||||||
|
sha="$(git rev-parse --short HEAD)"
|
||||||
|
git reset --hard HEAD~1
|
||||||
|
git checkout "$sha"
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$(eval "echo \"$SCM_BRANCH\"")" "detached:$sha"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git friendly ref: shows staged, unstaged, and untracked file counts' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
|
||||||
|
enter_new_git_repo
|
||||||
|
echo "line1" > file1
|
||||||
|
echo "line1" > file2
|
||||||
|
echo "line1" > file3
|
||||||
|
echo "line1" > file4
|
||||||
|
git add .
|
||||||
|
git commit -m"commit1"
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_STATE" " ✓"
|
||||||
|
|
||||||
|
echo "line2" >> file1
|
||||||
|
git add file1
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} S:1"
|
||||||
|
assert_equal "$SCM_STATE" " ✗"
|
||||||
|
assert_equal "$SCM_DIRTY" "3"
|
||||||
|
|
||||||
|
echo "line2" >> file2
|
||||||
|
echo "line2" >> file3
|
||||||
|
echo "line2" >> file4
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} S:1 U:3"
|
||||||
|
assert_equal "$SCM_DIRTY" "2"
|
||||||
|
|
||||||
|
echo "line1" > newfile5
|
||||||
|
echo "line1" > newfile6
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} S:1 U:3 ?:2"
|
||||||
|
assert_equal "$SCM_DIRTY" "1"
|
||||||
|
|
||||||
|
git config bash-it.hide-status 1
|
||||||
|
|
||||||
|
SCM_DIRTY='nope'
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}"
|
||||||
|
assert_equal "$SCM_DIRTY" "nope"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test 'themes base: Git: git user info: shows user initials' {
|
||||||
|
pre="\$(_git-friendly-ref)"
|
||||||
|
|
||||||
|
enter_new_git_repo
|
||||||
|
git config user.name "Cool User"
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre}"
|
||||||
|
|
||||||
|
SCM_GIT_SHOW_CURRENT_USER=true
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} ☺︎ cu"
|
||||||
|
|
||||||
|
# show initials set by `git pair`
|
||||||
|
|
||||||
|
git config user.initials "ab cd"
|
||||||
|
|
||||||
|
git_prompt_vars
|
||||||
|
assert_equal "$SCM_BRANCH" "${pre} ☺︎ ab+cd"
|
||||||
|
}
|
||||||
|
|
@ -129,32 +129,14 @@ function scm_prompt_info_common {
|
||||||
[[ ${SCM} == ${SCM_SVN} ]] && svn_prompt_info && return
|
[[ ${SCM} == ${SCM_SVN} ]] && svn_prompt_info && return
|
||||||
}
|
}
|
||||||
|
|
||||||
# This is added to address bash shell interpolation vulnerability described
|
|
||||||
# here: https://github.com/njhartwell/pw3nage
|
|
||||||
function git_clean_branch {
|
|
||||||
local unsafe_ref=$(command git symbolic-ref -q HEAD 2> /dev/null)
|
|
||||||
local stripped_ref=${unsafe_ref##refs/heads/}
|
|
||||||
local clean_ref=${stripped_ref//[^a-zA-Z0-9\/]/-}
|
|
||||||
echo $clean_ref
|
|
||||||
}
|
|
||||||
|
|
||||||
function git_prompt_minimal_info {
|
function git_prompt_minimal_info {
|
||||||
local ref
|
|
||||||
local status
|
|
||||||
local git_status_flags=('--porcelain')
|
|
||||||
SCM_STATE=${SCM_THEME_PROMPT_CLEAN}
|
SCM_STATE=${SCM_THEME_PROMPT_CLEAN}
|
||||||
|
|
||||||
if [[ "$(command git config --get bash-it.hide-status)" != "1" ]]; then
|
_git-hide-status && return
|
||||||
# Get the branch reference
|
|
||||||
ref=$(git_clean_branch) || \
|
|
||||||
ref=$(command git rev-parse --short HEAD 2> /dev/null) || return 0
|
|
||||||
SCM_BRANCH=${SCM_THEME_BRANCH_PREFIX}${ref}
|
|
||||||
|
|
||||||
# Get the status
|
SCM_BRANCH="${SCM_THEME_BRANCH_PREFIX}\$(_git-friendly-ref)"
|
||||||
[[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && git_status_flags+='-untracked-files=no'
|
|
||||||
status=$(command git status ${git_status_flags} 2> /dev/null | tail -n1)
|
|
||||||
|
|
||||||
if [[ -n ${status} ]]; then
|
if [[ -n "$(_git-status | tail -n1)" ]]; then
|
||||||
SCM_DIRTY=1
|
SCM_DIRTY=1
|
||||||
SCM_STATE=${SCM_THEME_PROMPT_DIRTY}
|
SCM_STATE=${SCM_THEME_PROMPT_DIRTY}
|
||||||
fi
|
fi
|
||||||
|
|
@ -163,122 +145,52 @@ function git_prompt_minimal_info {
|
||||||
SCM_PREFIX=${SCM_THEME_PROMPT_PREFIX}
|
SCM_PREFIX=${SCM_THEME_PROMPT_PREFIX}
|
||||||
SCM_SUFFIX=${SCM_THEME_PROMPT_SUFFIX}
|
SCM_SUFFIX=${SCM_THEME_PROMPT_SUFFIX}
|
||||||
echo -e "${SCM_PREFIX}${SCM_BRANCH}${SCM_STATE}${SCM_SUFFIX}"
|
echo -e "${SCM_PREFIX}${SCM_BRANCH}${SCM_STATE}${SCM_SUFFIX}"
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function git_status_summary {
|
|
||||||
awk '
|
|
||||||
BEGIN {
|
|
||||||
untracked=0;
|
|
||||||
unstaged=0;
|
|
||||||
staged=0;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
if (!after_first && $0 ~ /^##.+/) {
|
|
||||||
print $0
|
|
||||||
seen_header = 1
|
|
||||||
} else if ($0 ~ /^\?\? .+/) {
|
|
||||||
untracked += 1
|
|
||||||
} else {
|
|
||||||
if ($0 ~ /^.[^ ] .+/) {
|
|
||||||
unstaged += 1
|
|
||||||
}
|
|
||||||
if ($0 ~ /^[^ ]. .+/) {
|
|
||||||
staged += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
after_first = 1
|
|
||||||
}
|
|
||||||
END {
|
|
||||||
if (!seen_header) {
|
|
||||||
print
|
|
||||||
}
|
|
||||||
print untracked "\t" unstaged "\t" staged
|
|
||||||
}'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function git_prompt_vars {
|
function git_prompt_vars {
|
||||||
local details=''
|
if _git-branch &> /dev/null; then
|
||||||
|
SCM_GIT_DETACHED="false"
|
||||||
|
SCM_BRANCH="${SCM_THEME_BRANCH_PREFIX}\$(_git-friendly-ref)$(_git-remote-info)"
|
||||||
|
else
|
||||||
|
SCM_GIT_DETACHED="true"
|
||||||
|
|
||||||
|
local detached_prefix
|
||||||
|
if _git-tag &> /dev/null; then
|
||||||
|
detached_prefix=${SCM_THEME_TAG_PREFIX}
|
||||||
|
else
|
||||||
|
detached_prefix=${SCM_THEME_DETACHED_PREFIX}
|
||||||
|
fi
|
||||||
|
SCM_BRANCH="${detached_prefix}\$(_git-friendly-ref)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS=$'\t' read -r commits_behind commits_ahead <<< "$(_git-upstream-behind-ahead)"
|
||||||
|
[[ "${commits_ahead}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_AHEAD_CHAR}${commits_ahead}"
|
||||||
|
[[ "${commits_behind}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_BEHIND_CHAR}${commits_behind}"
|
||||||
|
|
||||||
|
local stash_count
|
||||||
|
stash_count="$(git stash list 2> /dev/null | wc -l | tr -d ' ')"
|
||||||
|
[[ "${stash_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_STASH_CHAR_PREFIX}${stash_count}${SCM_GIT_STASH_CHAR_SUFFIX}"
|
||||||
|
|
||||||
SCM_STATE=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN}
|
SCM_STATE=${GIT_THEME_PROMPT_CLEAN:-$SCM_THEME_PROMPT_CLEAN}
|
||||||
if [[ "$(git config --get bash-it.hide-status)" != "1" ]]; then
|
if ! _git-hide-status; then
|
||||||
[[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && local git_status_flags='-uno'
|
IFS=$'\t' read -r untracked_count unstaged_count staged_count <<< "$(_git-status-counts)"
|
||||||
local status_lines=$((git status --porcelain ${git_status_flags} -b 2> /dev/null ||
|
|
||||||
git status --porcelain ${git_status_flags} 2> /dev/null) | git_status_summary)
|
|
||||||
local status=$(awk 'NR==1' <<< "$status_lines")
|
|
||||||
local counts=$(awk 'NR==2' <<< "$status_lines")
|
|
||||||
IFS=$'\t' read untracked_count unstaged_count staged_count <<< "$counts"
|
|
||||||
if [[ "${untracked_count}" -gt 0 || "${unstaged_count}" -gt 0 || "${staged_count}" -gt 0 ]]; then
|
if [[ "${untracked_count}" -gt 0 || "${unstaged_count}" -gt 0 || "${staged_count}" -gt 0 ]]; then
|
||||||
SCM_DIRTY=1
|
SCM_DIRTY=1
|
||||||
if [[ "${SCM_GIT_SHOW_DETAILS}" = "true" ]]; then
|
if [[ "${SCM_GIT_SHOW_DETAILS}" = "true" ]]; then
|
||||||
[[ "${staged_count}" -gt 0 ]] && details+=" ${SCM_GIT_STAGED_CHAR}${staged_count}" && SCM_DIRTY=3
|
[[ "${staged_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_STAGED_CHAR}${staged_count}" && SCM_DIRTY=3
|
||||||
[[ "${unstaged_count}" -gt 0 ]] && details+=" ${SCM_GIT_UNSTAGED_CHAR}${unstaged_count}" && SCM_DIRTY=2
|
[[ "${unstaged_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_UNSTAGED_CHAR}${unstaged_count}" && SCM_DIRTY=2
|
||||||
[[ "${untracked_count}" -gt 0 ]] && details+=" ${SCM_GIT_UNTRACKED_CHAR}${untracked_count}" && SCM_DIRTY=1
|
[[ "${untracked_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_UNTRACKED_CHAR}${untracked_count}" && SCM_DIRTY=1
|
||||||
fi
|
fi
|
||||||
SCM_STATE=${GIT_THEME_PROMPT_DIRTY:-$SCM_THEME_PROMPT_DIRTY}
|
SCM_STATE=${GIT_THEME_PROMPT_DIRTY:-$SCM_THEME_PROMPT_DIRTY}
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ "${SCM_GIT_SHOW_CURRENT_USER}" == "true" ]] && details+="$(git_user_info)"
|
[[ "${SCM_GIT_SHOW_CURRENT_USER}" == "true" ]] && SCM_BRANCH+="$(git_user_info)"
|
||||||
|
|
||||||
SCM_CHANGE=$(git rev-parse --short HEAD 2>/dev/null)
|
|
||||||
|
|
||||||
local ref=$(git_clean_branch)
|
|
||||||
|
|
||||||
if [[ -n "$ref" ]]; then
|
|
||||||
SCM_BRANCH="${SCM_THEME_BRANCH_PREFIX}${ref}"
|
|
||||||
local tracking_info="$(grep -- "${SCM_BRANCH}\.\.\." <<< "${status}")"
|
|
||||||
if [[ -n "${tracking_info}" ]]; then
|
|
||||||
[[ "${tracking_info}" =~ .+\[gone\]$ ]] && local branch_gone="true"
|
|
||||||
tracking_info=${tracking_info#\#\# ${SCM_BRANCH}...}
|
|
||||||
tracking_info=${tracking_info% [*}
|
|
||||||
local remote_name=${tracking_info%%/*}
|
|
||||||
local remote_branch=${tracking_info#${remote_name}/}
|
|
||||||
local remote_info=""
|
|
||||||
local num_remotes=$(git remote | wc -l 2> /dev/null)
|
|
||||||
[[ "${SCM_BRANCH}" = "${remote_branch}" ]] && local same_branch_name=true
|
|
||||||
if ([[ "${SCM_GIT_SHOW_REMOTE_INFO}" = "auto" ]] && [[ "${num_remotes}" -ge 2 ]]) ||
|
|
||||||
[[ "${SCM_GIT_SHOW_REMOTE_INFO}" = "true" ]]; then
|
|
||||||
remote_info="${remote_name}"
|
|
||||||
[[ "${same_branch_name}" != "true" ]] && remote_info+="/${remote_branch}"
|
|
||||||
elif [[ ${same_branch_name} != "true" ]]; then
|
|
||||||
remote_info="${remote_branch}"
|
|
||||||
fi
|
|
||||||
if [[ -n "${remote_info}" ]];then
|
|
||||||
if [[ "${branch_gone}" = "true" ]]; then
|
|
||||||
SCM_BRANCH+="${SCM_THEME_BRANCH_GONE_PREFIX}${remote_info}"
|
|
||||||
else
|
|
||||||
SCM_BRANCH+="${SCM_THEME_BRANCH_TRACK_PREFIX}${remote_info}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
SCM_GIT_DETACHED="false"
|
|
||||||
else
|
|
||||||
local detached_prefix=""
|
|
||||||
ref=$(git describe --tags --exact-match 2> /dev/null)
|
|
||||||
if [[ -n "$ref" ]]; then
|
|
||||||
detached_prefix=${SCM_THEME_TAG_PREFIX}
|
|
||||||
else
|
|
||||||
ref=$(git describe --contains --all HEAD 2> /dev/null)
|
|
||||||
ref=${ref#remotes/}
|
|
||||||
[[ -z "$ref" ]] && ref=${SCM_CHANGE}
|
|
||||||
detached_prefix=${SCM_THEME_DETACHED_PREFIX}
|
|
||||||
fi
|
|
||||||
SCM_BRANCH=${detached_prefix}${ref}
|
|
||||||
SCM_GIT_DETACHED="true"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local ahead_re='.+ahead ([0-9]+).+'
|
|
||||||
local behind_re='.+behind ([0-9]+).+'
|
|
||||||
[[ "${status}" =~ ${ahead_re} ]] && SCM_BRANCH+=" ${SCM_GIT_AHEAD_CHAR}${BASH_REMATCH[1]}"
|
|
||||||
[[ "${status}" =~ ${behind_re} ]] && SCM_BRANCH+=" ${SCM_GIT_BEHIND_CHAR}${BASH_REMATCH[1]}"
|
|
||||||
|
|
||||||
local stash_count="$(git stash list 2> /dev/null | wc -l | tr -d ' ')"
|
|
||||||
[[ "${stash_count}" -gt 0 ]] && SCM_BRANCH+=" ${SCM_GIT_STASH_CHAR_PREFIX}${stash_count}${SCM_GIT_STASH_CHAR_SUFFIX}"
|
|
||||||
|
|
||||||
SCM_BRANCH+=${details}
|
|
||||||
|
|
||||||
SCM_PREFIX=${GIT_THEME_PROMPT_PREFIX:-$SCM_THEME_PROMPT_PREFIX}
|
SCM_PREFIX=${GIT_THEME_PROMPT_PREFIX:-$SCM_THEME_PROMPT_PREFIX}
|
||||||
SCM_SUFFIX=${GIT_THEME_PROMPT_SUFFIX:-$SCM_THEME_PROMPT_SUFFIX}
|
SCM_SUFFIX=${GIT_THEME_PROMPT_SUFFIX:-$SCM_THEME_PROMPT_SUFFIX}
|
||||||
|
|
||||||
|
SCM_CHANGE=$(_git-short-sha 2>/dev/null || echo "")
|
||||||
}
|
}
|
||||||
|
|
||||||
function svn_prompt_vars {
|
function svn_prompt_vars {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,157 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
function _git-symbolic-ref {
|
||||||
|
git symbolic-ref -q HEAD 2> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# When on a branch, this is often the same as _git-commit-description,
|
||||||
|
# but this can be different when two branches are pointing to the
|
||||||
|
# same commit. _git-branch is used to explicitly choose the checked-out
|
||||||
|
# branch.
|
||||||
|
function _git-branch {
|
||||||
|
git symbolic-ref -q --short HEAD 2> /dev/null || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-tag {
|
||||||
|
git describe --tags --exact-match 2> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-commit-description {
|
||||||
|
git describe --contains --all 2> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-short-sha {
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
}
|
||||||
|
|
||||||
|
# Try the checked-out branch first to avoid collision with branches pointing to the same ref.
|
||||||
|
function _git-friendly-ref {
|
||||||
|
_git-branch || _git-tag || _git-commit-description || _git-short-sha
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-num-remotes {
|
||||||
|
git remote | wc -l
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-upstream {
|
||||||
|
local ref
|
||||||
|
ref="$(_git-symbolic-ref)" || return 1
|
||||||
|
git for-each-ref --format="%(upstream:short)" "${ref}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-upstream-remote {
|
||||||
|
local upstream
|
||||||
|
upstream="$(_git-upstream)" || return 1
|
||||||
|
|
||||||
|
local branch
|
||||||
|
branch="$(_git-upstream-branch)" || return 1
|
||||||
|
echo "${upstream%"/${branch}"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-upstream-branch {
|
||||||
|
local ref
|
||||||
|
ref="$(_git-symbolic-ref)" || return 1
|
||||||
|
|
||||||
|
# git versions < 2.13.0 do not support "strip" for upstream format
|
||||||
|
# regex replacement gives the wrong result for any remotes with slashes in the name,
|
||||||
|
# so only use when the strip format fails.
|
||||||
|
git for-each-ref --format="%(upstream:strip=3)" "${ref}" 2> /dev/null || git for-each-ref --format="%(upstream)" "${ref}" | sed -e "s/.*\/.*\/.*\///"
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-upstream-behind-ahead {
|
||||||
|
git rev-list --left-right --count "$(_git-upstream)...HEAD" 2> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-upstream-branch-gone {
|
||||||
|
[[ "$(git status -s -b | sed -e 's/.* //')" == "[gone]" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-hide-status {
|
||||||
|
[[ "$(git config --get bash-it.hide-status)" == "1" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-status {
|
||||||
|
[[ "${SCM_GIT_IGNORE_UNTRACKED}" = "true" ]] && local git_status_flags='-uno'
|
||||||
|
git status --porcelain ${git_status_flags} 2> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-status-counts {
|
||||||
|
_git-status | awk '
|
||||||
|
BEGIN {
|
||||||
|
untracked=0;
|
||||||
|
unstaged=0;
|
||||||
|
staged=0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if ($0 ~ /^\?\? .+/) {
|
||||||
|
untracked += 1
|
||||||
|
} else {
|
||||||
|
if ($0 ~ /^.[^ ] .+/) {
|
||||||
|
unstaged += 1
|
||||||
|
}
|
||||||
|
if ($0 ~ /^[^ ]. .+/) {
|
||||||
|
staged += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
print untracked "\t" unstaged "\t" staged
|
||||||
|
}'
|
||||||
|
}
|
||||||
|
|
||||||
|
function _git-remote-info {
|
||||||
|
[[ "$(_git-upstream)" == "" ]] && return
|
||||||
|
|
||||||
|
[[ "$(_git-branch)" == "$(_git-upstream-branch)" ]] && local same_branch_name=true
|
||||||
|
if ([[ "${SCM_GIT_SHOW_REMOTE_INFO}" = "auto" ]] && [[ "$(_git-num-remotes)" -ge 2 ]]) ||
|
||||||
|
[[ "${SCM_GIT_SHOW_REMOTE_INFO}" = "true" ]]; then
|
||||||
|
if [[ "${same_branch_name}" != "true" ]]; then
|
||||||
|
remote_info="\$(_git-upstream)"
|
||||||
|
else
|
||||||
|
remote_info="$(_git-upstream-remote)"
|
||||||
|
fi
|
||||||
|
elif [[ ${same_branch_name} != "true" ]]; then
|
||||||
|
remote_info="\$(_git-upstream-branch)"
|
||||||
|
fi
|
||||||
|
if [[ -n "${remote_info}" ]];then
|
||||||
|
local branch_prefix
|
||||||
|
if _git-upstream-branch-gone; then
|
||||||
|
branch_prefix="${SCM_THEME_BRANCH_GONE_PREFIX}"
|
||||||
|
else
|
||||||
|
branch_prefix="${SCM_THEME_BRANCH_TRACK_PREFIX}"
|
||||||
|
fi
|
||||||
|
echo "${branch_prefix}${remote_info}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Unused by bash-it, present for API compatibility
|
||||||
|
function git_status_summary {
|
||||||
|
awk '
|
||||||
|
BEGIN {
|
||||||
|
untracked=0;
|
||||||
|
unstaged=0;
|
||||||
|
staged=0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if (!after_first && $0 ~ /^##.+/) {
|
||||||
|
print $0
|
||||||
|
seen_header = 1
|
||||||
|
} else if ($0 ~ /^\?\? .+/) {
|
||||||
|
untracked += 1
|
||||||
|
} else {
|
||||||
|
if ($0 ~ /^.[^ ] .+/) {
|
||||||
|
unstaged += 1
|
||||||
|
}
|
||||||
|
if ($0 ~ /^[^ ]. .+/) {
|
||||||
|
staged += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
after_first = 1
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
if (!seen_header) {
|
||||||
|
print
|
||||||
|
}
|
||||||
|
print untracked "\t" unstaged "\t" staged
|
||||||
|
}'
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue