Basically I'm after this but for PowerShell instead of bash.
I use git on windows through PowerShell. If possible, I'd like my current branch name to displayed as part of the command prompt.
Basically I'm after this but for PowerShell instead of bash.
I use git on windows through PowerShell. If possible, I'd like my current branch name to displayed as part of the command prompt.
An easier way would be just installing the Powershell module posh-git. It comes out of the box with the desired prompt:
The Prompt
PowerShell generates its prompt by executing a prompt function, if one exists. posh-git defines such a function in profile.example.ps1 that outputs the current working directory followed by an abbreviated git status:
C:\Users\Keith [master]>
By default, the status summary has the following format:
[{HEAD-name} +A ~B -C !D | +E ~F -G !H]
(For installing posh-git I suggest using psget)
If you don't have psget use the following command:
(new-object Net.WebClient).DownloadString("https://raw.githubusercontent.com/psget/psget/master/GetPsGet.ps1") | iex
To install posh-git use the command:
Install-Module posh-git
To ensure posh-git loads for every shell, use the Add-PoshGitToProfile
command.
Import-Module posh-git
in my powershell profile. Worked like a charm! –
Jaquez choco install poshgit
from an elevated command prompt. –
Divaricate Here's my take on it. I've edited the colours a bit to make it more readable.
Microsoft.PowerShell_profile.ps1
function Write-BranchName () {
try {
$branch = git rev-parse --abbrev-ref HEAD
if ($branch -eq "HEAD") {
# we're probably in detached HEAD state, so print the SHA
$branch = git rev-parse --short HEAD
Write-Host " ($branch)" -ForegroundColor "red"
}
else {
# we're on an actual branch, so print it
Write-Host " ($branch)" -ForegroundColor "blue"
}
} catch {
# we'll end up here if we're in a newly initiated git repo
Write-Host " (no branches yet)" -ForegroundColor "yellow"
}
}
function prompt {
$base = "PS "
$path = "$($executionContext.SessionState.Path.CurrentLocation)"
$userPrompt = "$('>' * ($nestedPromptLevel + 1)) "
Write-Host "`n$base" -NoNewline
if (Test-Path .git) {
Write-Host $path -NoNewline -ForegroundColor "green"
Write-BranchName
}
else {
# we're not in a repo so don't bother displaying branch name/sha
Write-Host $path -ForegroundColor "green"
}
return $userPrompt
}
Example 1:
Example 2:
Microsoft.PowerShell_profile.ps1
file, located here (for your local user): $UserHome\[My ]Documents\PowerShell` For me, because I have OneDrive integrated into my machine, it was located here:
C:\Users\<USER>\OneDrive - \Documents\WindowsPowerShell` –
Hippo @Paul-
My PowerShell profile for Git is based off of a script I found here:
http://techblogging.wordpress.com/2008/10/12/displaying-git-branch-on-your-powershell-prompt/
I've modified it a bit to display the directory path and a bit of formatting. It also sets the path to my Git bin location since I use PortableGit.
# General variables
$pathToPortableGit = "D:\shared_tools\tools\PortableGit"
$scripts = "D:\shared_tools\scripts"
# Add Git executables to the mix.
[System.Environment]::SetEnvironmentVariable("PATH", $Env:Path + ";" + (Join-Path $pathToPortableGit "\bin") + ";" + $scripts, "Process")
# Setup Home so that Git doesn't freak out.
[System.Environment]::SetEnvironmentVariable("HOME", (Join-Path $Env:HomeDrive $Env:HomePath), "Process")
$Global:CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$UserType = "User"
$CurrentUser.Groups | foreach {
if ($_.value -eq "S-1-5-32-544") {
$UserType = "Admin" }
}
function prompt {
# Fun stuff if using the standard PowerShell prompt; not useful for Console2.
# This, and the variables above, could be commented out.
if($UserType -eq "Admin") {
$host.UI.RawUI.WindowTitle = "" + $(get-location) + " : Admin"
$host.UI.RawUI.ForegroundColor = "white"
}
else {
$host.ui.rawui.WindowTitle = $(get-location)
}
Write-Host("")
$status_string = ""
$symbolicref = git symbolic-ref HEAD
if($symbolicref -ne $NULL) {
$status_string += "GIT [" + $symbolicref.substring($symbolicref.LastIndexOf("/") +1) + "] "
$differences = (git diff-index --name-status HEAD)
$git_update_count = [regex]::matches($differences, "M`t").count
$git_create_count = [regex]::matches($differences, "A`t").count
$git_delete_count = [regex]::matches($differences, "D`t").count
$status_string += "c:" + $git_create_count + " u:" + $git_update_count + " d:" + $git_delete_count + " | "
}
else {
$status_string = "PS "
}
if ($status_string.StartsWith("GIT")) {
Write-Host ($status_string + $(get-location) + ">") -nonewline -foregroundcolor yellow
}
else {
Write-Host ($status_string + $(get-location) + ">") -nonewline -foregroundcolor green
}
return " "
}
So far, this has worked really well. While in a repo, the prompt happily looks like:
GIT [master] c:0 u:1 d:0 | J:\Projects\forks\fluent-nhibernate>
*NOTE: Updated with suggestions from Jakub Narębski.
git symbolic-ref HEAD
. Do not use git-status; it is meant for end user and is subject to change (it would change in 1.7.0). Use git-diff-files, git-diff-tree, git-diff-index. –
Limbert posh-git is slow, there's a better way with https://ohmyposh.dev/.
ohmyposh
module:Install-Module oh-my-posh -Scope CurrentUser -AllowPrerelease
install font that supports glyphs (icons) from https://www.nerdfonts.com/.
I like Meslo LGM NF.
set that font in powershell defaults settings:
Microsoft.PowerShell_profile.ps1
at C:\Program Files\PowerShell\7
and write below to set theme (same as screenshot):Set-PoshPrompt -Theme aliens
You can choose other theme also. see preview by running Get-PoshThemes
Now open powershell at location containing git repo and you'll see the status.
See more: Power up your PowerShell
With Git 2.22 (Q2 2019), any script (Powershell or not) could use the new --show-current
option.
$branch = git branch --show-current
If empty, it means "detached HEAD".
I tweaked the prompt code (from @david-longnecker answer) to be a bit more colorful.
Edit: June 2019 - Updated to show untracked, stashes, renames. Tweaked visual to show index.
Why I use this (over posh-git etc):
The powershell code:
NOTE: Some commands used are porcelain (not recommended for scripting/parsing, e.g. git status
). Will eventually migrate to plumbing commands, but this works for now.
Function Prompt {
$SYMBOL_GIT_BRANCH='⑂'
$SYMBOL_GIT_MODIFIED='*'
$SYMBOL_GIT_PUSH='↑'
$SYMBOL_GIT_PULL='↓'
if (git rev-parse --git-dir 2> $null) {
$symbolicref = $(git symbolic-ref --short HEAD 2>$NULL)
if ($symbolicref) {#For branches append symbol
$branch = $symbolicref.substring($symbolicref.LastIndexOf("/") +1)
$branchText=$SYMBOL_GIT_BRANCH + ' ' + $branch
} else {#otherwise use tag/SHA
$symbolicref=$(git describe --tags --always 2>$NULL)
$branch=$symbolicref
$branchText=$symbolicref
}
} else {$symbolicref = $NULL}
if ($symbolicref -ne $NULL) {
# Tweak:
# When WSL and Powershell terminals concurrently viewing same repo
# Stops from showing CRLF/LF differences as updates
git status > $NULL
#Do git fetch if no changes in last 10 minutes
# Last Reflog: Last time upstream was updated
# Last Fetch: Last time fetch/pull was ATTEMPTED
# Between the two can identify when last updated or attempted a fetch.
$MaxFetchSeconds = 600
$upstream = $(git rev-parse --abbrev-ref "@{upstream}")
$lastreflog = $(git reflog show --date=iso $upstream -n1)
if ($lastreflog -eq $NULL) {
$lastreflog = (Get-Date).AddSeconds(-$MaxFetchSeconds)
}
else {
$lastreflog = [datetime]$($lastreflog | %{ [Regex]::Matches($_, "{(.*)}") }).groups[1].Value
}
$gitdir = $(git rev-parse --git-dir)
$TimeSinceReflog = (New-TimeSpan -Start $lastreflog).TotalSeconds
if (Test-Path $gitdir/FETCH_HEAD) {
$lastfetch = (Get-Item $gitdir/FETCH_HEAD).LastWriteTime
$TimeSinceFetch = (New-TimeSpan -Start $lastfetch).TotalSeconds
} else {
$TimeSinceFetch = $MaxFetchSeconds + 1
}
#Write-Host "Time since last reflog: $TimeSinceReflog"
#Write-Host "Time since last fetch: $TimeSinceFetch"
if (($TimeSinceReflog -gt $MaxFetchSeconds) -AND ($TimeSinceFetch -gt $MaxFetchSeconds)) {
git fetch --all | Out-Null
}
#Identify stashes
$stashes = $(git stash list 2>$NULL)
if ($stashes -ne $NULL) {
$git_stashes_count=($stashes | Measure-Object -Line).Lines
}
else {$git_stashes_count=0}
#Identify how many commits ahead and behind we are
#by reading first two lines of `git status`
#Identify how many untracked files (matching `?? `)
$marks=$NULL
(git status --porcelain --branch 2>$NULL) | ForEach-Object {
If ($_ -match '^##') {
If ($_ -match 'ahead\ ([0-9]+)') {$git_ahead_count=[int]$Matches[1]}
If ($_ -match 'behind\ ([0-9]+)') {$git_behind_count=[int]$Matches[1]}
}
#Identify Added/UnTracked files
elseIf ($_ -match '^A\s\s') {
$git_index_added_count++
}
elseIf ($_ -match '^\?\?\ ') {
$git_untracked_count++
}
#Identify Modified files
elseIf ($_ -match '^MM\s') {
$git_index_modified_count++
$git_modified_count++
}
elseIf ($_ -match '^M\s\s') {
$git_index_modified_count++
}
elseIf ($_ -match '^\sM\s') {
$git_modified_count++
}
#Identify Renamed files
elseIf ($_ -match '^R\s\s') {
$git_index_renamed_count++
}
#Identify Deleted files
elseIf ($_ -match '^D\s\s') {
$git_index_deleted_count++
}
elseIf ($_ -match '^\sD\s') {
$git_deleted_count++
}
}
$branchText+="$marks"
}
if (test-path variable:/PSDebugContext) {
Write-Host '[DBG]: ' -nonewline -foregroundcolor Yellow
}
Write-Host "PS " -nonewline -foregroundcolor White
Write-Host $($executionContext.SessionState.Path.CurrentLocation) -nonewline -foregroundcolor White
if ($symbolicref -ne $NULL) {
Write-Host (" [ ") -nonewline -foregroundcolor Magenta
#Output the branch in prettier colors
If ($branch -eq "master") {
Write-Host ($branchText) -nonewline -foregroundcolor White
}
else {Write-Host $branchText -nonewline -foregroundcolor Red}
#Output commits ahead/behind, in pretty colors
If ($git_ahead_count -gt 0) {
Write-Host (" $SYMBOL_GIT_PUSH") -nonewline -foregroundcolor White
Write-Host ($git_ahead_count) -nonewline -foregroundcolor Green
}
If ($git_behind_count -gt 0) {
Write-Host (" $SYMBOL_GIT_PULL") -nonewline -foregroundcolor White
Write-Host ($git_behind_count) -nonewline -foregroundcolor Yellow
}
#Output staged changes count, if any, in pretty colors
If ($git_index_added_count -gt 0) {
Write-Host (" Ai:") -nonewline -foregroundcolor White
Write-Host ($git_index_added_count) -nonewline -foregroundcolor Green
}
If ($git_index_renamed_count -gt 0) {
Write-Host (" Ri:") -nonewline -foregroundcolor White
Write-Host ($git_index_renamed_count) -nonewline -foregroundcolor DarkGreen
}
If ($git_index_modified_count -gt 0) {
Write-Host (" Mi:") -nonewline -foregroundcolor White
Write-Host ($git_index_modified_count) -nonewline -foregroundcolor Yellow
}
If ($git_index_deleted_count -gt 0) {
Write-Host (" Di:") -nonewline -foregroundcolor White
Write-Host ($git_index_deleted_count) -nonewline -foregroundcolor Red
}
#Output unstaged changes count, if any, in pretty colors
If (($git_index_added_count) -OR ($git_index_modified_count) -OR ($git_index_deleted_count)) {
If (($git_modified_count -gt 0) -OR ($git_deleted_count -gt 0)) {
Write-Host (" |") -nonewline -foregroundcolor White
}
}
If ($git_modified_count -gt 0) {
Write-Host (" M:") -nonewline -foregroundcolor White
Write-Host ($git_modified_count) -nonewline -foregroundcolor Yellow
}
If ($git_deleted_count -gt 0) {
Write-Host (" D:") -nonewline -foregroundcolor White
Write-Host ($git_deleted_count) -nonewline -foregroundcolor Red
}
If (($git_untracked_count -gt 0) -OR ($git_stashes_count -gt 0)) {
Write-Host (" |") -nonewline -foregroundcolor White
}
If ($git_untracked_count -gt 0) {
Write-Host (" untracked:") -nonewline -foregroundcolor White
Write-Host ($git_untracked_count) -nonewline -foregroundcolor Red
}
If ($git_stashes_count -gt 0) {
Write-Host (" stashes:") -nonewline -foregroundcolor White
Write-Host ($git_stashes_count) -nonewline -foregroundcolor Yellow
}
Write-Host (" ]") -nonewline -foregroundcolor Magenta
}
$(Write-Host $('>' * ($nestedPromptLevel + 1)) -nonewline -foregroundcolor White)
return " "}#Powershell requires a return, otherwise defaults to factory prompt
The result (VSCode, Using Powershell terminal):
Here are commands from result to view what it would look like:
mkdir "c:\git\newrepo" | Out-Null
cd "c:\git\newrepo"
git init
"test" >> ".gitignore"
"test" >> ".gitignore2"
git add -A
git commit -m "test commit" | Out-Null
"test" >> ".gitignore1"
git add -A
"test1" >> ".gitignore2"
git rm .gitignore
git add -A
git commit -m "test commit2" | Out-Null
git checkout -b "newfeature1"
"test" >> ".test"
mv .gitignore1 .gitignore3
git add -A
git stash
git checkout "master"
cd c:\git\test #Just a sample repo had that was ahead 1 commit
#Remove-Item "c:\git\newrepo" -Recurse -Force #Cleanup
I like the accepted answer so I will elaborate on the steps to set it up.
You can install PoshGit using Chocolatey or using the PowerShellGet
command which is available for the new Core PowerShell.
For Chocolatey, you need to have it already installed before proceeding. In an administrator/elevated shell execute the command:
choco install poshgit
For Core PowerShell, installation is also required. To install Core PowerShell, execute the following command:
dotnet tool install --global PowerShell
NB: You need to have .NET Core SDK installed (latest version preferably)
After installing Core PowerShell, execute the command below to install PoshGit:
PowerShellGet\Install-Module posh-git -Scope CurrentUser -AllowPrerelease -Force
Using PoshGit requires you import it to the currently running shell environment using the command Import-Module posh-git. This means you have to run this command every time you open a new shell.
If you want PoshGit to be always available you should execute this command instead:
Add-PoshGitToProfile
Please note that PowerShell and Core PowerShell are different and as a result they run on different profiles. What this means is that if you want PoshGit to work for either of the shells you need to execute those commands in their respective shell environment.
I adapted @tamj0rd2 answer to further display the branch name in sub folders of the repository as well.
function Write-BranchName () {
try {
$branch = git rev-parse --abbrev-ref HEAD
if ($branch -eq "HEAD") {
# we're probably in detached HEAD state, so print the SHA
$branch = git rev-parse --short HEAD
Write-Host " ($branch)" -ForegroundColor "red"
}
else {
# we're on an actual branch, so print it
Write-Host " ($branch)" -ForegroundColor "blue"
}
} catch {
# we'll end up here if we're in a newly initiated git repo
Write-Host " (no branches yet)" -ForegroundColor "yellow"
}
}
function prompt {
$base = "PS "
$path = "$($executionContext.SessionState.Path.CurrentLocation)"
$userPrompt = "$('>' * ($nestedPromptLevel + 1)) "
Write-Host "`n$base" -NoNewline
if (! (git -C . rev-parse) ) {
Write-Host $path -NoNewline -ForegroundColor "green"
Write-BranchName
}
else {
# we're not in a repo so don't bother displaying branch name/sha
Write-Host $path -ForegroundColor "green"
}
return $userPrompt
}
See the diff:
- if (Test-Path .git) {
+ if (! (git -C . rev-parse) ) {
From @tamj0rd2's answer we can get the branch name to a string variable like this.
$branch = git rev-parse --abbrev-ref HEAD
echo $branch
Here is my configuration for PowerShell Core. just copy the function below and put it in your $PROFILE
function prompt {
try {
$GitBranch = git rev-parse --abbrev-ref HEAD
# we're probably in detached HEAD state, so print the SHA
if ($GitBranch -eq "HEAD") { $GitBranch = git rev-parse --short HEAD }
} catch {}
if ($GitBranch) { $GitBranch = " `e[33;93m[`e[33;96m$GitBranch`e[33;93m]`e[0m" }
"PS $pwd$GitBranch> "
}
I used a similar method to the one above from @tamj0rd2, but less complex.
Open: Microsoft.PowerShell_profile.ps1
Add First:
function Get-GitBranch {
if (Test-Path .git) {
$branch = git rev-parse --abbrev-ref HEAD
" [$branch]"
}
}
Add Second:
function prompt {
$p = Split-Path -leaf -path (Get-Location)
Write-Host "$p" -NoNewline
Write-Host (Get-GitBranch) -NoNewline -ForegroundColor Yellow
Write-Host "> " -NoNewline
return " "
}
How I achieved the reduced string or directory path is by using the split-path, so in total the prompt is:
function prompt {
$p = Split-Path -leaf -path (Get-Location)
Write-Host "$p" -NoNewline
Write-Host (Get-GitBranch) -NoNewline -ForegroundColor Yellow
Write-Host "> " -NoNewline
return " "
}
This was the simplest method for me on Windows 11 using the Terminal app. It works on a themed PowerShell, applies no styling, and displays the branch when in sub directories.
echo %profile
in powershellC:\Users\YourName\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
function prompt {
$gitBranch = & git rev-parse --abbrev-ref HEAD 2>$null
$promptString = "$PWD"
if ($gitBranch) {
$promptString += " ($gitBranch)"
}
"$promptString> "
}
© 2022 - 2024 — McMap. All rights reserved.
git branch --current
. – Seriatimgit branch --show-current
. Not sure if it was originally--current
, but as of 2023 it is the former. – Uprear--show-current
indeed. – Seriatim