Skip to content

My Ideal Powershell Prompt with Git Integration

I have become quite fond of Powershell lately and enjoy its flexibility. As part of this flexibility, it has impressive scope for customisation and modification similar to Bash (although arguably in a much nicer way). My main bugbear with the default installation of Powershell is the horrible prompt you are provided with. As such, I have modified my prompt to better suit my needs including useful details about the git repository when within one.

The Git part of my prompt is inspired by this blog post, but with some of my own ideas and tweaks. It's also worth noting that like others, I use the excellent Console app, which makes a much nicer host application for Powershell (and cmd.exe, bash, etc).

So What Does It Look Like?

My standard (non-git) prompt looks like this:

I decided to make it closer resemble the standard bash prompt as I find it useful. It shows my username, the machine name and the current folder I am inside. This is good for me as I regularly SSH into other machines (which have a similar prompt) and this makes it easy to see at a glance what machine I am connected to and where on the filesystem I am at present. I also find it useful to set the title to the same information, as can be seen in the tab at the top of the Console window.

When I move into a git repository I have cloned (or created) on my machine, the prompt grows to show me some useful information about my repository clone:

In addition to my standard prompt, I now have the git branch name and number of files added (+), edited (~) and deleted (-) shown. The branch name also changes colour depending on the status: if I have made no commits since cloning (i.e. my branch is not ahead of that on origin), the branch name is shown in cyan. If I have made additional commits (and my branch is therefore ahead of that on origin), the branch name changes to red. This is to remind me to push my branch back up to origin when I am done. Of course, if there is no remote, it will never change colour. Also, if additional files have been created but are not yet tracked, an exclamation point (!) will appear at the end of the prompt to show the presence of untracked files.

Nuts and Bolts

So now onto the good stuff - how it's done. Powershell uses a profile.ps1 (or Microsoft.Powershell_profile.ps1) file within your ~/Documents/WindowsPowershell directory to determine what happens to your Powershell. It is pretty much equivalent to Bash's ~/bash_profile file. In order to change the prompt, we simply create a function called prompt, and do whatever we want in here.

I have split mine into two files: profile.ps1 which defines the prompt function and actually decides what should be shown, and gitutils.ps1 which contains a couple of functions for gathering the git information. I have made them both available as gists on GitHub and these can be dropped straight into your ~/Documents/WindowsPowershell directory.

The Code

gitutils.ps1

# Git functions for PowerShell
# Copyright 2009-2019 Mark Embling (http://www.markembling.info/)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# Is the current directory a git repository/working copy?
function isCurrentDirectoryGitRepository {
if ((Test-Path ".git") -eq $TRUE) {
return $TRUE
}
# Test within parent dirs
$checkIn = (Get-Item .).parent
while ($checkIn -ne $NULL) {
$pathToTest = $checkIn.fullname + '/.git'
if ((Test-Path $pathToTest) -eq $TRUE) {
return $TRUE
} else {
$checkIn = $checkIn.parent
}
}
return $FALSE
}
# Get the current branch
function gitBranchName {
$currentBranch = ''
git branch | foreach {
if ($_ -match "^\* (.*)") {
$currentBranch += $matches[1]
}
}
return $currentBranch
}
# Extracts status details about the repo
function gitStatus {
$untracked = $FALSE
$added = 0
$modified = 0
$deleted = 0
$ahead = $FALSE
$aheadCount = 0
$output = git status
$branchbits = $output[0].Split(' ')
$branch = $branchbits[$branchbits.length - 1]
$output | foreach {
if ($_ -match "^\#.*origin/.*' by (\d+) commit.*") {
$aheadCount = $matches[1]
$ahead = $TRUE
}
elseif ($_ -match "deleted:") {
$deleted += 1
}
elseif (($_ -match "modified:") -or ($_ -match "renamed:")) {
$modified += 1
}
elseif ($_ -match "new file:") {
$added += 1
}
elseif ($_ -match "Untracked files:") {
$untracked = $TRUE
}
}
return @{"untracked" = $untracked;
"added" = $added;
"modified" = $modified;
"deleted" = $deleted;
"ahead" = $ahead;
"aheadCount" = $aheadCount;
"branch" = $branch}
}
view raw gitutils.ps1 hosted with ❤ by GitHub

profile.ps1

# My preferred prompt for Powershell.
# Displays git branch and stats when inside a git repository.
# See http://gist.github.com/180853 for gitutils.ps1.
. (Resolve-Path ~/Documents/WindowsPowershell/gitutils.ps1)
function prompt {
$path = ""
$pathbits = ([string]$pwd).split("\", [System.StringSplitOptions]::RemoveEmptyEntries)
if($pathbits.length -eq 1) {
$path = $pathbits[0] + "\"
} else {
$path = $pathbits[$pathbits.length - 1]
}
$userLocation = $env:username + '@' + [System.Environment]::MachineName + ' ' + $path
$host.UI.RawUi.WindowTitle = $userLocation
Write-Host($userLocation) -nonewline -foregroundcolor Green
if (isCurrentDirectoryGitRepository) {
$status = gitStatus
$currentBranch = $status["branch"]
Write-Host(' [') -nonewline -foregroundcolor Yellow
if ($status["ahead"] -eq $FALSE) {
# We are not ahead of origin
Write-Host($currentBranch) -nonewline -foregroundcolor Cyan
} else {
# We are ahead of origin
Write-Host($currentBranch) -nonewline -foregroundcolor Red
}
Write-Host(' +' + $status["added"]) -nonewline -foregroundcolor Yellow
Write-Host(' ~' + $status["modified"]) -nonewline -foregroundcolor Yellow
Write-Host(' -' + $status["deleted"]) -nonewline -foregroundcolor Yellow
if ($status["untracked"] -ne $FALSE) {
Write-Host(' !') -nonewline -foregroundcolor Yellow
}
Write-Host(']') -nonewline -foregroundcolor Yellow
}
Write-Host('>') -nonewline -foregroundcolor Green
return " "
}
view raw profile.ps1 hosted with ❤ by GitHub

Summary

So there it is - my ideal fusion of Powershell, Git and the spirit of bash. Of course, my gigantic prompt might not suit all - I like it as it contains a lot of information, but it also uses a lot of screen space. The prompt function can be tweaked to shrink it up if necessary - the username@host part might not be for everyone.

You may have also noticed in my screenshots that all the colours appear a bit more pastel than normal - Console allows you to tweak the colours which are used for each of the 16 ANSI colours. However I did make sure it looks fine with the default Powershell colours too, and it does. Enjoy.