Blag

He's not dead, he's resting

Git and Subversion information in the Bash Prompt

Here’s my variation on the “Git and Subversion status in the bash prompt” thing:

ps_scm_f() {
    local s=
    if [[ -d ".svn" ]] ; then
        local r=$(svn info | sed -n -e '/^Revision: \([0-9]*\).*$/s//\1/p' )
        s="(r$r$(svn status | grep -q -v '^?' && echo -n "*" ))"
    else
        local d=$(git rev-parse --git-dir 2>/dev/null ) b= r= a=
        if [[ -n "${d}" ]] ; then
            if [[ -d "${d}/../.dotest" ]] ; then
                if [[ -f "${d}/../.dotest/rebase" ]] ; then
                    r="rebase"
                elif [[ -f "${d}/../.dotest/applying" ]] ; then
                    r="am"
                else
                    r="???"
                fi
                b=$(git symbolic-ref HEAD 2>/dev/null )
            elif [[ -f "${d}/.dotest-merge/interactive" ]] ; then
                r="rebase-i"
                b=$(<${d}/.dotest-merge/head-name)
            elif [[ -d "${d}/../.dotest-merge" ]] ; then
                r="rebase-m"
                b=$(<${d}/.dotest-merge/head-name)
            elif [[ -f "${d}/MERGE_HEAD" ]] ; then
                r="merge"
                b=$(git symbolic-ref HEAD 2>/dev/null )
            elif [[ -f "${d}/BISECT_LOG" ]] ; then
                r="bisect"
                b=$(git symbolic-ref HEAD 2>/dev/null )"???"
            else
                r=""
                b=$(git symbolic-ref HEAD 2>/dev/null )
            fi

            if git status | grep -q '^# Changed but not updated:' ; then
                a="${a}*"
            fi

            if git status | grep -q '^# Changes to be committed:' ; then
                a="${a}+"
            fi

            if git status | grep -q '^# Untracked files:' ; then
                a="${a}?"
            fi

            b=${b#refs/heads/}
            b=${b// }
            [[ -n "${r}${b}${a}" ]] && s="(${r:+${r}:}${b}${a:+ ${a}})"
        fi
    fi
    s="${s}${ACTIVE_COMPILER}"
    s="${s:+${s} }"
    echo -n "$s"
}

This is added to PS1 as normal.

For Subversion, it gives us the revision, and a * if anything’s been modified.

For Git, we get quite a bit more. If we’re in the middle of a merge, interactive rebase or am, we get told so. If we’re in the middle of a bisect, we get question marks, since I’ve not had to bisect anything since I wrote that code and I haven’t implemented anything fancy for it. We also get the branch, and a combination of * for changed but not updated files, + for changed and committed files and ? for untracked files.

It’s generally sufficiently fast to not be annoying, although the initial cd into a large project can take a few seconds. It’s probably possible to drop to a single ‘git status’ call if performance matters, although the kernel does a pretty good job of speeding up subsequent runs.

Advertisements

4 responses to “Git and Subversion information in the Bash Prompt

  1. CuleX July 27, 2008 at 6:49 am

    Is something like this available for mercurial, too? It looks very git specific and I’m not really experienced in mercurial/git, so i cannot “translate” the commands.

    Thank you

  2. Ciaran McCreesh July 27, 2008 at 1:02 pm

    It’s probably doable, but as I have no reason to use mercurial I can’t tell you how.

  3. CuleX July 28, 2008 at 7:46 am

    I wrote something for mercurial now, however, it’s fairly simple, but sure clearifies the state of the directory. It’s based on the Z-Shell, i’m sorry if i used any zsh-only functions to increase performance (Yes, Mercurial isn’t blazing fast). Bash users can rename the function and use it in their Prompt. However, if your home directory is under version control you shouldn’t use this, as it will notably slow down the prompt creation by around 0.6 seconds. Use p2 as mercurial-revision display variable for your prompt. Eg: PROMPT=”someprompt”$p2″somemoreprompt”

    precmd() {
    if [ $(hg root 2>/dev/null) ] ; then
    local r=$(hg log | head -n1 | awk ‘{print $2}’ | cut -f1 -d:) c=
    hg status >>(grep -q ‘^A .*’ && c=”${c}+”) \
    >>(grep -q ‘^M .*’ && c=”${c}*”) \
    >>(grep -q ‘^R .*’ && c=”${c}-“) \
    >>(grep -q ‘^\? .*’ && c=”${c}?”)
    if [[ -n $c ]] ; then
    c=” ${c}”
    fi
    export p2=”(r$r$c)”
    fi
    PROMPT=${p1}${p2}${p3}
    }

  4. Antti Kaihola September 18, 2008 at 6:08 am

    To get a space between the opening parenthesis of the scm info, replace both instances of
    s=”(
    with
    s=” (

    Some git-only solutions are here:
    http://unboundimagination.com/Current-Git-Branch-in-Bash-Prompt

    Git also includes a bash completion library with a __git_ps1 function you can include in your PS1.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s