Skip to content

Commit 87e6832

Browse files
authored
Merge pull request #370 from rkeithhill/rkeithhill/is291-fix-bare-repo
Fix Get-GitDirectory to work in bare repo.
2 parents 73b8bf9 + a1bb28f commit 87e6832

7 files changed

+257
-37
lines changed

GitUtils.ps1

+56-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,53 @@
11
# Inspired by Mark Embling
22
# http://www.markembling.info/view/my-ideal-powershell-prompt-with-git-integration
33

4+
<#
5+
.SYNOPSIS
6+
Gets the path to the current repository's .git dir.
7+
.DESCRIPTION
8+
Gets the path to the current repository's .git dir. Or if the repository
9+
is a bare repository, the root directory of the bare repository.
10+
.EXAMPLE
11+
PS C:\GitHub\posh-git\tests> Get-GitDirectory
12+
Returns C:\GitHub\posh-git\.git
13+
.INPUTS
14+
None.
15+
.OUTPUTS
16+
System.String
17+
#>
418
function Get-GitDirectory {
5-
if ($Env:GIT_DIR) {
6-
$Env:GIT_DIR
19+
$pathInfo = Microsoft.PowerShell.Management\Get-Location
20+
if (!$pathInfo -or ($pathInfo.Provider.Name -ne 'FileSystem')) {
21+
$null
22+
}
23+
elseif ($Env:GIT_DIR) {
24+
$Env:GIT_DIR -replace '\\|/', [System.IO.Path]::DirectorySeparatorChar
725
}
826
else {
9-
Get-LocalOrParentPath .git
27+
$currentDir = Get-Item $pathInfo -Force
28+
while ($currentDir) {
29+
$gitDirPath = Join-Path $currentDir.FullName .git
30+
if (Test-Path -LiteralPath $gitDirPath -PathType Container) {
31+
return $gitDirPath
32+
}
33+
34+
$headPath = Join-Path $currentDir.FullName HEAD
35+
if (Test-Path -LiteralPath $headPath -PathType Leaf) {
36+
$refsPath = Join-Path $currentDir.FullName refs
37+
$objsPath = Join-Path $currentDir.FullName objects
38+
if ((Test-Path -LiteralPath $refsPath -PathType Container) -and
39+
(Test-Path -LiteralPath $objsPath -PathType Container)) {
40+
41+
$bareDir = Invoke-Utf8ConsoleCommand { git rev-parse --git-dir 2>$null }
42+
if ($bareDir -and (Test-Path -LiteralPath $bareDir -PathType Container)) {
43+
$resolvedBareDir = (Resolve-Path $bareDir).Path
44+
return $resolvedBareDir
45+
}
46+
}
47+
}
48+
49+
$currentDir = $currentDir.Parent
50+
}
1051
}
1152
}
1253

@@ -147,7 +188,7 @@ function Get-GitStatus($gitDir = (Get-GitDirectory)) {
147188
$filesUnmerged = New-Object System.Collections.Generic.List[string]
148189
$stashCount = 0
149190

150-
if($settings.EnableFileStatus -and !$(InDisabledRepository)) {
191+
if($settings.EnableFileStatus -and !$(InDotGitOrBareRepoDir $gitDir) -and !$(InDisabledRepository)) {
151192
if ($settings.EnableFileStatusFromCache -eq $null) {
152193
$settings.EnableFileStatusFromCache = (Get-Module GitStatusCachePoshClient) -ne $null
153194
}
@@ -290,6 +331,17 @@ function InDisabledRepository {
290331
return $false
291332
}
292333

334+
function InDotGitOrBareRepoDir([string][ValidateNotNullOrEmpty()]$GitDir) {
335+
# A UNC path has no drive so it's better to use the ProviderPath e.g. "\\server\share".
336+
# However for any path with a drive defined, it's better to use the Path property.
337+
# In this case, ProviderPath is "\LocalMachine\My"" whereas Path is "Cert:\LocalMachine\My".
338+
# The latter is more desirable.
339+
$pathInfo = Microsoft.PowerShell.Management\Get-Location
340+
$currentPath = if ($pathInfo.Drive) { $pathInfo.Path } else { $pathInfo.ProviderPath }
341+
$res = $currentPath.StartsWith($GitDir, (Get-PathStringComparison))
342+
$res
343+
}
344+
293345
function Enable-GitColors {
294346
Write-Warning 'Enable-GitColors is Obsolete and will be removed in a future version of posh-git.'
295347
}

Utils.ps1

+20-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Need this variable as long as we support PS v2
22
$ModuleBasePath = Split-Path $MyInvocation.MyCommand.Path -Parent
33

4+
# Store error records generated by stderr output when invoking an executable
5+
# This can be accessed from the user's session by executing:
6+
# PS> $m = Get-Module posh-git
7+
# PS> & $m Get-Variable invokeErrors -ValueOnly
8+
$invokeErrors = New-Object System.Collections.ArrayList 256
9+
410
# General Utility Functions
511

612
function Invoke-NullCoalescing {
@@ -21,12 +27,26 @@ Set-Alias ?? Invoke-NullCoalescing -Force
2127

2228
function Invoke-Utf8ConsoleCommand([ScriptBlock]$cmd) {
2329
$currentEncoding = [Console]::OutputEncoding
30+
$errorCount = $global:Error.Count
2431
try {
32+
# A native executable that writes to stderr AND has its stderr redirected will generate non-terminating
33+
# error records if the user has set $ErrorActionPreference to Stop. Override that value in this scope.
34+
$ErrorActionPreference = 'Continue'
2535
[Console]::OutputEncoding = [Text.Encoding]::UTF8
2636
& $cmd
2737
}
2838
finally {
2939
[Console]::OutputEncoding = $currentEncoding
40+
41+
# Clear out stderr output that was added to the $Error collection, putting those errors in a module variable
42+
if ($global:Error.Count -gt $errorCount) {
43+
$numNewErrors = $global:Error.Count - $errorCount
44+
$invokeErrors.InsertRange(0, $global:Error.GetRange(0, $numNewErrors))
45+
if ($invokeErrors.Count -gt 256) {
46+
$invokeErrors.RemoveRange(256, ($invokeErrors.Count - 256))
47+
}
48+
$global:Error.RemoveRange(0, $numNewErrors)
49+
}
3050
}
3151
}
3252

@@ -163,23 +183,6 @@ function Get-PathStringComparison {
163183
}
164184
}
165185

166-
function Get-LocalOrParentPath($path) {
167-
$checkIn = Get-Item -Force .
168-
if ($checkIn.PSProvider.Name -ne 'FileSystem') {
169-
return $null
170-
}
171-
while ($null -ne $checkIn) {
172-
$pathToTest = [System.IO.Path]::Combine($checkIn.fullname, $path)
173-
if (Test-Path -LiteralPath $pathToTest) {
174-
return $pathToTest
175-
}
176-
else {
177-
$checkIn = $checkIn.parent
178-
}
179-
}
180-
return $null
181-
}
182-
183186
function Get-PSModulePath {
184187
$modulePaths = $Env:PSModulePath -split ';'
185188
$modulePaths

posh-git.psd1

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ FunctionsToExport = @(
2828
'Write-GitStatus',
2929
'Write-Prompt',
3030
'Write-VcsStatus',
31+
'Get-GitBranch',
3132
'Get-GitStatus',
3233
'Enable-GitColors',
3334
'Get-GitDirectory',

posh-git.psm1

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ $exportModuleMemberParams = @{
125125
'Write-GitStatus',
126126
'Write-Prompt',
127127
'Write-VcsStatus',
128+
'Get-GitBranch',
128129
'Get-GitStatus',
129130
'Enable-GitColors',
130131
'Get-GitDirectory',

test/Get-GitBranch.Tests.ps1

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
. $PSScriptRoot\Shared.ps1
2+
3+
Describe 'Get-GitBranch Tests' {
4+
Context 'Get-GitBranch GIT_DIR Tests' {
5+
It 'Returns GIT_DIR! when in .git dir of the repo' {
6+
$repoRoot = (Resolve-Path $PSScriptRoot\..).Path
7+
Set-Location $repoRoot\.git -ErrorAction Stop
8+
Get-GitBranch | Should BeExactly 'GIT_DIR!'
9+
}
10+
It 'Returns correct path when in a child folder of the .git dir of the repo' {
11+
$repoRoot = (Resolve-Path $PSScriptRoot\..).Path
12+
Set-Location $repoRoot\.git\hooks -ErrorAction Stop
13+
Get-GitBranch | Should BeExactly 'GIT_DIR!'
14+
}
15+
}
16+
}

test/Get-GitDirectory.Tests.ps1

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
. $PSScriptRoot\Shared.ps1
2+
3+
Describe 'Get-GitDiretory Tests' {
4+
Context "Test normal repository" {
5+
BeforeAll {
6+
$origPath = Get-Location
7+
}
8+
AfterAll {
9+
Set-Location $origPath
10+
}
11+
12+
It 'Returns $null for not a Git repo' {
13+
Set-Location $env:windir
14+
Get-GitDirectory | Should BeNullOrEmpty
15+
}
16+
It 'Returns $null for not a filesystem path' {
17+
Set-Location Cert:\CurrentUser
18+
Get-GitDirectory | Should BeNullOrEmpty
19+
}
20+
It 'Returns correct path when in the root of repo' {
21+
$repoRoot = (Resolve-Path $PSScriptRoot\..).Path
22+
Set-Location $repoRoot
23+
Get-GitDirectory | Should BeExactly (MakeNativePath $repoRoot\.git)
24+
}
25+
It 'Returns correct path when under a child folder of the root of repo' {
26+
$repoRoot = (Resolve-Path $PSScriptRoot\..).Path
27+
Set-Location $PSScriptRoot
28+
Get-GitDirectory | Should BeExactly (Join-Path $repoRoot .git)
29+
}
30+
}
31+
32+
Context "Test bare repository" {
33+
BeforeAll {
34+
$origPath = Get-Location
35+
$temp = [System.IO.Path]::GetTempPath()
36+
$bareRepoName = "test.git"
37+
$bareRepoPath = Join-Path $temp $bareRepoName
38+
if (Test-Path $bareRepoPath) {
39+
Remove-Item $bareRepoPath -Recurse -Force
40+
}
41+
git init --bare $bareRepoPath
42+
}
43+
AfterAll {
44+
Set-Location $origPath
45+
if (Test-Path $bareRepoPath) {
46+
Remove-Item $bareRepoPath -Recurse -Force
47+
}
48+
}
49+
50+
It 'Returns correct path when in the root of bare repo' {
51+
Set-Location $bareRepoPath
52+
Get-GitDirectory | Should BeExactly (MakeNativePath $bareRepoPath)
53+
}
54+
It 'Returns correct path when under a child folder of the root of bare repo' {
55+
Set-Location $bareRepoPath\hooks -ErrorVariable Stop
56+
MakeNativePath (Get-GitDirectory) | Should BeExactly $bareRepoPath
57+
}
58+
}
59+
60+
Context "Test GIT_DIR environment variable" {
61+
AfterAll {
62+
Remove-Item Env:\GIT_DIR -ErrorAction SilentlyContinue
63+
}
64+
It 'Returns the value in GIT_DIR env var' {
65+
$env:GIT_DIR = 'C:\xyzzy\posh-git\.git'
66+
Get-GitDirectory | Should BeExactly $env:GIT_DIR
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)