path.c: refactor relative_path(), not only strip prefix
[gitweb.git] / contrib / completion / git-prompt.sh
index a8b53ba5f3ed1e34acfdae99bb218223ba9f40f0..eaf5c369aacde207cbad4c9df9574e7b26634bb7 100644 (file)
 #    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
 #    2) Add the following line to your .bashrc/.zshrc:
 #        source ~/.git-prompt.sh
-#    3a) In ~/.bashrc set PROMPT_COMMAND=__git_ps1
-#        To customize the prompt, provide start/end arguments
-#        PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
-#    3b) Alternatively change your PS1 to call __git_ps1 as
+#    3a) Change your PS1 to call __git_ps1 as
 #        command-substitution:
 #        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
 #        ZSH:  PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
-#        the optional argument will be used as format string
+#        the optional argument will be used as format string.
+#    3b) Alternatively, if you are using bash, __git_ps1 can be
+#        used for PROMPT_COMMAND with two parameters, <pre> and
+#        <post>, which are strings you would put in $PS1 before
+#        and after the status string generated by the git-prompt
+#        machinery.  e.g.
+#           PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
+#        will show username, at-sign, host, colon, cwd, then
+#        various status string, followed by dollar and SP, as
+#        your prompt.
+#        Optionally, you can supply a third argument with a printf
+#        format string to finetune the output of the branch status
 #
 # The argument to __git_ps1 will be displayed only if you are currently
 # in a git repository.  The %s token will be the name of the current
 #
 # If you would like to see if there're untracked files, then you can set
 # GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
-# files, then a '%' will be shown next to the branch name.
+# files, then a '%' will be shown next to the branch name.  You can
+# configure this per-repository with the bash.showUntrackedFiles
+# variable, which defaults to true once GIT_PS1_SHOWUNTRACKEDFILES is
+# enabled.
 #
 # If you would like to see the difference between HEAD and its upstream,
 # set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
@@ -216,10 +227,12 @@ __git_ps1_show_upstream ()
 # when called from PS1 using command substitution
 # in this mode it prints text to add to bash PS1 prompt (includes branch name)
 #
-# __git_ps1 requires 2 arguments when called from PROMPT_COMMAND (pc)
+# __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc)
 # in that case it _sets_ PS1. The arguments are parts of a PS1 string.
-# when both arguments are given, the first is prepended and the second appended
+# when two arguments are given, the first is prepended and the second appended
 # to the state string when assigned to PS1.
+# The optional third parameter will be used as printf format string to further
+# customize the output of the git-status string.
 # In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
 __git_ps1 ()
 {
@@ -230,9 +243,10 @@ __git_ps1 ()
        local printf_format=' (%s)'
 
        case "$#" in
-               2)      pcmode=yes
+               2|3)    pcmode=yes
                        ps1pc_start="$1"
                        ps1pc_end="$2"
+                       printf_format="${3:-$printf_format}"
                ;;
                0|1)    printf_format="${1:-$printf_format}"
                ;;
@@ -249,14 +263,21 @@ __git_ps1 ()
        else
                local r=""
                local b=""
-               if [ -f "$g/rebase-merge/interactive" ]; then
-                       r="|REBASE-i"
-                       b="$(cat "$g/rebase-merge/head-name")"
-               elif [ -d "$g/rebase-merge" ]; then
-                       r="|REBASE-m"
+               local step=""
+               local total=""
+               if [ -d "$g/rebase-merge" ]; then
                        b="$(cat "$g/rebase-merge/head-name")"
+                       step=$(cat "$g/rebase-merge/msgnum")
+                       total=$(cat "$g/rebase-merge/end")
+                       if [ -f "$g/rebase-merge/interactive" ]; then
+                               r="|REBASE-i"
+                       else
+                               r="|REBASE-m"
+                       fi
                else
                        if [ -d "$g/rebase-apply" ]; then
+                               step=$(cat "$g/rebase-apply/next")
+                               total=$(cat "$g/rebase-apply/last")
                                if [ -f "$g/rebase-apply/rebasing" ]; then
                                        r="|REBASE"
                                elif [ -f "$g/rebase-apply/applying" ]; then
