Aynı yerel depoda çalışan birden çok git istemcisi bu kilit için rekabet eder. Her müşteri, kilit, iyi bir vatandaş olmak için karşı taraf tarafından serbest bırakılıncaya kadar beklemelidir. Bizim için, SourceTree veya MSVS, büyük komut dosyaları çalıştırırken arka planda biraz bakım yapıyor gibi görünüyor.
Belki de 'git' kendisi yeniden denemeleri desteklemek için '--retriesWhenLocked 5' argümanını desteklemelidir.veya manuel olarak çalıştırıldığında bunu varsayılan olarak ayarlayabilirsiniz.
Burada "gitr" adlı bir PowerShell sarmalayıcısı, index.lock kaybolana kadar, her biri arasında 3 saniye varsayılan 5 deneme kullanılarak kaybolana kadar yeniden denenir. Kullanıcının müdahale etmesi gerektiğini varsayarak index.lock dosyasını asla kaldırmaz. Daha büyük bir komut dosyasından çıkarıldı. Sadece basit argümanlarla minimal testlere sahiptir.
- Komut dosyasını C: \ bin dizinine kopyalayın ve C: \ bin dizinini $ PATH dizinine ekleyin.
- PS1'den> gitr --help
- DOS% 'dan> powershell gitr --help
gitr.ps1
#requires -version 2
<#
.SYNOPSIS
gitr
.DESCRIPTION
Run "git" as an external process with retry and capturing stdout stderr.
.NOTES
2017/05/16 crokusek: Initial version
#>
#---------------------------------------------------------[Initializations]--------------------------------------------------------
#Set Error Action
$ErrorActionPreference = "Stop";
#----------------------------------------------------------[Declarations]----------------------------------------------------------
$scriptDir = Split-Path $script:MyInvocation.MyCommand.Path
#Set-Location $scriptDir
## Disabled logging
# Log File
# $logFile = "$($scriptDir)\getr.log"
# If (Test-Path $logFile) { Clear-Content $logFile }
#-----------------------------------------------------------[Functions]------------------------------------------------------------
Function Log([string]$msg, [bool]$echo = $true)
{
$timestamp = "$(get-date -Format 'yyyy/MM/dd HH:mm:ss'): "
$fullmsg = $msg -replace '(?ms)^', $timestamp # the (?ms) enables multiline mode
## Disabled Logging
# Add-content $LogFile -value $fullmsg
if ($echo)
{
Write-Host $msg
}
}
Function ExecSimple([string]$command, [bool]$echo=$true, [bool]$stopOnNonZeroExitCode=$true)
{
$command, $args = $command -split " "
return Exec $command $args $echo $stopOnNonZeroExitCode
}
Function Exec([string]$exe, [string[]]$arguments, [bool]$echo=$true, [bool]$stopOnNonZeroExitCode=$true)
{
# Passing $args (list) as a single parameter is the most flexible, it supports spaces and double quotes
$orgErrorActionPreference = $ErrorActionPreference
Try
{
$error.clear() # this apparently catches all the stderr pipe lines
if ($false -and $exe -eq 'git') # todo make this a generic flag
{
$exe = "$($exe) 2>&1"
}
$output = ""
$argflattened = $arguments -join ' '
Log "`n% $($exe) $($arguments)`n"
# This way some advantages over Invoke-Expressions or Start-Process for some cases:
# - merges stdout/stderr line by line properly,
# - echoes the output live as it is streamed to the current window,
# - waits for completion
# - works when calling both console and windows executables.
#
$ErrorActionPreference = "Continue" # required in order to catch more than 1 stderr line in the exception
if ($echo)
{
# Using "cmd.exe" allows the stderr -> stdout redirection to work properly. Otherwise the 2>&1 runs after PS for
# some reason. When a command such as "git" writes to stderr, powershell was terminating on the first stderr
# line (and stops capturing additional lines).
#
# but unfortuantely cmd has some bizarre de-quoting rules that weren't working for all cases.
#& cmd /c "`"" $exe $arguments "`"" | Tee-Object -variable output | Write-Host | out-null
# This is simplest but has some issues with stderr/stdout (stderr caught as exception below)
#
& $exe $arguments 2>&1 | tee -variable output | Write-Host | out-null
}
else
{
& $exe $arguments 2>&1 | tee -variable output | out-null
}
$output = $output -join "`r`n"
if ($stopOnNonZeroExitCode -and !$LASTEXITCODE -eq 0)
{
throw [System.Exception] "Exit code ($($LASTEXITCODE)) was non-zero. Output:`n$($output)"
}
}
catch [System.Management.Automation.RemoteException]
{
$output = $_.Exception.ToString().Replace("System.Management.Automation.RemoteException:", "").Trim()
if ($output.Contains("fatal"))
{
throw
}
if ($echo)
{
Log $output
}
}
finally
{
$ErrorActionPreference = $orgErrorActionPreference;
}
if (-not $output -eq "")
{
Log $output $false # don't echo to screen as the pipe above did
}
return $output
}
Function ExecWithRetry([string]$exe, [string[]]$arguments, [bool]$echo=$true, [bool]$stopOnNonZeroExitCode=$true,
[int]$maxRetries = 5, [int]$msDelay = 3000, [AllowNull()][string]$exceptionMustContain = $null)
{
for ($i = 0; $i -lt $maxRetries; $i++)
{
try
{
Exec $exe $arguments $echo $stopOnNonZeroExitCode
return
}
catch
{
if (-not [string]::IsNullOrEmpty($exceptionMustContain) -and $_.Exception.ToString().Contains($exceptionMustContain))
{
Log "Last Error from $($exe) is retryable ($($i + 1) of $($maxRetries))" $true
Start-Sleep -Milliseconds ($msDelay);
continue
}
throw
}
}
throw [System.Exception] "Unable to successfully exec '$($exe)' within $($maxRetries) attempts."
}
Function GitWithRetry([string[]]$arguments, [bool]$echo=$true)
{
ExecWithRetry "git" $arguments $echo -exceptionMustContain "Another git process seems to be running"
}
#-----------------------------------------------------------[Main]------------------------------------------------------------
function Main([string[]]$arguments)
{
GitWithRetry @($arguments)
}
#-------------------------------------- Startup ------------------------------------
try
{
Main $args
Exit 0
}
catch
{
#Log "*** A fatal error occured: $($_.Exception)"
#Read-Host -Prompt "`nA fatal error occurred, press enter to close."
exit 1
}