gitstatus_pre-1.7.10.sh 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #!/usr/bin/env bash
  2. # -*- coding: UTF-8 -*-
  3. # gitstatus.sh -- produce the current git repo status on STDOUT
  4. # Functionally equivalent to 'gitstatus.py', but written in bash (not python).
  5. #
  6. # Alan K. Stebbens <aks@stebbens.org> [http://github.com/aks]
  7. # helper functions
  8. count_lines() { echo "${1}" | egrep -c "^${2}" ; }
  9. all_lines() { echo "${1}" | grep -v "^$" | wc -l ; }
  10. if [[ -z "${__GIT_PROMPT_DIR-}" ]]; then
  11. SOURCE="${BASH_SOURCE[0]}"
  12. while [[ -h "${SOURCE}" ]]; do
  13. DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
  14. SOURCE="$(readlink "${SOURCE}")"
  15. [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}"
  16. done
  17. __GIT_PROMPT_DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )"
  18. fi
  19. if [[ "${__GIT_PROMPT_WITH_USERNAME_AND_REPO}" == "1" ]]; then
  20. # returns "user/repo" from remote.origin.url git variable
  21. #
  22. # supports urls:
  23. # https://user@bitbucket.org/user/repo.git
  24. # https://github.com/user/repo.git
  25. # git@github.com:user/repo.git
  26. #
  27. remote_url=$(git config --get remote.origin.url | sed 's|^.*//||; s/.*@//; s/[^:/]\+[:/]//; s/.git$//')
  28. else
  29. remote_url='.'
  30. fi
  31. gitsym=$( git symbolic-ref HEAD 2>/dev/null )
  32. #If exit status OK, we have a branch
  33. if [[ "${?}" == 0 ]]; then
  34. # the current branch is the tail end of the symbolic reference
  35. branch="${gitsym##refs/heads/}" # get the basename after "refs/heads/"
  36. fi
  37. gitstatus=$( git diff --name-status 2>&1 )
  38. # if the diff is fatal, exit now
  39. if [[ "${?}" != 0 ]]; then exit 0; fi
  40. staged_files=$( git diff --staged --name-status )
  41. num_changed=$(( $( all_lines "${gitstatus}" ) - $( count_lines "${gitstatus}" U ) ))
  42. num_conflicts=$( count_lines "${staged_files}" U )
  43. num_staged=$(( $( all_lines "${staged_files}" ) - num_conflicts ))
  44. num_untracked=$( git ls-files --others --exclude-standard $(git rev-parse --show-cdup) | wc -l )
  45. num_stashed=0
  46. if [[ "${__GIT_PROMPT_IGNORE_STASH}" != "1" ]]; then
  47. stash_file="$( git rev-parse --git-dir )/logs/refs/stash"
  48. if [[ -e "${stash_file}" ]]; then
  49. while IFS='' read -r wcline || [[ -n "${wcline}" ]]; do
  50. ((num_stashed++))
  51. done < "${stash_file}"
  52. fi
  53. fi
  54. clean=0
  55. if (( num_changed == 0 && num_staged == 0 && num_untracked == 0 && num_stashed == 0 && num_conflicts == 0 )) ; then
  56. clean=1
  57. fi
  58. remote=""
  59. upstream=""
  60. if [[ -z "${branch-}" ]]; then
  61. tag=$( git describe --tags --exact-match 2>/dev/null )
  62. if [[ -n "${tag}" ]]; then
  63. branch="${tag}"
  64. else
  65. branch="_PREHASH_$( git rev-parse --short HEAD )"
  66. fi
  67. else
  68. remote_name=$( git config "branch.${branch}.remote" )
  69. if [[ -n "$remote_name" ]]; then
  70. merge_name=$( git config "branch.${branch}.merge" )
  71. else
  72. remote_name='origin'
  73. merge_name="refs/heads/${branch}"
  74. fi
  75. if [[ "${remote_name}" == '.' ]]; then
  76. remote_ref="${merge_name}"
  77. else
  78. remote_ref="refs/remotes/${remote_name}/${merge_name##refs/heads/}"
  79. fi
  80. # detect if the local branch have a remote tracking branch
  81. upstream=$( git rev-parse --abbrev-ref "${branch}"@{upstream} 2>&1 )
  82. if [[ "${?}" == 0 ]]; then
  83. # get the revision list, and count the leading "<" and ">"
  84. revgit=$( git rev-list --left-right "${remote_ref}...HEAD" 2>/dev/null )
  85. if [[ "${?}" == 0 ]]; then
  86. num_revs=$( all_lines "${revgit}" )
  87. num_ahead=$( count_lines "${revgit}" "^>" )
  88. num_behind=$(( num_revs - num_ahead ))
  89. if (( num_behind > 0 )) ; then
  90. remote="${remote}_BEHIND_${num_behind}"
  91. fi
  92. if (( num_ahead > 0 )) ; then
  93. remote="${remote}_AHEAD_${num_ahead}"
  94. fi
  95. fi
  96. else
  97. remote='_NO_REMOTE_TRACKING_'
  98. remote_url='.'
  99. unset upstream
  100. fi
  101. fi
  102. if [[ -z "${remote:+x}" ]] ; then
  103. remote='.'
  104. fi
  105. if [[ -z "${upstream:+x}" ]] ; then
  106. upstream='^'
  107. fi
  108. printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n" \
  109. "${branch}" \
  110. "${remote}" \
  111. "${remote_url}" \
  112. "${upstream}" \
  113. "${num_staged}" \
  114. "${num_conflicts}" \
  115. "${num_changed}" \
  116. "${num_untracked// /}" \
  117. "${num_stashed}" \
  118. "${clean}"
  119. exit