Mehrere Git-Clients, die an demselben lokalen Repository arbeiten, konkurrieren um diese Sperre. Jeder Kunde sollte warten, bis die Sperre von der anderen Partei freigegeben wird, um ein guter Bürger zu sein. Für uns scheinen SourceTree oder MSVS im Hintergrund einige Wartungsarbeiten durchzuführen, während wir große Festschreibungsskripte ausführen.
Vielleicht sollte 'git' selbst ein '--retriesWhenLocked 5'-Argument unterstützen, um Wiederholungsversuche zu unterstützen.oder sogar standardmäßig, wenn manuell ausgeführt.
Hier ist ein PowerShell-Wrapper um git mit dem Namen "gitr", der erneut versucht, bis index.lock verschwindet. Dabei werden standardmäßig 5 Versuche mit jeweils 3 Sekunden Abstand verwendet. Die index.lock wird niemals entfernt, vorausgesetzt, der Benutzer sollte eingreifen. Es wurde aus einem größeren Commit-Skript extrahiert. Es gibt nur minimale Tests mit einfachen Argumenten.
- Kopieren Sie das Skript nach C: \ bin und fügen Sie C: \ bin zu $ PATH hinzu.
- Von PS1> gitr --help
- Von DOS%> Powershell Gitr - Hilfe
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
}