Skip to content

Instantly share code, notes, and snippets.

@jdharmon
Last active April 2, 2025 18:21
Show Gist options
  • Save jdharmon/c317da2c95af8f4e126f84d0b705e16d to your computer and use it in GitHub Desktop.
Save jdharmon/c317da2c95af8f4e126f84d0b705e16d to your computer and use it in GitHub Desktop.
One-page PowerShell Git Prompt. Alternative to posh-git.
# Add to PowerShell $PROFILE
function Get-GitPrompt {
$inGitRepo = [bool](git rev-parse --is-inside-work-tree 2>$null)
if (-not $inGitRepo) {
return
}
$branch = git branch --show-current
$status = git status --short --branch
$statusLine = ([string[]]$status)[0]
if ($statusLine -match '\.\.\.(?<remote>\S+)( \[(ahead (?<ahead>\d+))?((, )?behind (?<behind>\d+))?\])?') {
$remoteStatus = ' '
if ($Matches['ahead']) {
$remoteStatus += "↑$($Matches['ahead'])"
}
if ($Matches['behind']) {
$remoteStatus += "↓$($Matches['behind'])"
}
if ([string]::IsNullOrWhiteSpace($remoteStatus)) {
$remoteStatus += '≡'
}
} else {
$remoteStatus = ''
}
$stagedChanges = ($status | Select-String '^M' | Measure-Object).Count
$unstagedChanges = ($status | Select-String '^ M' | Measure-Object).Count
$stagedAdds = ($status | Select-String '^A' | Measure-Object).Count
$unstagedAdds = ($status | Select-String '^\?\?' | Measure-Object).Count
$stagedDeletes = ($status | Select-String '^D' | Measure-Object).Count
$unstagedDeletes = ($status | Select-String '^ D' | Measure-Object).Count
$e=$([char]0x1b)
if ($remoteStatus.Contains('↑') -and $remoteStatus.Contains('↓')) {
$branch = "$e[93m$branch" # Yellow
} elseif ($remoteStatus.Contains('↑')) {
$branch = "$e[92m$branch" # Green
} elseif ($remoteStatus.Contains('↓')) {
$branch = "$e[91m$branch" # Red
} else {
$branch = "$e[96m$branch" # Blue
}
if ($stagedChanges -ne '0' -or $stagedAdds -ne '0' -or $stagedDeletes -ne '0') {
$staged = " $e[32m+$stagedAdds ~$stagedChanges -$stagedDeletes"
}
if ($unstagedChanges -ne '0' -or $unstagedAdds -ne '0' -or $unstagedDeletes -ne '0') {
$unstaged = " $e[31m+$unstagedAdds ~$unstagedChanges -$unstagedDeletes"
}
if ($staged -and $unstaged) {
$separator = " $e93m|"
}
$prompt = "$e[93m[$e0m$branch$remoteStatus$staged$separator$unstaged$e[93m]$e[0m"
if ($host.UI.SupportsVirtualTerminal) {
return $prompt
} else {
return $prompt -replace '\x1b\[\d+m', ''
}
}
function prompt {
$gitPrompt = Get-GitPrompt
if ($gitPrompt) {
$Host.UI.RawUI.WindowTitle = "$(Split-Path -Leaf $PWD) $gitPrompt" -replace '\x1b\[\d+m', ''
"PS ${PWD} $gitPrompt> "
} else {
$Host.UI.RawUI.WindowTitle = $PWD
"PS ${PWD}> "
}
}
# Command completion
Register-ArgumentCompleter -Native -CommandName git -ScriptBlock {
param([string]$wordToComplete, [string]$commandAst, [int]$cursorPosition)
$command = $commandAst.Split(' ', [StringSplitOptions]::RemoveEmptyEntries)
$options = switch -Regex ($command[1]) {
'branch|checkout|merge' { git branch --list "${wordToComplete}*" | Where-Object { -not $_.StartsWith('*') } }
default { (git --list-cmds=main) -match "^${wordToComplete}" }
}
$options | ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_.Trim(), $_.Trim(), 'ParameterValue', $_.Trim())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment