├── .gitignore ├── .old ├── demo-more-script └── git-demo ├── Makefile ├── README ├── demo-script ├── git-prompt.conf ├── git-prompt.sh ├── index.txt ├── screenshot-labels.png ├── screenshot-labels.xcf ├── screenshot-prompt-basic.png ├── screenshot-prompt-git.png └── screenshot-svn.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | 3 | # emacs backup and lock files 4 | *~ 5 | \#*\# 6 | -------------------------------------------------------------------------------- /.old/demo-more-script: -------------------------------------------------------------------------------- 1 | set +xv 2 | . /t/prompt/prompt 3 | test -d demo && rm -rf demo/ 4 | test -d ../demo && cd .. && rm -rf demo/ 5 | clear 6 | : ------------------------------------------------------------------------ 7 | mkdir demo 8 | cd demo 9 | git init 10 | echo 'main() {puts("Hello World!");}' > hello.c 11 | make hello && ./hello 12 | git add hello.c 13 | git commit -q -m "1st hello" 14 | git checkout -b universe; git clean -f 15 | echo 'main() {puts("Hello Universe!");}' > hello.c 16 | git add hello.c 17 | echo "// FIXME: includes" >> hello.c 18 | git add hello.c 19 | git commit -q -m "notes to self" 20 | git checkout master 21 | cat hello.c 22 | echo 'main() {puts("Hello Universe!"); exit(0);}' > hello.c 23 | git add hello.c 24 | git commit -q -m "fixed exit code" 25 | git merge universe 26 | git cat-file -p universe:hello.c > hello.c 27 | git add hello.c 28 | git commit -q -m "merged" 29 | cat hello.c 30 | git checkout HEAD^ 31 | git checkout HEAD^ 32 | cat hello.c 33 | git checkout master 34 | sleep 2; echo "this emulates unsaved vim session" > .hello.c.swp 35 | git clean -f 36 | : ------------------------------------------------------------------------ 37 | cd .. 38 | -------------------------------------------------------------------------------- /.old/git-demo: -------------------------------------------------------------------------------- 1 | set +xv 2 | . /t/prompt/prompt 3 | test -d demo && rm -rf demo/ 4 | test -d ../demo && cd .. && rm -rf demo/ 5 | clear 6 | : ------------------------------------------------------------------------ 7 | mkdir demo 8 | cd demo 9 | git init 10 | echo 'main() {puts("Hello World!");}' > hello.c 11 | make hello && ./hello 12 | git add hello.c 13 | git commit -q -m "1st hello" 14 | git checkout -b universe; git clean -f 15 | echo 'main() {puts("Hello Universe!");}' > hello.c 16 | git add hello.c 17 | echo "// FIXME: includes" >> hello.c 18 | git add hello.c 19 | git commit -q -m "notes to self" 20 | git checkout master 21 | cat hello.c 22 | echo 'main() {puts("Hello Universe!"); exit(0);}' > hello.c 23 | git add hello.c 24 | git commit -q -m "fixed exit code" 25 | git merge universe 26 | git cat-file -p universe:hello.c > hello.c 27 | git add hello.c 28 | git commit -q -m "merged" 29 | cat hello.c 30 | git checkout HEAD^ 31 | git checkout HEAD^ 32 | cat hello.c 33 | git checkout master 34 | sleep 2; echo "this emulates unsaved vim session" > .hello.c.swp 35 | git clean -f 36 | : ------------------------------------------------------------------------ 37 | cd .. 38 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(USER),lvv) 2 | HOMEDIR := /home/lvv/p/volnitsky.com/ 3 | INCLUDE := $(HOMEDIR)/include.mk 4 | else 5 | INCLUDE := /dev/null 6 | endif 7 | 8 | include $(INCLUDE) 9 | 10 | 11 | COPY_LIST = git-prompt.sh 12 | 13 | 14 | install: 15 | cp -v git-prompt.sh /etc/ 16 | [ -f /etc/git-prompt.conf ] || cp -v git-prompt.conf /etc/ 17 | 18 | tgit: 19 | xclip -i git-demo 20 | echo "ready to paste ..." 21 | 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | GIT Prompt for BASH 2 | 3 | Screenshots and docs are at: http://volnitsky.com/project/git-prompt 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo-script: -------------------------------------------------------------------------------- 1 | cd p/git-prompt 2 | . ./git-prompt.sh 3 | cd 4 | test -d demo && rm -rf demo/ 5 | test -d ../demo && cd .. && rm -rf demo/ 6 | clear 7 | : ------------------------------------------------------------------------ 8 | clear 9 | mkdir demo 10 | cd demo 11 | git init 12 | echo "1st line" > FOO 13 | git add FOO 14 | touch untracked.o 15 | echo '*.o' >> .gitignore 16 | git commit -q -m "1st line" FOO 17 | git checkout -b test 18 | echo "added 2nd line in test" >> FOO 19 | git add FOO 20 | echo "2nd in BAR" > BAR 21 | git add BAR 22 | echo "added 3nd line FOO" >> FOO 23 | git add FOO 24 | git commit -q -m "FOO moded, BAR added" 25 | git checkout master 26 | cat FOO 27 | echo "now added 2nd line in master" >> FOO 28 | git add FOO 29 | git commit -q -m "2nd line" 30 | git merge test 31 | git cat-file -p test:FOO > FOO 32 | git add FOO 33 | git commit -q -m "merged" 34 | cat FOO 35 | git checkout HEAD^ 36 | cat FOO 37 | git checkout HEAD 38 | git clean -f 39 | : ------------------------------------------------------------------------ 40 | cd .. 41 | -------------------------------------------------------------------------------- /git-prompt.conf: -------------------------------------------------------------------------------- 1 | 2 | ### GIT-PROMPT.SH CONFIG 3 | ### 4 | ### lines commented-out with single '#' are default values 5 | ### lines commented-out with double '##' are examples 6 | ### 7 | ### NOTE: this is bash syntax - no spaces around "=" 8 | 9 | ########################################################### 10 | 11 | # error_bell=off # sound terminal bell when command return code is not zero. (use setterm to set pitch and duration) 12 | # max_file_list_length=100 # in characters 13 | # count_only=off # off - display file list; on - display file count 14 | # rawhex_len=5 # length of git rawhex revision id display (use 0 to hide it) 15 | 16 | ############################################################ MODULES 17 | 18 | # git_module=on 19 | # svn_module=off 20 | # hg_module=on 21 | # vim_module=on 22 | # virtualenv_module=on 23 | 24 | 25 | ########################################################### DEFAULT OBJECTS 26 | ### Default objects are not displayed. Example: 27 | 28 | ## default_user=lvv 29 | ## default_host="ahp" # remote host is always shown 30 | ## default_domain="lvvnet" 31 | 32 | ########################################################### Current Working Dir display 33 | # cwd_cmd='\w' # display full path 34 | ## cwd_cmd='\W' # display only last dir of path 35 | ## cwd_cmd='cwd_truncate 40' # display only last N chars of path 36 | 37 | ########################################################### ETC 38 | 39 | # Some don't like hostname in uppercase 40 | # upcase_hostname=on # =off 41 | # Some don't like long hostname 42 | # short_hostname=off # =on 43 | 44 | # Do not do VCS parsing for listed directories 45 | # useful for directories for which it is difficult to maintain .gitignore so 46 | # they are always dirty (ex: home, /etc) or directory with huge repo (ex: linux src) 47 | ## vcs_ignore_dir_list=" /etc $HOME /usr/src/linux.git " 48 | 49 | ########################################################### COLOR 50 | 51 | ### directory, exit code, root color 52 | 53 | # cols=`tput colors` 54 | # if [[ -n "$cols" && $cols -ge 8 ]]; then # if terminal supports colors 55 | # dir_color=CYAN 56 | # rc_color=red 57 | # virtualenv_color=green 58 | # user_id_color=blue 59 | # root_id_color=magenta 60 | # else # B/W terminal 61 | # dir_color=bw_bold 62 | # rc_color=bw_bold 63 | # fi 64 | 65 | ### prompt character for root/non-root, default '>' for both 66 | # prompt_char='>' 67 | # root_prompt_char='>' 68 | ## prompt_char='$' 69 | ## prompt_char='➔' 70 | ## root_prompt_char='#' 71 | 72 | ##### Per host color 73 | 74 | ### Per host color. If not set, color will be derived from hostname checksum). 75 | ### Variable name is uppercase-short-hostname with appended "_host_color" 76 | ### Example per-host-color config: 77 | 78 | ## TASHA_host_color=cyan 79 | ## AL_host_color=green 80 | ## AHP_host_color=white 81 | 82 | 83 | ##### VCS (version control system) state colors 84 | 85 | # init_vcs_color=WHITE # initial 86 | # clean_vcs_color=blue # nothing to commit (working directory clean) 87 | # modified_vcs_color=red # Changed but not updated: 88 | # added_vcs_color=green # Changes to be committed: 89 | # mixed_vcs_color=yellow # 90 | # untracked_vcs_color=BLUE # Untracked files: 91 | # op_vcs_color=MAGENTA 92 | # detached_vcs_color=RED 93 | # hex_vcs_color=BLACK # git revision id: bright black (makes gray) 94 | 95 | 96 | # :vim:ft=sh ts=8 sw=8 et: 97 | -------------------------------------------------------------------------------- /git-prompt.sh: -------------------------------------------------------------------------------- 1 | # don't set prompt if this is not interactive shell 2 | [[ $- != *i* ]] && return 3 | 4 | # bash version check 5 | if [[ -z ${BASH_VERSION} || "${BASH_VERSINFO[0]}" -lt 4 ]]; then 6 | echo "git-prompt requires bash-v4 or newer, git-prompt is not enabled." 7 | return 8 | fi 9 | 10 | # clear vars from previous invocation 11 | unset dir_color rc_color user_id_color root_id_color init_vcs_color clean_vcs_color 12 | unset modified_vcs_color added_vcs_color addmoded_vcs_color untracked_vcs_color op_vcs_color detached_vcs_color hex_vcs_color 13 | unset rawhex_len 14 | 15 | # work around for conflict with vte.sh 16 | unset VTE_VERSION 17 | 18 | ################################################################### CONFIG 19 | 20 | ##### read config file if any. 21 | 22 | 23 | conf=git-prompt.conf; [[ -r $conf ]] && . $conf 24 | conf=/etc/git-prompt.conf; [[ -r $conf ]] && . $conf 25 | conf=~/.git-prompt.conf; [[ -r $conf ]] && . $conf 26 | conf=~/.config/git-prompt.conf; [[ -r $conf ]] && . $conf 27 | unset conf 28 | 29 | 30 | ##### set defaults if not set 31 | 32 | git_module=${git_module:-on} 33 | svn_module=${svn_module:-off} 34 | hg_module=${hg_module:-on} 35 | vim_module=${vim_module:-on} 36 | virtualenv_module=${virtualenv_module:-on} 37 | error_bell=${error_bell:-off} 38 | cwd_cmd=${cwd_cmd:-\\w} 39 | 40 | 41 | #### dir, rc, root color 42 | cols=`tput colors` # in emacs shell-mode tput colors returns -1 43 | if [[ -n "$cols" && $cols -ge 8 ]]; then # if terminal supports colors 44 | dir_color=${dir_color:-CYAN} 45 | rc_color=${rc_color:-red} 46 | virtualenv_color=${virtualenv_color:-green} 47 | user_id_color=${user_id_color:-blue} 48 | root_id_color=${root_id_color:-magenta} 49 | else # only B/W 50 | dir_color=${dir_color:-bw_bold} 51 | rc_color=${rc_color:-bw_bold} 52 | fi 53 | unset cols 54 | 55 | #### prompt character, for root/non-root 56 | prompt_char=${prompt_char:-'>'} 57 | root_prompt_char=${root_prompt_char:-'>'} 58 | 59 | #### vcs colors 60 | init_vcs_color=${init_vcs_color:-WHITE} # initial 61 | clean_vcs_color=${clean_vcs_color:-blue} # nothing to commit (working directory clean) 62 | modified_vcs_color=${modified_vcs_color:-red} # Changed but not updated: 63 | added_vcs_color=${added_vcs_color:-green} # Changes to be committed: 64 | addmoded_vcs_color=${addmoded_vcs_color:-yellow} 65 | untracked_vcs_color=${untracked_vcs_color:-BLUE} # Untracked files: 66 | op_vcs_color=${op_vcs_color:-MAGENTA} 67 | detached_vcs_color=${detached_vcs_color:-RED} 68 | 69 | hex_vcs_color=${hex_vcs_color:-BLACK} # gray 70 | 71 | 72 | max_file_list_length=${max_file_list_length:-100} 73 | short_hostname=${short_hostname:-off} 74 | upcase_hostname=${upcase_hostname:-on} 75 | count_only=${count_only:-off} 76 | rawhex_len=${rawhex_len:-5} 77 | 78 | aj_max=20 79 | 80 | 81 | ##################################################################### post config 82 | 83 | ################# make PARSE_VCS_STATUS 84 | unset PARSE_VCS_STATUS 85 | [[ $git_module = "on" ]] && type git >&/dev/null && PARSE_VCS_STATUS+="parse_git_status" 86 | [[ $svn_module = "on" ]] && type svn >&/dev/null && PARSE_VCS_STATUS+="${PARSE_VCS_STATUS+||}parse_svn_status" 87 | [[ $hg_module = "on" ]] && type hg >&/dev/null && PARSE_VCS_STATUS+="${PARSE_VCS_STATUS+||}parse_hg_status" 88 | PARSE_VCS_STATUS+="${PARSE_VCS_STATUS+||}return" 89 | ################# terminfo colors-16 90 | # 91 | # black? 0 8 92 | # red 1 9 93 | # green 2 10 94 | # yellow 3 11 95 | # blue 4 12 96 | # magenta 5 13 97 | # cyan 6 14 98 | # white 7 15 99 | # 100 | # terminfo setaf/setab - sets ansi foreground/background 101 | # terminfo sgr0 - resets all attributes 102 | # terminfo colors - number of colors 103 | # 104 | ################# Colors-256 105 | # To use foreground and background colors: 106 | # Set the foreground color to index N: \033[38;5;${N}m 107 | # Set the background color to index M: \033[48;5;${M}m 108 | # To make vim aware of a present 256 color extension, you can either set 109 | # the $TERM environment variable to xterm-256color or use vim's -T option 110 | # to set the terminal. I'm using an alias in my bashrc to do this. At the 111 | # moment I only know of two color schemes which is made for multi-color 112 | # terminals like urxvt (88 colors) or xterm: inkpot and desert256, 113 | 114 | ### if term support colors, then use color prompt, else bold 115 | 116 | black='\['`tput sgr0; tput setaf 0`'\]' 117 | red='\['`tput sgr0; tput setaf 1`'\]' 118 | green='\['`tput sgr0; tput setaf 2`'\]' 119 | yellow='\['`tput sgr0; tput setaf 3`'\]' 120 | blue='\['`tput sgr0; tput setaf 4`'\]' 121 | magenta='\['`tput sgr0; tput setaf 5`'\]' 122 | cyan='\['`tput sgr0; tput setaf 6`'\]' 123 | white='\['`tput sgr0; tput setaf 7`'\]' 124 | 125 | BLACK='\['`tput setaf 0; tput bold`'\]' 126 | RED='\['`tput setaf 1; tput bold`'\]' 127 | GREEN='\['`tput setaf 2; tput bold`'\]' 128 | YELLOW='\['`tput setaf 3; tput bold`'\]' 129 | BLUE='\['`tput setaf 4; tput bold`'\]' 130 | MAGENTA='\['`tput setaf 5; tput bold`'\]' 131 | CYAN='\['`tput setaf 6; tput bold`'\]' 132 | WHITE='\['`tput setaf 7; tput bold`'\]' 133 | 134 | dim='\['`tput sgr0; tput setaf p1`'\]' # half-bright 135 | 136 | bw_bold='\['`tput bold`'\]' 137 | 138 | on='' 139 | off=': ' 140 | bell="\[`eval ${!error_bell} tput bel`\]" 141 | colors_reset='\['`tput sgr0`'\]' 142 | 143 | # replace symbolic colors names to raw treminfo strings 144 | init_vcs_color=${!init_vcs_color} 145 | modified_vcs_color=${!modified_vcs_color} 146 | untracked_vcs_color=${!untracked_vcs_color} 147 | clean_vcs_color=${!clean_vcs_color} 148 | added_vcs_color=${!added_vcs_color} 149 | op_vcs_color=${!op_vcs_color} 150 | addmoded_vcs_color=${!addmoded_vcs_color} 151 | detached_vcs_color=${!detached_vcs_color} 152 | hex_vcs_color=${!hex_vcs_color} 153 | 154 | unset PROMPT_COMMAND 155 | 156 | ####### work around for MC bug. 157 | ####### specifically exclude emacs, want full when running inside emacs 158 | if [[ -z "$TERM" || ("$TERM" = "dumb" && -z "$INSIDE_EMACS") || -n "$MC_SID" ]]; then 159 | unset PROMPT_COMMAND 160 | PS1="\w$prompt_char " 161 | return 0 162 | fi 163 | 164 | #################################################################### MARKERS 165 | if [[ "$LC_CTYPE $LC_ALL" =~ "UTF" && $TERM != "linux" ]]; then 166 | elipses_marker="…" 167 | else 168 | elipses_marker="..." 169 | fi 170 | 171 | export who_where 172 | 173 | 174 | cwd_truncate() { 175 | # based on: https://www.blog.montgomerie.net/pwd-in-the-title-bar-or-a-regex-adventure-in-bash 176 | 177 | # arg1: max path lenght 178 | # returns abbrivated $PWD in public "cwd" var 179 | 180 | cwd="${PWD/$HOME/\~}" # substitute "~" 181 | 182 | case $1 in 183 | full) 184 | return 185 | ;; 186 | last) 187 | cwd="${PWD##/*/}" 188 | [[ "$PWD" == "$HOME" ]] && cwd="~" 189 | return 190 | ;; 191 | *) 192 | ;; 193 | esac 194 | 195 | # split path into: head='~/', truncateble middle, last_dir 196 | 197 | local cwd_max_length=$1 198 | 199 | if [[ "$cwd" =~ '(~?/)(.*/)([^/]*)$' ]] ; then # only valid if path have more than 1 dir 200 | local path_head=${BASH_REMATCH[1]} 201 | local path_middle=${BASH_REMATCH[2]} 202 | local path_last_dir=${BASH_REMATCH[3]} 203 | 204 | local cwd_middle_max=$(( $cwd_max_length - ${#path_last_dir} )) 205 | [[ $cwd_middle_max < 0 ]] && cwd_middle_max=0 206 | 207 | 208 | # trunc middle if over limit 209 | if [[ ${#path_middle} -gt $(( $cwd_middle_max + ${#elipses_marker} + 5 )) ]]; then 210 | 211 | # truncate 212 | middle_tail=${path_middle:${#path_middle}-${cwd_middle_max}} 213 | 214 | # trunc on dir boundary (trunc 1st, probably tuncated dir) 215 | [[ $middle_tail =~ '[^/]*/(.*)$' ]] 216 | middle_tail=${BASH_REMATCH[1]} 217 | 218 | # use truncated only if we cut at least 4 chars 219 | if [[ $(( ${#path_middle} - ${#middle_tail})) -gt 4 ]]; then 220 | cwd=$path_head$elipses_marker$middle_tail$path_last_dir 221 | fi 222 | fi 223 | fi 224 | return 225 | } 226 | 227 | 228 | set_shell_label() { 229 | 230 | xterm_label() { 231 | local args="$*" 232 | echo -n "]2;${args:0:200}" ; # FIXME: replace hardcodes with terminfo codes 233 | } 234 | 235 | screen_label() { 236 | # FIXME: run this only if screen is in xterm (how to test for this?) 237 | xterm_label "$plain_who_where $@" 238 | 239 | # FIXME $STY not inherited though "su -" 240 | [ "$STY" ] && screen -S $STY -X title "$*" 241 | } 242 | if [[ -n "$STY" ]]; then 243 | screen_label "$*" 244 | else 245 | case $TERM in 246 | 247 | screen*) 248 | screen_label "$*" 249 | ;; 250 | 251 | xterm* | rxvt* | gnome-* | konsole | eterm | wterm ) 252 | # is there a capability which we can to test 253 | # for "set term title-bar" and its escapes? 254 | xterm_label "$plain_who_where $@" 255 | ;; 256 | 257 | *) 258 | ;; 259 | esac 260 | fi 261 | } 262 | 263 | export -f set_shell_label 264 | 265 | ###################################################### ID (user name) 266 | id=`id -un` 267 | id=${id#$default_user} 268 | 269 | ########################################################### TTY 270 | tty=`tty` 271 | tty=`echo $tty | sed "s:/dev/pts/:p:; s:/dev/tty::" ` # RH tty devs 272 | tty=`echo $tty | sed "s:/dev/vc/:vc:" ` # gentoo tty devs 273 | 274 | if [[ "$TERM" = "screen" ]] ; then 275 | 276 | # [ "$WINDOW" = "" ] && WINDOW="?" 277 | # 278 | # # if under screen then make tty name look like s1-p2 279 | # # tty="${WINDOW:+s}$WINDOW${WINDOW:+-}$tty" 280 | # tty="${WINDOW:+s}$WINDOW" # replace tty name with screen number 281 | tty="$WINDOW" # replace tty name with screen number 282 | fi 283 | 284 | # we don't need tty name under X11 285 | case $TERM in 286 | xterm* | rxvt* | gnome-terminal | konsole | eterm* | wterm | cygwin) unset tty ;; 287 | *);; 288 | esac 289 | 290 | dir_color=${!dir_color} 291 | rc_color=${!rc_color} 292 | virtualenv_color=${!virtualenv_color} 293 | user_id_color=${!user_id_color} 294 | root_id_color=${!root_id_color} 295 | 296 | ########################################################### HOST 297 | ### we don't display home host/domain $SSH_* set by SSHD or keychain 298 | 299 | # How to find out if session is local or remote? Working with "su -", ssh-agent, and so on ? 300 | 301 | ## is sshd our parent? 302 | # if { for ((pid=$$; $pid != 1 ; pid=`ps h -o pid --ppid $pid`)); do ps h -o command -p $pid; done | grep -q sshd && echo == REMOTE ==; } 303 | #then 304 | 305 | host=${HOSTNAME} 306 | if [[ $short_hostname = "on" ]]; then 307 | if [[ "$(uname)" =~ "CYGWIN" ]]; then 308 | host=`hostname` 309 | else 310 | host=`hostname -s` 311 | fi 312 | fi 313 | host=${host#$default_host} 314 | uphost=`echo ${host} | tr a-z-. A-Z_` 315 | if [[ $upcase_hostname = "on" ]]; then 316 | host=${uphost} 317 | fi 318 | 319 | host_color=${uphost}_host_color 320 | host_color=${!host_color} 321 | if [[ -z $host_color && -x /usr/bin/cksum ]] ; then 322 | cksum_color_no=`echo $uphost | cksum | awk '{print $1%6}'` 323 | color_index=(green yellow blue magenta cyan white) # FIXME: bw, color-256 324 | host_color=${color_index[cksum_color_no]} 325 | fi 326 | 327 | host_color=${!host_color} 328 | 329 | # we might already have short host name 330 | host=${host%.$default_domain} 331 | 332 | #################################################################### WHO_WHERE 333 | # [[user@]host[-tty]] 334 | 335 | if [[ -n $id || -n $host ]] ; then 336 | [[ -n $id && -n $host ]] && at='@' || at='' 337 | color_who_where="${id}${host:+$host_color$at$host}${tty:+ $tty}" 338 | plain_who_where="${id}$at$host" 339 | 340 | # add trailing " " 341 | color_who_where="$color_who_where " 342 | plain_who_where="$plain_who_where " 343 | 344 | # if root then make it root_color 345 | if [ "$id" == "root" ] ; then 346 | user_id_color=$root_id_color 347 | prompt_char="$root_prompt_char" 348 | fi 349 | color_who_where="$user_id_color$color_who_where$colors_reset" 350 | else 351 | color_who_where='' 352 | fi 353 | 354 | 355 | parse_svn_status() { 356 | 357 | [[ -d .svn ]] || return 1 358 | 359 | vcs=svn 360 | 361 | ### get rev 362 | eval ` 363 | svn info | 364 | sed -n " 365 | s@^URL[^/]*//@repo_dir=@p 366 | s/^Revision: /rev=/p 367 | " 368 | ` 369 | ### get status 370 | 371 | unset status modified added clean init added mixed untracked op detached 372 | eval `svn status 2>/dev/null | 373 | sed -n ' 374 | s/^A... \([^.].*\)/modified=modified; modified_files[${#modified_files[@]}]=\"\1\";/p 375 | s/^M... \([^.].*\)/modified=modified; modified_files[${#modified_files[@]}]=\"\1\";/p 376 | s/^\?... \([^.].*\)/untracked=untracked; untracked_files[${#untracked_files[@]}]=\"\1\";/p 377 | ' 378 | ` 379 | # TODO branch detection if standard repo layout 380 | 381 | [[ -z $modified ]] && [[ -z $untracked ]] && clean=clean 382 | vcs_info=svn:r$rev 383 | } 384 | 385 | parse_hg_status() { 386 | 387 | # ☿ 388 | hg_root=`hg root 2>/dev/null` || return 1 389 | 390 | vcs=hg 391 | 392 | ### get status 393 | unset status modified added clean init added mixed untracked op detached 394 | 395 | eval `hg status 2>/dev/null | 396 | sed -n ' 397 | s/^M \([^.].*\)/modified=modified; modified_files[${#modified_files[@]}]=\"\1\";/p 398 | s/^A \([^.].*\)/added=added; added_files[${#added_files[@]}]=\"\1\";/p 399 | s/^R \([^.].*\)/added=added;/p 400 | s/^! \([^.].*\)/modified=modified;/p 401 | s/^? \([^.].*\)/untracked=untracked; untracked_files[${#untracked_files[@]}]=\\"\1\\";/p 402 | '` 403 | 404 | branch=`hg branch 2> /dev/null` 405 | 406 | [[ -f $hg_root/.hg/bookmarks.current ]] && bookmark=`cat "$hg_root/.hg/bookmarks.current"` 407 | 408 | [[ -z $modified ]] && [[ -z $untracked ]] && [[ -z $added ]] && clean=clean 409 | vcs_info=${branch/default/D} 410 | if [[ "$bookmark" ]] ; then 411 | vcs_info+=/$bookmark 412 | fi 413 | } 414 | 415 | 416 | 417 | parse_git_status() { 418 | 419 | # TODO add status: LOCKED (.git/index.lock) 420 | 421 | git_dir=`[[ $git_module = "on" ]] && git rev-parse --git-dir 2> /dev/null` 422 | #git_dir=`eval \$$git_module git rev-parse --git-dir 2> /dev/null` 423 | #git_dir=` git rev-parse --git-dir 2> /dev/null` 424 | 425 | [[ -n ${git_dir/./} ]] || return 1 426 | [[ -f ${git_dir}/git-prompt-ignored ]] && return 1 427 | 428 | vcs=git 429 | 430 | ########################################################## GIT STATUS 431 | added_files=() 432 | modified_files=() 433 | untracked_files=() 434 | [[ $rawhex_len -gt 0 ]] && freshness="$dim=" 435 | 436 | unset branch status modified added clean init added mixed untracked op detached 437 | 438 | # work around for VTE bug (hang on printf) 439 | unset VTE_VERSION 440 | 441 | # info not in porcelain status 442 | eval " $( 443 | LANG=C git status 2>/dev/null | 444 | sed -n ' 445 | s/^\(# \)*On branch /branch=/p 446 | s/^nothing to commi.*/clean=clean/p 447 | s/^\(# \)*Initial commi.*/init=init/p 448 | s/^\(# \)*Your branch is ahead of \(.\).\+\1 by [[:digit:]]\+ commit.*/freshness=${WHITE}↑/p 449 | s/^\(# \)*Your branch is behind \(.\).\+\1 by [[:digit:]]\+ commit.*/freshness=${YELLOW}↓/p 450 | s/^\(# \)*Your branch and \(.\).\+\1 have diverged.*/freshness=${YELLOW}↕/p 451 | ' 452 | )" 453 | 454 | # porcelain file list 455 | # TODO: sed-less -- http://tldp.org/LDP/abs/html/arrays.html -- Example 27-5 456 | 457 | # git bug: (was reported to git@vger.kernel.org ) 458 | # echo 1 > "with space" 459 | # git status --porcelain 460 | # ?? with space <------------ NO QOUTES 461 | # git add with\ space 462 | # git status --porcelain 463 | # A "with space" <------------- WITH QOUTES 464 | 465 | eval " $( 466 | LANG=C git status --porcelain 2>/dev/null | 467 | sed -n ' 468 | s,^[MARC]. \([^\"][^/]*/\?\).*, added=added; [[ \" ${added_files[@]} \" =~ \" \1 \" ]] || added_files[${#added_files[@]}]=\"\1\",p 469 | s,^[MARC]. \"\([^/]\+/\?\).*\"$, added=added; [[ \" ${added_files[@]} \" =~ \" \1 \" ]] || added_files[${#added_files[@]}]=\"\1\",p 470 | s,^.[MAU] \([^\"][^/]*/\?\).*, modified=modified; [[ \" ${modified_files[@]} \" =~ \" \1 \" ]] || modified_files[${#modified_files[@]}]=\"\1\",p 471 | s,^.[MAU] \"\([^/]\+/\?\).*\"$, modified=modified; [[ \" ${modified_files[@]} \" =~ \" \1 \" ]] || modified_files[${#modified_files[@]}]=\"\1\",p 472 | s,^?? \([^\"][^/]*/\?\).*, untracked=untracked; [[ \" ${untracked_files[@]} \" =~ \" \1 \" ]] || untracked_files[${#untracked_files[@]}]=\"\1\",p 473 | s,^?? \"\([^/]\+/\?\).*\"$, untracked=untracked; [[ \" ${untracked_files[@]} \" =~ \" \1 \" ]] || untracked_files[${#untracked_files[@]}]=\"\1\",p 474 | ' # |tee /dev/tty 475 | )" 476 | 477 | if ! grep -q "^ref:" "$git_dir/HEAD" 2>/dev/null; then 478 | detached=detached 479 | fi 480 | 481 | 482 | ################# GET GIT OP 483 | 484 | unset op 485 | 486 | if [[ -d "$git_dir/.dotest" ]] ; then 487 | 488 | if [[ -f "$git_dir/.dotest/rebasing" ]] ; then 489 | op="rebase" 490 | 491 | elif [[ -f "$git_dir/.dotest/applying" ]] ; then 492 | op="am" 493 | 494 | else 495 | op="am/rebase" 496 | 497 | fi 498 | 499 | elif [[ -f "$git_dir/.dotest-merge/interactive" ]] ; then 500 | op="rebase -i" 501 | # ??? branch="$(cat "$git_dir/.dotest-merge/head-name")" 502 | 503 | elif [[ -d "$git_dir/.dotest-merge" ]] ; then 504 | op="rebase -m" 505 | # ??? branch="$(cat "$git_dir/.dotest-merge/head-name")" 506 | 507 | # lvv: not always works. Should ./.dotest be used instead? 508 | elif [[ -f "$git_dir/MERGE_HEAD" ]] ; then 509 | op="merge" 510 | # ??? branch="$(git symbolic-ref HEAD 2>/dev/null)" 511 | 512 | elif [[ -f "$git_dir/index.lock" ]] ; then 513 | op="locked" 514 | 515 | else 516 | [[ -f "$git_dir/BISECT_LOG" ]] && op="bisect" 517 | # ??? branch="$(git symbolic-ref HEAD 2>/dev/null)" || \ 518 | # branch="$(git describe --exact-match HEAD 2>/dev/null)" || \ 519 | # branch="$(cut -c1-7 "$git_dir/HEAD")..." 520 | fi 521 | 522 | 523 | #### GET GIT HEX-REVISION 524 | if [[ $rawhex_len -gt 0 ]] ; then 525 | rawhex=`git rev-parse HEAD 2>/dev/null` 526 | rawhex=${rawhex/HEAD/} 527 | rawhex="$hex_vcs_color${rawhex:0:$rawhex_len}" 528 | else 529 | rawhex="" 530 | fi 531 | 532 | #### branch 533 | branch=${branch/#master/M} 534 | 535 | # another method of above: 536 | # branch=$(git symbolic-ref -q HEAD || { echo -n "detached:" ; git name-rev --name-only HEAD 2>/dev/null; } ) 537 | # branch=${branch#refs/heads/} 538 | 539 | ### compose vcs_info 540 | 541 | if [[ $init ]]; then 542 | vcs_info=${white}init 543 | 544 | else 545 | if [[ "$detached" ]] ; then 546 | branch="/dev/null`" 547 | 548 | 549 | elif [[ "$op" ]]; then 550 | branch="$op:$branch" 551 | if [[ "$op" == "merge" ]] ; then 552 | branch+="<--$(git name-rev --name-only $(<$git_dir/MERGE_HEAD))" 553 | fi 554 | #branch="<$branch>" 555 | fi 556 | vcs_info="$branch$freshness$rawhex" 557 | 558 | fi 559 | } 560 | 561 | 562 | parse_vcs_status() { 563 | 564 | unset file_list modified_files untracked_files added_files 565 | unset vcs vcs_info 566 | unset status modified untracked added init detached 567 | unset file_list modified_files untracked_files added_files 568 | 569 | [[ $vcs_ignore_dir_list =~ $PWD ]] && return 570 | 571 | eval $PARSE_VCS_STATUS 572 | 573 | 574 | ### status: choose primary (for branch color) 575 | unset status 576 | status=${op:+op} 577 | status=${status:-$detached} 578 | status=${status:-$clean} 579 | status=${status:-$modified} 580 | status=${status:-$added} 581 | status=${status:-$untracked} 582 | status=${status:-$init} 583 | # at least one should be set 584 | : ${status?prompt internal error: git status} 585 | eval vcs_color="\${${status}_vcs_color}" 586 | # no def: vcs_color=${vcs_color:-$WHITE} # default 587 | 588 | 589 | ### VIM 590 | 591 | if [[ $vim_module = "on" ]] ; then 592 | # equivalent to vim_glob=`ls .*.vim` but without running ls 593 | unset vim_glob vim_file vim_files 594 | old_nullglob=`shopt -p nullglob` 595 | shopt -s nullglob 596 | vim_glob=`echo .*.sw?` 597 | eval $old_nullglob 598 | 599 | if [[ $vim_glob ]]; then 600 | set $vim_glob 601 | #vim_file=${vim_glob#.} 602 | if [[ $# > 1 ]] ; then 603 | vim_files="*" 604 | else 605 | vim_file=${1#.} 606 | vim_file=${vim_file/.sw?/} 607 | [[ .${vim_file}.swp -nt $vim_file ]] && vim_files=$vim_file 608 | fi 609 | # if swap is newer, then this is unsaved vim session 610 | # [temoto custom] if swap is older, then it must be deleted, so show all swaps. 611 | fi 612 | fi 613 | 614 | 615 | ### file list 616 | unset file_list 617 | if [[ $count_only = "on" ]] ; then 618 | [[ ${added_files[0]} ]] && file_list+=" "${added_vcs_color}+${#added_files[@]} 619 | [[ ${modified_files[0]} ]] && file_list+=" "${modified_vcs_color}*${#modified_files[@]} 620 | [[ ${untracked_files[0]} ]] && file_list+=" "${untracked_vcs_color}?${#untracked_files[@]} 621 | else 622 | [[ ${added_files[0]} ]] && file_list+=" "$added_vcs_color${added_files[@]} 623 | [[ ${modified_files[0]} ]] && file_list+=" "$modified_vcs_color${modified_files[@]} 624 | [[ ${untracked_files[0]} ]] && file_list+=" "$untracked_vcs_color${untracked_files[@]} 625 | fi 626 | [[ ${vim_files} ]] && file_list+=" "${MAGENTA}vim:${vim_files} 627 | 628 | if [[ ${#file_list} -gt $max_file_list_length ]] ; then 629 | file_list=${file_list:0:$max_file_list_length} 630 | if [[ $max_file_list_length -gt 0 ]] ; then 631 | file_list="${file_list% *} $elipses_marker" 632 | fi 633 | fi 634 | 635 | 636 | head_local="$vcs_color(${vcs_info}$vcs_color${file_list}$vcs_color)" 637 | 638 | ### fringes 639 | head_local="${head_local+$vcs_color$head_local }" 640 | #above_local="${head_local+$vcs_color$head_local\n}" 641 | #tail_local="${tail_local+$vcs_color $tail_local}${dir_color}" 642 | } 643 | 644 | parse_virtualenv_status() { 645 | unset virtualenv 646 | 647 | [[ $virtualenv_module = "on" ]] || return 1 648 | 649 | if [[ -n "$VIRTUAL_ENV" ]] ; then 650 | virtualenv=`basename $VIRTUAL_ENV` 651 | rc="$rc $virtualenv_color<$virtualenv> " 652 | fi 653 | } 654 | 655 | disable_set_shell_label() { 656 | trap - DEBUG >& /dev/null 657 | } 658 | 659 | # show currently executed command in label 660 | enable_set_shell_label() { 661 | disable_set_shell_label 662 | # check for BASH_SOURCE being empty, no point running set_shell_label on every line of .bashrc 663 | trap '[[ -z "$BASH_SOURCE" && ($BASH_COMMAND != prompt_command_function) ]] && 664 | set_shell_label $BASH_COMMAND' DEBUG >& /dev/null 665 | } 666 | 667 | declare -ft disable_set_shell_label 668 | declare -ft enable_set_shell_label 669 | 670 | # autojump (see http://wiki.github.com/joelthelion/autojump) 671 | 672 | # TODO reverse the line order of a file 673 | #awk ' { line[NR] = $0 } 674 | # END { for (i=NR;i>0;i--) 675 | # print line[i] }' listlogs 676 | 677 | j (){ 678 | : ${1? usage: j dir-beginning} 679 | # go in ring buffer starting from current index. cd to first matching dir 680 | for (( i=(aj_idx-1)%aj_max; i != aj_idx%aj_max; i=(--i+aj_max)%aj_max )) ; do 681 | if [[ ${aj_dir_list[$i]} =~ ^.*/$1[^/]*$ ]] ; then 682 | cd "${aj_dir_list[$i]}" 683 | return 684 | fi 685 | done 686 | echo '?' 687 | } 688 | 689 | alias jumpstart='echo ${aj_dir_list[@]}' 690 | 691 | ###################################################################### PROMPT_COMMAND 692 | 693 | prompt_command_function() { 694 | rc="$?" 695 | 696 | if [[ "$rc" == "0" ]]; then 697 | rc="" 698 | else 699 | rc="$rc_color$rc$colors_reset$bell " 700 | fi 701 | 702 | cwd=${PWD/$HOME/\~} # substitute "~" 703 | set_shell_label "${cwd##[/~]*/}/" # default label - path last dir 704 | 705 | parse_virtualenv_status 706 | parse_vcs_status 707 | 708 | # autojump 709 | if [[ ${aj_dir_list[aj_idx%aj_max]} != $PWD ]] ; then 710 | aj_dir_list[++aj_idx%aj_max]="$PWD" 711 | fi 712 | 713 | # if cwd_cmd have back-slash, then assign it value to cwd 714 | # else eval cwd_cmd, cwd should have path after exection 715 | eval "${cwd_cmd/\\/cwd=\\\\}" 716 | 717 | PS1="$colors_reset$rc$head_local$color_who_where$dir_color$cwd$tail_local$dir_color$prompt_char $colors_reset" 718 | 719 | unset head_local tail_local pwd 720 | } 721 | 722 | PROMPT_COMMAND=prompt_command_function 723 | 724 | enable_set_shell_label 725 | 726 | unset rc id tty modified_files file_list 727 | 728 | # vim: set ft=sh ts=8 sw=8 et: 729 | -------------------------------------------------------------------------------- /index.txt: -------------------------------------------------------------------------------- 1 | // This is raw asciidoc file. The HTML rendered page is at http://volnitsky.com/project/git-prompt 2 | 3 | = GIT Prompt 4 | 5 | * Repo: httpx://github.com/lvv/scc[GitHub], httpx://bitbucket.org/lvv/scc[BitBucket] + 6 | * License: httpx://www.gnu.org/licenses/gpl-3.0.html[GPL3] 7 | 8 | :v-p: http://volnitsky.com/project 9 | :compact-option: compact 10 | 11 | 12 | == Basic Usage 13 | 14 | image:screenshot-prompt-basic.png[basic usage] 15 | 16 | Digit [red]*1* on 3rd line is `false(1)` exit code. Also on non-zero exit code 17 | terminal bell is sounded. Bell is turned off by default (to set softer 18 | terminal bell use `setterm`). 19 | 20 | 21 | == GIT 22 | 23 | Branch and files are colored according to state. "M" stands for master. 24 | 25 | image:screenshot-prompt-git.png[git module screenshot] 26 | 27 | .Branch and Files Colors 28 | [cols="^3,^3,12",frame="topbot",options="header"] 29 | |================================================================ 30 | | *Branch* | *File* | *Meaning* 31 | | [darkblue]#dark blue# | | Clean repo 32 | | [green]#green# | [green]#green# | Modified or new file. Modifications are in index but not in repo yet. 33 | | [darkred]#dark red# | [darkred]#dark red# | Modified and tracked by repo, but modifications not added to index yet. 34 | | [lightblue]#light blue# | [lightblue]#light blue# | Untracked file. 35 | | [red]#light red# | | Detached Head 36 | | [magenta]#magenta# | | In middle of doing something 37 | |================================================================ 38 | 39 | 40 | == Subversion/SVN 41 | image:screenshot-svn.png[svn module screenshot] 42 | 43 | SVN module disabled by default because even on moderate sized working 44 | directories there is noticeable delay for prompt display. SVN is slower than 45 | GIT. Enable if needed in <> 46 | 47 | == Mercurial/HG 48 | HG module was developed by Lee Nussbaum ``. 49 | 50 | 51 | == Labels 52 | 53 | Labels are visual cues to help figure out what terminal is running what command. 54 | It is generalization of xterm-title but differ from xterm-title that it 55 | can be displayed in other places (on Screen(1) windows titles for example). 56 | Also label can display currently executed command (when bash prompt obviously 57 | is not displayed). Because labels have less space then prompt, instead of full path 58 | only last dir is shown. 59 | On screenshot below labels are in red ovals. 60 | 61 | image:screenshot-labels.png["labels screenshot", width="300", link="screenshot-labels.png"] 62 | 63 | The `screen(1)` status line at bottom of smaller gnome-terminal is displayed with 64 | following line in `~/.screenrc`: 65 | 66 | --------- 67 | caption always "%{= kw}%-w%{= bw}%n %t%{-}%+w %-= @%H - %LD %d %LM - %c" 68 | --------- 69 | 70 | 71 | == Simple AutoJump 72 | 73 | AutoJump is python script from Joel Schaerer providing shortcuts for jumping 74 | to directories you once visited. Git-prompt have built-in, simplified 75 | autojump. It is only about 10 lines of bash code (vs original 100+ python 76 | LOC), there is no database. It remembers only directories from current 77 | session. It selects not most frequent dir, but last visited. Matches are done 78 | from beginning of of dir name (not path name). 79 | 80 | ----------------- 81 | cd /tmp 82 | cd "~/long dir mp3" 83 | cd "~/long dir mp4" 84 | cd /tmp 85 | cd /var/tmp 86 | cd /etc 87 | cd 88 | j t # same as cd /var/tmp 89 | j .*3 # same as cd "~/long dir mp3" 90 | ------------- 91 | 92 | 93 | == Install 94 | Download link:git-prompt.sh[] or get it with GIT: 95 | 96 | ------------------ 97 | git clone git://github.com/lvv/git-prompt.git 98 | --------------- 99 | 100 | Put following command at the end of your profile (`~/.bash_profile` or `~/.profile`) 101 | 102 | -------------------- 103 | [[ $- == *i* ]] && . /path/to/git-prompt.sh 104 | --------------------- 105 | 106 | There might be your old prompt defined too. You can comment it out. 107 | Some distros also have `/etc/bashrc` or `/etc/bash/bashrc` with distro default 108 | prompt. 109 | 110 | 111 | 112 | == GIT config 113 | 114 | GIT-PROMPT requires following GIT's option to be set: 115 | 116 | ------------------------- 117 | git config [--global] core.quotepath off 118 | git config [--global] --unset svn.pathnameencoding 119 | git config [--global] --unset i18n.logoutputencoding 120 | ----------------------------- 121 | 122 | 123 | == GIT-PROMPT config 124 | [[config]] 125 | 126 | Is optional. If config file is not found then git-prompt uses defaults. 127 | Defaults are listed in example `git-prompt.conf`. Git-prompt looks (in listed order) 128 | for config file in following locations: 129 | 130 | * `/etc/git-prompt.conf` 131 | * `~/.git-prompt.conf` 132 | 133 | Copy example config `git-prompt.conf` 134 | to any of above locations and customize as needed. 135 | 136 | 137 | == Limitations 138 | 139 | * cd-ing into something like linux kernel git working directory for the 1st 140 | time (with cold cache) might take up to 10 seconds (that is how long `git status` executes). 141 | Use `vcs_ignore_dir_list` in config if you want to ingnore such dirs. 142 | * Because you will be always reminded about dirty repo (not checked-in files), 143 | you will maintain `.gitignore` and commit more often. 144 | * This prompt is most useful if your screen have enough width. 145 | If this is not the case, you might want to disable file list display (`max_file_list_length=0`). 146 | * When prompt is longer than screen-width it wraps to second line. This is always undesirable. 147 | Because of bug in `gnome-terminal` (or `readline` ?) some color escape codes can be visible on second line. 148 | I've reported gnome-terminal bug. Again, you can disable file list display or limit length (`max_file_list_length`). 149 | * By default some terminals display ascii color with maximum color saturation 150 | which makes colored text of different perceptual brightness. This makes it hard to read. 151 | If your terminal colors are configurable, try change it to softer (pastel) 152 | colors. 153 | 154 | 155 | == Dependencies 156 | 157 | Most probably you don't need to install anything because not optional 158 | dependencies are standard unix utils. 159 | 160 | * bash (tested with v3.2.33) 161 | * sed 162 | * tput (terminfo) 163 | * tty (core utils) 164 | * grep 165 | * locale (glibc) 166 | * id (core utils) 167 | * cksum (core utils) 168 | 169 | * git (optional) 170 | * svn (optional) 171 | * hg (optional) 172 | 173 | 174 | == Todo 175 | 176 | * httpx://jonisalonen.com/2012/your-bash-prompt-needs-this/[] 177 | * httpx://tldp.org/HOWTO/Bash-Prompt-HOWTO/x810.html[Beep after long running command] 178 | * httpx://briancarper.net/blog/248/[Sync bash history] 179 | * VIM module needs to be moved out of GIT module 180 | 181 | include::../volnitsky.com/project/howto-submit-patch.txt[] 182 | 183 | Nobody will use git-prompt if there will be delay in prompt display. 184 | Try to avoid use of external commands and 185 | subshells (backticks) in prompt_command_function. It is ok to use 186 | time consuming ops in postconfig which is executed only once. 187 | 188 | == Authors 189 | - Leonid Volnitsky (original author) , http://volnitsky.com 190 | - Niklas Hofer (CWD truncation) , httpx://github.com/niklas/[] 191 | - Lee Nussbaum (HG support) , httpx://github.com/wln[] 192 | - Albert Vernon http://xenoclub.wordpress.com[] 193 | - Amir Yalon httpx://github.com/amiryal[] 194 | - Martin httpx://github.com/jerrywho[] 195 | - Alexander Goldstein (emacs-shell, prompt chars) httpx://github.com/alexg0[] 196 | - Dmitry (bash completion) 197 | - Sergey Shepelev 198 | - Robert Wahler 199 | - Gustavo Delfino 200 | - Dan Bravender 201 | - Thomas Geffert 202 | - Tibor Simko 203 | 204 | 205 | [bibliography] 206 | .References 207 | - [[[1]]] 'Bash Prompt HOWTO', http://tldp.org/HOWTO/Bash-Prompt-HOWTO/index.html 208 | - [[[2]]] 'BASH Frequently Asked Questions', http://mywiki.wooledge.org/BashFAQ 209 | 210 | -------------------------------------------------------------------------------- /screenshot-labels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvv/git-prompt/689cbbe4b4ae0f4cdf7c247d13982d589fdc54eb/screenshot-labels.png -------------------------------------------------------------------------------- /screenshot-labels.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvv/git-prompt/689cbbe4b4ae0f4cdf7c247d13982d589fdc54eb/screenshot-labels.xcf -------------------------------------------------------------------------------- /screenshot-prompt-basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvv/git-prompt/689cbbe4b4ae0f4cdf7c247d13982d589fdc54eb/screenshot-prompt-basic.png -------------------------------------------------------------------------------- /screenshot-prompt-git.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvv/git-prompt/689cbbe4b4ae0f4cdf7c247d13982d589fdc54eb/screenshot-prompt-git.png -------------------------------------------------------------------------------- /screenshot-svn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lvv/git-prompt/689cbbe4b4ae0f4cdf7c247d13982d589fdc54eb/screenshot-svn.png --------------------------------------------------------------------------------