GitPrompt.ps1

<#PSScriptInfo
 
.VERSION 0.1.0
 
.GUID 7546af34-156c-4109-b38c-0fb64e3fe385
 
.AUTHOR Kirill Lappo<dnaplayer@hotmail.com>
 
.COMPANYNAME Kira Lappo
 
.COPYRIGHT (c) 2019 Kirill Lappo. All rights reserved.
 
.TAGS git prompt ps-prompt git-prompt
 
.LICENSEURI https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
 
.PROJECTURI https://github.com/Kira-Lappo/git-prompt
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 0.1.0 - Initial release, testing purposes.
 
 .DESCRIPTION Allows you to bring a Git status to PowerShell prompt.
 Gracies to Mark Kembling
 https://markembling.info/2009/09/my-ideal-powershell-prompt-with-git-integration
 https://gist.github.com/markembling/180853
 Also thanks to git-prompt.sh creators
 https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh
#>


$STATUS_VALUE     = "__status"

function Get-GitStatus{
param(
    [String]
    [PARAMETER(Position=0,HelpMessage = "Git Status value")]
    $Format = $STATUS_VALUE)

    $directory = $pwd.Path;

    if (!(Test-DirectoryIsUnderGit -DirectoryPath $directory)){
        return "";
    }

    $status = Get-RepoStatus -DirectoryPath $directory
    $status = $Format.Replace($STATUS_VALUE, $status)

    return $status
}

class BranchSyncStatus {
    [Int] $Ahead
    [Int] $Behind
}

class RepoStatus {
    [string] $BranchName
    [string] $StageState
    [Int] $HitPoints
    [BranchSyncStatus] $BranchSyncStatus
}

function Test-DirectoryIsUnderGit {
    param (
        [string] $DirectoryPath
    )

    if (Test-Path "$DirectoryPath/.git") {
        return $TRUE
    }

    $parentDirectory = (Get-Item .).parent
    while ($parentDirectory) {
        $gitDirectory = "$($parentDirectory.fullname)/.git"
        if (Test-Path $gitDirectory) {
            return $TRUE
        }

        $parentDirectory = $parentDirectory.parent
    }

    return $FALSE
}

function Get-GitCurrentBranchName{
    return $(git describe --contains --all HEAD)
}

function Get-GitCurrentBranchUpstreamName {
    $description = $(git status -sb) | Select-Object -First 1
    return $description.Split("...") | Select-Object -Last 1
}

function Get-GitStageState {
    param (
        [string] $DirectoryPath
    )

    $state = "";

    if ($(git diff --name-only)){
        $state += "*";
    }

    if ($(git diff --name-only --staged)){
        $state += "+";
    }

    return $state
}

function Get-GitBranchSyncStatus {
    param (
        [string] $DirectoryPath
    )

    $syncState = [BranchSyncStatus]::new()

    $branchName = "HEAD"
    $upstreamName = "@{upstream}"

    $syncState.Ahead = (git rev-list --left-only "$branchName...$upstreamName" | Measure-Object).Count
    $syncState.Behind = (git rev-list --right-only "$branchName...$upstreamName" | Measure-Object).Count

    return $syncState;
}

function Get-RepoStatus {
    param (
        [string] $DirectoryPath
    )

    $result = Get-GitCurrentBranchName $DirectoryPath

    if (!$env:GIT_PS_SHOWDIRTYSTATE){
        return $result;
    }

    $stageState = Get-GitStageState $DirectoryPath
    if (![string]::IsNullOrWhiteSpace($stageState)){
        $result += " $stageState"
    }


    $branchSyncStatus = Get-GitBranchSyncStatus $DirectoryPath
    $syncState = ""
    if ($branchSyncStatus.Ahead -gt 0){
        $syncState += "up$($branchSyncStatus.Ahead)"
    }

    if ($branchSyncStatus.Behind -gt 0){
        $syncState += "down$($branchSyncStatus.Behind)"
    }

    if (![string]::IsNullOrWhiteSpace($syncState)){
        $result += " $syncState"
    }

    return $result
}