Thursday, April 15, 2010

Improved Git-enabled Shell Prompt

In my previous post, I wrote about how you could bolster your shell prompt with Git status information.

Today, I added two more Git indicators that I find extremely useful while working on shared code.

The first is unmerged branches, which is the list of local branches that are not yet merged into the current branch.
# Returns "|unmerged:N" where N is the number of unmerged local and remote
# branches (if any).
function parse_git_unmerged {
  local unmerged=`expr $(git branch --no-color -a --no-merged | wc -l)`
  if [ "$unmerged" != "0" ]
  then
    echo "|unmerged:$unmerged"
  fi
}
The second is unpushed branches, which is the list of remote branches that are not synced to the local HEAD.
# Returns "|unpushed:N" where N is the number of unpushed local and remote
# branches (if any).
function parse_git_unpushed {
  local unpushed=`expr $( (git branch --no-color -r --contains HEAD; \
    git branch --no-color -r) | sort | uniq -u | wc -l )`
  if [ "$unpushed" != "0" ]
  then
    echo "|unpushed:$unpushed"
  fi
}
I now have the perfect git-enabled shell prompt!

Git-enabled Shell Prompt
The code to the full prompt is available here: prompt.sh (also see evilgit.sh for the git support functions). Enjoy!

2 comments:

  1. Hi,

    > local unmerged=`expr $(git branch --no-color -a --no-merged | wc -l)`

    I don't see why you need `expr` here. (--no-color is superfluous, too, btw)

    local unmerged=$(git branch --no-color -a --no-merged | wc -l)

    should do just fine.

    Mixing `` and $() is a bit weird, too. The benefit of $() is that it allows nesting, thus $(foo $(bar)). The only drawback is that not all shells support it (e.g. the bourne shell on older solaris, /bin/sh -- posix shell does, though).

    since you appear to not target that shell, you could also use [[ ]] instead of [ ] in the following snippets. those keep a couple of problems with empty arguments etc. away.

    > if [ "$unmerged" != "0" ]

    checking inequality of integers is done with -ne, thus

    if [ "$unmerged" -ne 0 ]

    or even

    if [[ $unmerged -ne 0 ]]

    > local unpushed=`expr $( (git branch --no-color -r --contains HEAD; git branch --no-color -r) | sort | uniq -u | wc -l )`

    you want branches to be printed that aren't shown by both `git branch --no-color -r --contains HEAD` and `git branch --no-color -r`. There's a program for that: comm(1) (you definitely have that if you're on linux). you could do

    > comm -3 <(git branch --no-color -r --contains HEAD | sort) <(git branch --no-color -r | sort) | wc -l

    that's a whole lot cleaner and clearer (assuming one is familiar with comm(1)).

    Thanks for giving me idea btw :)

    ReplyDelete
  2. Thanks for the bash lesson. :-)

    ReplyDelete