diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..d5bd758be --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Normalize line endings +4256c20d7fa3514651df10f4dbc38bcd8fa012e3 diff --git a/src/GitUtils.ps1 b/src/GitUtils.ps1 index 54f9061db..d9e03cc50 100644 --- a/src/GitUtils.ps1 +++ b/src/GitUtils.ps1 @@ -59,7 +59,7 @@ function Get-GitDirectory { } } -function Get-GitBranch($gitDir = $(Get-GitDirectory), [Diagnostics.Stopwatch]$sw) { +function Get-GitBranch($branch = $null, $gitDir = $(Get-GitDirectory), [switch]$isDotGitOrBare, [Diagnostics.Stopwatch]$sw) { if (!$gitDir) { return } Invoke-Utf8ConsoleCommand { @@ -114,7 +114,13 @@ function Get-GitBranch($gitDir = $(Get-GitDirectory), [Diagnostics.Stopwatch]$sw $r = '|BISECTING' } + if ($step -and $total) { + $r += " $step/$total" + } + $b = Invoke-NullCoalescing ` + $b ` + $branch ` { dbg 'Trying symbolic-ref' $sw; git --no-optional-locks symbolic-ref HEAD -q 2>$null } ` { '({0})' -f (Invoke-NullCoalescing ` { @@ -143,7 +149,7 @@ function Get-GitBranch($gitDir = $(Get-GitDirectory), [Diagnostics.Stopwatch]$sw return $Matches['ref'] } elseif ($ref -and $ref.Length -ge 7) { - return $ref.Substring(0,7)+'...' + return $ref.Substring(0, 7) + '...' } else { return 'unknown' @@ -152,23 +158,21 @@ function Get-GitBranch($gitDir = $(Get-GitDirectory), [Diagnostics.Stopwatch]$sw ) } } - dbg 'Inside git directory?' $sw - $revParseOut = git --no-optional-locks rev-parse --is-inside-git-dir 2>$null - if ('true' -eq $revParseOut) { - dbg 'Inside git directory' $sw - $revParseOut = git --no-optional-locks rev-parse --is-bare-repository 2>$null + if ($isDotGitOrBare -or !$b) { + dbg 'Inside git directory?' $sw + $revParseOut = git --no-optional-locks rev-parse --is-inside-git-dir 2>$null if ('true' -eq $revParseOut) { - $c = 'BARE:' - } - else { - $b = 'GIT_DIR!' + dbg 'Inside git directory' $sw + $revParseOut = git --no-optional-locks rev-parse --is-bare-repository 2>$null + if ('true' -eq $revParseOut) { + $c = 'BARE:' + } + else { + $b = 'GIT_DIR!' + } } } - if ($step -and $total) { - $r += " $step/$total" - } - "$c$($b -replace 'refs/heads/','')$r" } } @@ -228,7 +232,7 @@ function Get-GitStatus { param( # The path of a directory within a Git repository that you want to get # the Git status. - [Parameter(Position=0)] + [Parameter(Position = 0)] $GitDir = (Get-GitDirectory), # If specified, overrides $GitPromptSettings.EnableFileStatus and @@ -266,7 +270,8 @@ function Get-GitStatus { $stashCount = 0 $fileStatusEnabled = $Force -or $settings.EnableFileStatus - if ($fileStatusEnabled -and !$(InDotGitOrBareRepoDir $GitDir) -and !$(InDisabledRepository)) { + # Optimization: short-circuit to avoid InDotGitOrBareRepoDir and InDisabledRepository if !$fileStatusEnabled + if ($fileStatusEnabled -and !$($isDotGitOrBare = InDotGitOrBareRepoDir $GitDir) -and !$(InDisabledRepository)) { if ($null -eq $settings.EnableFileStatusFromCache) { $settings.EnableFileStatusFromCache = $null -ne (Get-Module GitStatusCachePoshClient) } @@ -285,21 +290,21 @@ function Get-GitStatus { else { dbg 'Parsing status' $sw - $indexAdded.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.IndexAdded)))) - $indexModified.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.IndexModified)))) + $indexAdded.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.IndexAdded)))) + $indexModified.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.IndexModified)))) foreach ($indexRenamed in $cacheResponse.IndexRenamed) { $indexModified.Add($indexRenamed.Old) } - $indexDeleted.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.IndexDeleted)))) - $indexUnmerged.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.Conflicted)))) + $indexDeleted.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.IndexDeleted)))) + $indexUnmerged.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.Conflicted)))) - $filesAdded.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.WorkingAdded)))) - $filesModified.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.WorkingModified)))) + $filesAdded.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.WorkingAdded)))) + $filesModified.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.WorkingModified)))) foreach ($workingRenamed in $cacheResponse.WorkingRenamed) { $filesModified.Add($workingRenamed.Old) } - $filesDeleted.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.WorkingDeleted)))) - $filesUnmerged.AddRange($castStringSeq.Invoke($null, (,@($cacheResponse.Conflicted)))) + $filesDeleted.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.WorkingDeleted)))) + $filesUnmerged.AddRange($castStringSeq.Invoke($null, (, @($cacheResponse.Conflicted)))) $branch = $cacheResponse.Branch $upstream = $cacheResponse.Upstream @@ -319,9 +324,9 @@ function Get-GitStatus { else { dbg 'Getting status' $sw switch ($settings.UntrackedFilesMode) { - "No" { $untrackedFilesOption = "-uno" } - "All" { $untrackedFilesOption = "-uall" } - default { $untrackedFilesOption = "-unormal" } + "No" { $untrackedFilesOption = "-uno" } + "All" { $untrackedFilesOption = "-uall" } + default { $untrackedFilesOption = "-unormal" } } $status = Invoke-Utf8ConsoleCommand { git --no-optional-locks -c core.quotepath=false -c color.status=false status $untrackedFilesOption --short --branch 2>$null } if ($settings.EnableStashStatus) { @@ -384,41 +389,41 @@ function Get-GitStatus { } } - if (!$branch) { $branch = Get-GitBranch $GitDir $sw } + $branch = Get-GitBranch -Branch $branch -GitDir $GitDir -IsDotGitOrBare:$isDotGitOrBare -sw $sw dbg 'Building status object' $sw # This collection is used twice, so create the array just once $filesAdded = $filesAdded.ToArray() - $indexPaths = @(GetUniquePaths $indexAdded,$indexModified,$indexDeleted,$indexUnmerged) - $workingPaths = @(GetUniquePaths $filesAdded,$filesModified,$filesDeleted,$filesUnmerged) - $index = (,$indexPaths) | + $indexPaths = @(GetUniquePaths $indexAdded, $indexModified, $indexDeleted, $indexUnmerged) + $workingPaths = @(GetUniquePaths $filesAdded, $filesModified, $filesDeleted, $filesUnmerged) + $index = (, $indexPaths) | Add-Member -Force -PassThru NoteProperty Added $indexAdded.ToArray() | Add-Member -Force -PassThru NoteProperty Modified $indexModified.ToArray() | Add-Member -Force -PassThru NoteProperty Deleted $indexDeleted.ToArray() | Add-Member -Force -PassThru NoteProperty Unmerged $indexUnmerged.ToArray() - $working = (,$workingPaths) | + $working = (, $workingPaths) | Add-Member -Force -PassThru NoteProperty Added $filesAdded | Add-Member -Force -PassThru NoteProperty Modified $filesModified.ToArray() | Add-Member -Force -PassThru NoteProperty Deleted $filesDeleted.ToArray() | Add-Member -Force -PassThru NoteProperty Unmerged $filesUnmerged.ToArray() $result = New-Object PSObject -Property @{ - GitDir = $GitDir - RepoName = Split-Path (Split-Path $GitDir -Parent) -Leaf - Branch = $branch - AheadBy = $aheadBy - BehindBy = $behindBy - UpstreamGone = $gone - Upstream = $upstream - HasIndex = [bool]$index - Index = $index - HasWorking = [bool]$working - Working = $working - HasUntracked = [bool]$filesAdded - StashCount = $stashCount + GitDir = $GitDir + RepoName = Split-Path (Split-Path $GitDir -Parent) -Leaf + Branch = $branch + AheadBy = $aheadBy + BehindBy = $behindBy + UpstreamGone = $gone + Upstream = $upstream + HasIndex = [bool]$index + Index = $index + HasWorking = [bool]$working + Working = $working + HasUntracked = [bool]$filesAdded + StashCount = $stashCount } dbg 'Finished' $sw @@ -453,7 +458,7 @@ function InDotGitOrBareRepoDir([string][ValidateNotNullOrEmpty()]$GitDir) { function Get-AliasPattern($cmd) { $aliases = @($cmd) + @(Get-Alias | Where-Object { $_.Definition -match "^$cmd(\.exe)?$" } | Foreach-Object Name) - "($($aliases -join '|'))" + "($($aliases -join '|'))" } <# @@ -531,16 +536,16 @@ function Get-AliasPattern($cmd) { Shows the branches, both merged and unmerged, that match the specified wildcard that would be deleted without actually deleting them. Once you've verified the list of branches looks correct, remove the WhatIf parameter to actually delete the branches. #> function Remove-GitBranch { - [CmdletBinding(DefaultParameterSetName="Wildcard", SupportsShouldProcess, ConfirmImpact="Medium")] + [CmdletBinding(DefaultParameterSetName = "Wildcard", SupportsShouldProcess, ConfirmImpact = "Medium")] param( # Specifies a regular expression pattern for the branches that will be deleted. Certain branches are always excluded from deletion e.g. the current branch as well as the develop and master branches. See the ExcludePattern parameter to modify that pattern. - [Parameter(Position=0, Mandatory, ParameterSetName="Wildcard")] + [Parameter(Position = 0, Mandatory, ParameterSetName = "Wildcard")] [ValidateNotNullOrEmpty()] [string] $Name, # Specifies a regular expression for the branches that will be deleted. Certain branches are always excluded from deletion e.g. the current branch as well as the develop and master branches. See the ExcludePattern parameter to modify that pattern. - [Parameter(Position=0, Mandatory, ParameterSetName="Pattern")] + [Parameter(Position = 0, Mandatory, ParameterSetName = "Pattern")] [ValidateNotNull()] [string] $Pattern, @@ -579,7 +584,7 @@ function Remove-GitBranch { $branches = git branch --merged $Commit } - $filteredBranches = $branches | Where-Object {$_ -notmatch $ExcludePattern } + $filteredBranches = $branches | Where-Object { $_ -notmatch $ExcludePattern } if ($PSCmdlet.ParameterSetName -eq "Wildcard") { $branchesToDelete = $filteredBranches | Where-Object { $_.Trim() -like $Name } @@ -588,15 +593,16 @@ function Remove-GitBranch { $branchesToDelete = $filteredBranches | Where-Object { $_ -match $Pattern } } - $action = if ($DeleteForce) { "delete with force"} else { "delete" } + $action = if ($DeleteForce) { "delete with force" } else { "delete" } $yesToAll = $noToAll = $false foreach ($branch in $branchesToDelete) { $targetBranch = $branch.Trim() if ($PSCmdlet.ShouldProcess($targetBranch, $action)) { if ($Force -or $yesToAll -or - $PSCmdlet.ShouldContinue("Are you REALLY sure you want to $action `"$targetBranch`"?", - "Confirm branch deletion", [ref]$yesToAll, [ref]$noToAll)) { + $PSCmdlet.ShouldContinue( + "Are you REALLY sure you want to $action `"$targetBranch`"?", + "Confirm branch deletion", [ref]$yesToAll, [ref]$noToAll)) { if ($noToAll) { return } diff --git a/test/Get-GitBranch.Tests.ps1 b/test/Get-GitBranch.Tests.ps1 index 4ea107db2..3e4d00fb3 100644 --- a/test/Get-GitBranch.Tests.ps1 +++ b/test/Get-GitBranch.Tests.ps1 @@ -8,14 +8,16 @@ Describe 'Get-GitBranch Tests' { $repoRoot = (Resolve-Path $PSScriptRoot\..).Path Set-Location $repoRoot\.git -ErrorAction Stop InModuleScope posh-git { - Get-GitBranch | Should -BeExactly 'GIT_DIR!' + InDotGitOrBareRepoDir (Get-Location) | Should -Be $true + Get-GitBranch -IsDotGitOrBare | Should -BeExactly 'GIT_DIR!' } } It 'Returns correct path when in a child folder of the .git dir of the repo' { $repoRoot = (Resolve-Path $PSScriptRoot\..).Path Set-Location $repoRoot\.git\hooks -ErrorAction Stop InModuleScope posh-git { - Get-GitBranch | Should -BeExactly 'GIT_DIR!' + InDotGitOrBareRepoDir (Get-Location) | Should -Be $true + Get-GitBranch -IsDotGitOrBare | Should -BeExactly 'GIT_DIR!' } } } diff --git a/test/Get-GitStatus.Tests.ps1 b/test/Get-GitStatus.Tests.ps1 index cd5bc57e8..418a55a7d 100644 --- a/test/Get-GitStatus.Tests.ps1 +++ b/test/Get-GitStatus.Tests.ps1 @@ -440,6 +440,77 @@ U test/Unmerged.Tests.ps1 } } + Context 'Branch progress suffix' { + BeforeEach { + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')] + $repoPath = NewGitTempRepo -MakeInitialCommit + } + AfterEach { + Set-Location $PSScriptRoot + RemoveGitTempRepo $repoPath + } + + It('Shows CHERRY-PICKING') { + git checkout -qb test + Write-Output 1 > test.txt + git add test.txt + git commit -qam 'first' 2> $null + + git checkout -qb conflict + Write-Output 2 > test.txt + git commit -qam 'second' 2> $null + + $status = Get-GitStatus + $status.Branch | Should -Be conflict + + git cherry-pick test + + $status = Get-GitStatus + $status.Branch | Should -Be 'conflict|CHERRY-PICKING' + } + + It('Shows MERGING') { + git checkout -qb test + Write-Output 1 > test.txt + git add test.txt + git commit -qam 'first' 2> $null + + Write-Output 2 > test.txt + git commit -qam 'second' 2> $null + + git checkout HEAD~ -qb conflict + Write-Output 3 > test.txt + git commit -qam 'third' 2> $null + + $status = Get-GitStatus + $status.Branch | Should -Be conflict + + git merge test + + $status = Get-GitStatus + $status.Branch | Should -Be 'conflict|MERGING' + } + + It('Shows REVERTING') { + git checkout -qb test + Write-Output 1 > test.txt + git add test.txt + git commit -qam 'first' 2> $null + + git checkout -qb conflict + Write-Output 2 > test.txt + git commit -qam 'second' 2> $null + + $status = Get-GitStatus + $status.Branch | Should -Be conflict + + git revert test + + $status = Get-GitStatus + $status.Branch | Should -Be 'conflict|REVERTING' + } + } + Context 'In .git' { BeforeEach { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssigments', '')]