3

I have a simple PowerShell script to keep a folder up-to-date with its git repository.

Param(
    [Parameter(Mandatory = $true)][string]$branch,
    [string]$location,
    [int]$depth
)

Get-ChildItem -Recurse -Directory -Depth $depth -Filter _$branch -Name -Path $location | 
ForEach-Object {
    Write-Output "`n$("{0:MM/dd/yy} {0:HH:mm:ss}" -f (Get-Date)): Getting latest from $location$_"
    git -C $location$_ pull
} *>> logs\$branch.log

It works fine when the repository is already up-to-date. However, when it isn't, this is the output:

07/29/19 14:47:27: Getting latest from somepath
git : From https://gitlab.com/someplace
At someplace\UpdateBranch.ps1:10 char:5
+     git -C $location$_ pull
+     ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (From https://gi...n/somerepo:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

   b34e5d0..3ec9561  develop           -> origin/develop
   b6d33b1..65fb520  feature/feature1  -> origin/feature/feature1
 * [new branch]      feature/feature2  -> origin/feature/feature2
   c3fe1c9..9553b72  master            -> origin/master

Updating b34e5d0..3ec9561
Fast-forward
 stylesheet.scss      | 4 ++--
 ...
 6 files changed, 11 insertions(+), 10 deletions(-)

It seems to do the update but also outputs an error.

Ansgar Wiechers
  • 175,025
  • 22
  • 204
  • 278
Alex Laquerre
  • 195
  • 1
  • 1
  • 17

2 Answers2

5

Git writes the more verbose data to the Error stream to allow parsers to parse the most important bits. These parsers can then ignore the more verbose output that's meant for the human user. That data is sent through the stderr stream. Powershell converts data on stderr to an error record by default, throwing the error you see.

The following github issue has a whole bunch of possible solutions.

The one that seems to be the simplest is to add --porcelain or --quiet, which will not write verbose data to stderr or no data at all.

git checkout branch --porcelain
git checkout branch --quiet

Another option is to configure the standard redirect mode for git through the environment, at least this way you don't need to scatter the redirect throughout the whole code:

$env:GIT_REDIRECT_STDERR = '2>&1'

More options are found in this StackOverflow answer, forcing all redirected messages to their string representation works nicely too:

git checkout branch 2>&1 | %{ "$_" }

An alternate syntax for that is:

"$(git checkout branch ? 2>&1 )"

Another workaround is to invoke git through cmd:

& cmd /c 'git checkout branch 2>&1'

And in this answer you'll find a wrapper function to call git in a clean manner.

function Invoke-Git {
<#
.Synopsis
Wrapper function that deals with Powershell's peculiar error output when Git uses the error stream.

.Example
Invoke-Git ThrowError
$LASTEXITCODE

#>
    [CmdletBinding()]
    param(
        [parameter(ValueFromRemainingArguments=$true)]
        [string[]]$Arguments
    )

    & {
        [CmdletBinding()]
        param(
            [parameter(ValueFromRemainingArguments=$true)]
            [string[]]$InnerArgs
        )
        C:\Full\Path\To\git.exe $InnerArgs
    } -ErrorAction SilentlyContinue -ErrorVariable fail @Arguments

    if ($fail) {
        $fail.Exception
    }

}

# Could shorten the function name. I instead alias it, for terseness.
Set-Alias -Name git -Value Invoke-Git

# Also alias the name with the extension, as it is called by some applications this way.
Set-Alias -Name git.exe -Value Invoke-Git
jessehouwing
  • 87,636
  • 19
  • 214
  • 286
1

I have encountered this behavior in the past with git commands and PowerShell, I don't know exactly why PS print the success response like an error but I solved it in this way:

$output = git pull 2>&1
Write-Host $output
Shayki Abramczyk
  • 24,285
  • 13
  • 49
  • 65