@@ -268,6 +289,8 @@ __git_ps1 ()
                                r="|MERGING"
                        elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
                                r="|CHERRY-PICKING"
+                       elif [ -f "$g/REVERT_HEAD" ]; then
+                               r="|REVERTING"
                        elif [ -f "$g/BISECT_LOG" ]; then
                                r="|BISECTING"
                        fi
@@ -292,6 +315,10 @@ __git_ps1 ()
                        }
                fi
 
+               if [ -n "$step" ] && [ -n "$total" ]; then
+                       r="$r $step/$total"
+               fi
+
                local w=""
                local i=""
                local s=""
@@ -306,24 +333,25 @@ __git_ps1 ()
                                b="GIT_DIR!"
                        fi
                elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then
-                       if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then
-                               if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then
-                                       git diff --no-ext-diff --quiet --exit-code || w="*"
-                                       if git rev-parse --quiet --verify HEAD >/dev/null; then
-                                               git diff-index --cached --quiet HEAD -- || i="+"
-                                       else
-                                               i="#"
-                                       fi
+                       if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
+                          [ "$(git config --bool bash.showDirtyState)" != "false" ]
+                       then
+                               git diff --no-ext-diff --quiet --exit-code || w="*"
+                               if git rev-parse --quiet --verify HEAD >/dev/null; then
+                                       git diff-index --cached --quiet HEAD -- || i="+"
+                               else
+                                       i="#"
                                fi
                        fi
                        if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then
                                git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$"
                        fi
 
-                       if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then
-                               if [ -n "$(git ls-files --others --exclude-standard)" ]; then
-                                       u="%"
-                               fi
+                       if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
+                          [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
+                          [ -n "$(git ls-files --others --exclude-standard)" ]
+                       then
+                               u="%${ZSH_VERSION+%}"
                        fi
 
                        if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
@@ -333,6 +361,7 @@ __git_ps1 ()
 
                local f="$w$i$s$u"
                if [ $pcmode = yes ]; then
+                       local gitstring=
                        if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
                                local c_red='\e[31m'
                                local c_green='\e[32m'
@@ -350,29 +379,31 @@ __git_ps1 ()
                                        branch_color="$bad_color"
                                fi
 
-                               # Setting PS1 directly with \[ and \] around colors
+                               # Setting gitstring directly with \[ and \] around colors
                                # is necessary to prevent wrapping issues!
-                               PS1="$ps1pc_start (\[$branch_color\]$branchstring\[$c_clear\]"
+                               gitstring="\[$branch_color\]$branchstring\[$c_clear\]"
 
                                if [ -n "$w$i$s$u$r$p" ]; then
-                                       PS1="$PS1 "
+                                       gitstring="$gitstring "
                                fi
                                if [ "$w" = "*" ]; then
-                                       PS1="$PS1\[$bad_color\]$w"
+                                       gitstring="$gitstring\[$bad_color\]$w"
                                fi
                                if [ -n "$i" ]; then
-                                       PS1="$PS1\[$ok_color\]$i"
+                                       gitstring="$gitstring\[$ok_color\]$i"
                                fi
                                if [ -n "$s" ]; then
-                                       PS1="$PS1\[$flags_color\]$s"
+                                       gitstring="$gitstring\[$flags_color\]$s"
                                fi
                                if [ -n "$u" ]; then
-                                       PS1="$PS1\[$bad_color\]$u"
+                                       gitstring="$gitstring\[$bad_color\]$u"
                                fi
-                               PS1="$PS1\[$c_clear\]$r$p)$ps1pc_end"
+                               gitstring="$gitstring\[$c_clear\]$r$p"
                        else
-                               PS1="$ps1pc_start ($c${b##refs/heads/}${f:+ $f}$r$p)$ps1pc_end"
+                               gitstring="$c${b##refs/heads/}${f:+ $f}$r$p"
                        fi
+                       gitstring=$(printf -- "$printf_format" "$gitstring")
+                       PS1="$ps1pc_start$gitstring$ps1pc_end"
                else
                        # NO color option unless in PROMPT_COMMAND mode
                        printf -- "$printf_format" "$c${b##refs/heads/}${f:+ $f}$r$p"