首页 > 解决方案 > 从 PowerShell 脚本中提取时出错

问题描述

我有一个简单的 PowerShell 脚本,可以让文件夹与它的 git 存储库保持同步。

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

当存储库已经是最新的时,它可以正常工作。但是,如果不是,这是输出:

07/29/19 14:47:27:从 somepath 获取最新信息
git:来自 https://gitlab.com/someplace
在某个地方\UpdateBranch.ps1:10 char:5
+ git -C $location$_ 拉
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (来自 https://gi...n/somerepo:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

   b34e5d0..3ec9561 开发 -> 起源/开发
   b6d33b1..65fb520 特征/特征1 -> 原点/特征/特征1
 * [新分支] feature/feature2 -> origin/feature/feature2
   c3fe1c9..9553b72 主 -> 原点/主

更新 b34e5d0..3ec9561
快进
 样式表.scss | 4++--
 ...
 6 个文件更改,11 个插入(+),10 个删除(-)

它似乎进行了更新,但也输出了错误。

标签: gitpowershell

解决方案


Git 将更详细的数据写入错误流,以允许解析器解析最重要的位。然后,这些解析器可以忽略对人类用户意味着的更详细的输出。该数据通过 stderr 流发送。Powershell 默认将 stderr 上的数据转换为错误记录,抛出你看到的错误。

以下github 问题有一大堆可能的解决方案

似乎最简单的一个是添加--porcelainor --quiet,它不会将详细数据写入 stderr 或根本没有数据。

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

另一种选择是通过环境为 git 配置标准重定向模式,至少这样您不需要将重定向分散在整个代码中:

$env:GIT_REDIRECT_STDERR = '2>&1'

在这个 StackOverflow 答案中找到了更多选项,强制所有重定向消息到它们的字符串表示也很好:

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

另一种语法是:

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

另一种解决方法是通过以下方式调用 git cmd

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

在这个答案中,您将找到一个以干净方式调用 git 的包装函数

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

推荐阅读