Git-aware PowerShell prompt

Today a colleague sent around an interesting link on how to put your git status in your bash prompt. I thought I’d spend a few minutes trying to get a similar effect in PowerShell (v2 CTP3). It’s not particularly useful, but I found it an interesting exercise. Here’s what I came up with, saved in GitAwarePrompt.ps1. Disclaimer: I know nothing about PowerShell so use anything from this post at your own risk. :)

function Get-GitBranchNameWithStatusIndicator {
$statusOutput = Invoke-Expression 'git status 2>$null'  #1
if (!$statusOutput) { return } #2$branch = $statusOutput[0] #3 if ($branch -eq "# Not currently on any branch.") {
$branch = "No branch" } else {$branch =  $branch.SubString("# On branch ".Length) }$statusSummary = $statusOutput[-1] #4 if ($statusSummary -eq "nothing to commit (working directory clean)") { #5
$statusIndicator = "" } else {$statusIndicator = "*"
}
return $branch +$statusIndicator
}

function prompt { #6
$gitStatus = Get-GitBranchNameWithStatusIndicator Write-Host ("PS " +$(get-location)) -nonewline
if ($gitStatus) { Write-Host (" [" +$gitStatus +"]") -nonewline -foregroundcolor Gray
}
Write-Host (">") -nonewline
return " "
}


I’ve put some numbered comments on a couple of lines so we can go through the main parts of the script, or you can skip to the next heading if you just want to try out the script.

Line #1 uses the Invoke-Expression commandlet to run the git status command and store the output in the local $statusOutput variable. We are using 2>$null to drop any output written to standard error, otherwise whenever we try and write a prompt in a non-git directory we’ll get a git error message appearing. You’ll also notice we have the git status 2>$null command surrounded by single quotes (‘), rather than double quotes ("). The reason is that PowerShell automatically performs variable substitution within double quoted strings. So if we used double quotes the $null would be replaced by with nothing (it’s current value), which will cause us no end of problems (go on, ask me how I know! :)).

If the git status command errors out (say, if the current directory is not in a git repo), then $gitStatus will be null. Line #2 checks for this and returns void if $statusOutput is undefined. Otherwise $statusOutput will an array of objects, with an item for each line of the command output. Line #3 grabs the first line of output, which contains a string which contains our branch name, and stores it in a variable. The if/else that follow checks first to make sure we are actually on a branch, and parses the branch name from the line. Line #4 was a nice surprise for me – PowerShell supports wrapped array indexing! Using an index of -1 grabs the last item in the array. Very pythonesque :). Line #5 then compares this with the output git status gives when there are no changes, and the rest of the if/else block sets the $statusIndicator based on this result. (No built in ternary operator apparently.)

Finally, line #6 defines a prompt function, which PowerShell uses to write it’s prompt.

Using the script

If we just run this script from within PowerShell it will do absolutely nothing. The reason is because any functions or variables defined will be cleaned up when the script exits. To change the scope and affect the current environment we need to dot-source the script, like this (depending on where you saved the script):