git clone writes its output to stderr as documented here. I can redirect this with the following command:
git clone https://myrepo
Here's yet another take which might serve as inspiration for some. As others pointed out redirecting and checking exit code works well. Things which are different from other answers:
-C instead of having to cd into directories, but also support that for commands which normally do not have that functionality. So you can do igit -dir some/path stash. I use this mainly in automated scripts where it's otherwise annoying to have to cd into directories.igit checkout master works like igit 'checkout master'. Almost, that is, because standard PS caveats apply: quoting so you still need an actual string if quotes need to be passed to the underlying command, i.e. igit log '--format="%h %d"'. And PS doesn't require you to type full parameter names meaning igit push -vwill be interpreted asigit push -Verboseinstead of passing-vi.e. verbose push to git. Use double dash to deal with thatigit -- push -v` or write quotes after all.Code:
<#
.SYNOPSIS
Run git, Powershell-style.
.DESCRIPTION
By default some git commands (clone, checkout, ...) write a part of their
output to stderr, resulting in PS treating that as an error.
Here we work around that by redirecting stderr and using git's exit code
to check if something was actually wrong, and use Write-Error if that's the case,
i.e. standard PS error handling which works with -ErrorAction/-ErrorVariable etc.
The command can be passed as a string or as separate strings.
Additionally takes a $Directory argument which when used has the same effect as git -C,
but also works for clone/stash/submodule/... commands making it easier to automate those.
The $Git argument can be used to specify the executable.
.EXAMPLE
Invoke-Git status
Invoke-Git -Directory some/path status
Invoke-Git 'push -v'
Invoke-Git -Verbose -- push -v # Pass that last -v to git.
#>
function Invoke-Git {
[CmdletBinding()]
param(
[Parameter()] [Alias('Dir')] [String] $Directory = $null,
[Parameter()] [String] $Git = 'git',
[Parameter(Mandatory, Position=0, ValueFromRemainingArguments=$true)] [string] $Command
)
try {
$commandParts = $Command.Split(' ')
$subCommand = $commandParts[0]
if ($Directory -and $subCommand -eq 'clone') {
# To make all commands look alike handle this one as well.
$Command = ($commandParts + @($Directory)) -join ' '
} elseif ($Directory -and @('submodule', 'stash', 'init') -eq $subCommand) {
# These currently require one to be in the git directory so go there.
$currentDir = Get-Location
cd $Directory
} elseif ($Directory) {
if ($commandParts -eq '-C') {
# Not an error, git will pick the last one, but unexpected.
Write-Warning 'Better use either -Directory or -C, not both'
}
$Command = "-C $Directory " + $Command
}
Write-Verbose "Invoke-Git on '$Directory' with command '$Command'"
$gitRedirection = $env:GIT_REDIRECT_STDERR
$env:GIT_REDIRECT_STDERR = '2>&1'
# Deliberately not getting output here: while this means we cannot pass the actual error to Write-Error,
# it does result in all commands being shown 'live'. Otherwise when doing a clone for instance,
# nothing gets displayed while git is doing it's thing which is unexepected and too different from normal usage.
Invoke-Expression "$Git $Command"
if ($LASTEXITCODE -ne 0) {
Write-Error "git exited with code $LASTEXITCODE"
}
} finally {
$env:GIT_REDIRECT_STDERR = $gitRedirection
if ($currentDir) {
cd $currentDir
}
}
}
New-Alias -Name IGit -Value Invoke-Git -ErrorAction SilentlyContinue