private/functions/Get-PowerStubGitInfo.ps1
|
<# .SYNOPSIS Gets Git repository information for a given path. .DESCRIPTION Checks if a path is part of a Git repository and returns repository details including the remote URL and status information. Uses git -C to avoid changing the current working directory. .PARAMETER Path The path to check for Git repository information. .PARAMETER Fetch If specified, fetches the tracking remote before calculating ahead/behind counts. A failed fetch makes the status unavailable, rather than using stale counts. .OUTPUTS PSCustomObject with properties: - IsRepo: Boolean indicating if path is in a git repo - RepoRoot: The root path of the repository - RemoteUrl: The tracking remote URL, or origin URL when no upstream is configured - CurrentBranch: The current branch name - TrackingBranch: The upstream branch (if any) - BehindCount / AheadCount: Commit counts, or null when status is unavailable - Status: Ready, NotRepository, NoRemote, NoUpstream, FetchFailed or StatusFailed - StatusMessage: Explanation when status is unavailable .EXAMPLE Get-PowerStubGitInfo -Path "C:\MyRepo" #> function Get-PowerStubGitInfo { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Path, [Parameter()] [switch]$Fetch ) $result = [PSCustomObject]@{ IsRepo = $false RepoRoot = $null RemoteUrl = $null CurrentBranch = $null TrackingBranch = $null BehindCount = $null AheadCount = $null Status = 'NotRepository' StatusMessage = 'Path is not a Git repository' } if (-not $Script:GitAvailable -or -not (Test-Path -LiteralPath $Path)) { return $result } # Handle expected native failures ourselves, regardless of the caller's preference. $PSNativeCommandUseErrorActionPreference = $false try { $repoRoot = git -C $Path rev-parse --show-toplevel 2>$null if ($LASTEXITCODE -ne 0 -or -not $repoRoot) { return $result } $result.IsRepo = $true $result.RepoRoot = $repoRoot $result.Status = 'StatusFailed' $result.StatusMessage = 'Unable to determine repository status' $currentBranch = git -C $Path rev-parse --abbrev-ref HEAD 2>$null if ($LASTEXITCODE -ne 0 -or -not $currentBranch) { return $result } $result.CurrentBranch = $currentBranch $trackingRemote = git -C $Path config --get "branch.$currentBranch.remote" 2>$null if ($LASTEXITCODE -gt 1) { return $result } $trackingRef = git -C $Path config --get "branch.$currentBranch.merge" 2>$null if ($LASTEXITCODE -gt 1) { return $result } $remoteName = if ($trackingRemote) { $trackingRemote } else { 'origin' } if ($remoteName -eq '.') { # Git also allows an upstream in this same repository. $result.RemoteUrl = '.' } else { $remoteUrl = git -C $Path config --get "remote.$remoteName.url" 2>$null if ($LASTEXITCODE -gt 1) { return $result } $result.RemoteUrl = $remoteUrl } if (-not $result.RemoteUrl) { $result.Status = 'NoRemote' $result.StatusMessage = "No remote configured for repository ('$remoteName')" return $result } if (-not $trackingRemote -or -not $trackingRef -or $currentBranch -eq 'HEAD') { $result.Status = 'NoUpstream' $result.StatusMessage = 'No tracking branch configured for the current branch' return $result } if ($Fetch) { # A status check must never wait on a credential prompt. $savedTerminalPrompt = $env:GIT_TERMINAL_PROMPT $savedGcmInteractive = $env:GCM_INTERACTIVE $env:GIT_TERMINAL_PROMPT = '0' $env:GCM_INTERACTIVE = 'never' $fetchSucceeded = $false try { git -C $Path fetch $remoteName --quiet 2>$null $fetchSucceeded = $LASTEXITCODE -eq 0 } catch { $fetchSucceeded = $false } finally { $env:GIT_TERMINAL_PROMPT = $savedTerminalPrompt $env:GCM_INTERACTIVE = $savedGcmInteractive } if (-not $fetchSucceeded) { $result.Status = 'FetchFailed' $result.StatusMessage = 'Fetch failed; remote status could not be checked' return $result } } $trackingBranch = git -C $Path rev-parse --abbrev-ref '@{upstream}' 2>$null if ($LASTEXITCODE -ne 0 -or -not $trackingBranch) { return $result } $result.TrackingBranch = $trackingBranch $countOutput = git -C $Path rev-list --left-right --count "$trackingBranch...HEAD" 2>$null if ($LASTEXITCODE -ne 0 -or -not $countOutput) { return $result } $counts = "$countOutput".Trim() -split '\s+' $behindCount = 0 $aheadCount = 0 if ($counts.Count -ne 2 -or -not [int]::TryParse($counts[0], [ref]$behindCount) -or $behindCount -lt 0 -or -not [int]::TryParse($counts[1], [ref]$aheadCount) -or $aheadCount -lt 0) { return $result } $result.BehindCount = $behindCount $result.AheadCount = $aheadCount $result.Status = 'Ready' $result.StatusMessage = $null } catch { $result.Status = 'StatusFailed' $result.StatusMessage = "Unable to determine repository status: $($_.Exception.Message)" } return $result } |