Git clone:将stderr重定向到stdout但是将错误写入stderr

Pas*_*ger 19 git powershell git-clone

git clone它的输出写到stderr作为记录在这里.我可以使用以下命令重定向它:

git clone https://myrepo c:\repo 2>&1
Run Code Online (Sandbox Code Playgroud)

但是这会将所有输出(包括错误)重定向stderrstdout.有没有办法将进度消息重定向到stdout但仍然写入错误消息stderr.

Von*_*onC 12

MingW更新提供了一种新方法来处理Git 2.15.x / 2.16(Q1 2018)的重定向

请参阅Johannes Schindelin()的commit b2f5571commit 1a172e4commit 3f94442(2017年11月1日(通过合并JUNIOÇ滨野- -提交421f21c,2017年11月9日)dscho
gitster

mingw:添加实验性功能以重定向标准手柄

特别是从诸如Visual Studio的Team Explorer之类的应用程序调用Git时,正确关闭stdin / stdout / stderr很重要。
但是,在Windows上生成进程时,如果要使用它们,则必须将这些句柄标记为可继承,但是该标志是全局标志,并且可能很好地被其他生成的进程使用,这些进程随后不知道关闭这些句柄。

让我们介绍一组环境变量(GIT_REDIRECT_STDIN和朋友),这些变量指定文件的路径,或者甚至更好的命名管道(类似于Unix套接字),并由生成的Git进程使用。
这有助于解决上述问题:启动时将以不可继承的方式打开那些命名管道,并且不会传递任何句柄(因此,任何派生的子代都无需关闭继承的句柄)。

从v2.11.0(2)开始,Git for Windows附带了此功能(标记为实验性),因此在此期间已经进行了一些认真的测试。

Git的文档现在包括:

GIT_REDIRECT_STDIN:
GIT_REDIRECT_STDOUT:
GIT_REDIRECT_STDERR:
Run Code Online (Sandbox Code Playgroud)

仅限Windows:允许将标准输入/输出/错误句柄重定向到环境变量指定的路径。这在多线程应用程序中特别有用,在这种情况下,不能通过标准方式传递标准句柄,CreateProcess()因为这将要求将句柄标记为可继承(因此,每个生成的进程都将继承它们,可能会阻止常规的Git操作)。

主要的预期用例是使用命名管道进行通信(例如\\.\pipe\my-git-stdin-123)。

它添加了:

mingw:可以选择通过同一句柄重定向stderr / stdout

2>&1在Powershell和Unix Shell中,“ ”表示stderr 被重定向到stdout已经写入的同一句柄。

让我们使用此特殊值与GIT_REDIRECT_STDERR和允许相同的技巧GIT_REDIRECT_STDOUT:如果前者的值为 2>&1stderr则将简单地写入与相同的句柄stdout

该功能由Jeff Hostetler建议。

用法示例:$env:GIT_REDIRECT_STDERR = '2>&1'

  • 谢谢!我在TFS构建中因使用Powershell脚本而发疯,因为它成功但被报告为错误(当然没有错误消息),只是在运行git命令修复它之前添加了$ env:GIT_REDIRECT_STDERR ='2>&1'`。 。 (5认同)

mkl*_*nt0 12

一般来说

  • 控制台(终端)应用程序- 无论是在 Windows 上还是在类 Unix 平台上 - 都只有两个输出流可供使用:

    • stdout(标准输出)- 这是数据(“返回值”)所在的位置。
    • stderr(标准错误) - 这是错误消息的位置,并且 - 由于缺少附加流 -任何其他非数据的内容,例如进度和状态信息。
  • 因此,不能也不应该根据 stderr 输出的存在来推断成功与失败

    • 相反,您必须仅依赖应用程序的进程退出代码

      • 0表示成功
      • 任何非零都表示失败
    • PowerShell中,进程退出代码反映在自动变量中$LASTEXITCODE


具体来说,这意味着:

  • 给定gitstderr 输出行,您无法推断它们是否表示错误消息或其他类型的非数据信息,例如git经常使用的进度或状态消息。

    • 告诉git将其 stderr 输出明确重定向到 stdout(通过在 PowerShell 中将环境变量设置GIT_REDIRECT_STDERR为 string 2>&1; $env:GIT_REDIRECT_STDERR = '2>&1'并没有帮助,因为错误消息和进度/状态消息都会发送到那里。
  • 如前所述,您应该仅从非零退出代码推断失败。


务实的方法是执行以下操作:

# Invoke git and capture both its stdout and stderr streams, as strings.
$result = git clone https://myrepo c:\repo 2>&1 | % ToString

# Throw an error, if git indicated failure.
if ($LASTEXITCODE) { Throw "git failed (exit code: $LASTEXITCODE):`n$($result -join "`n")" }                                            

# Output the captured result, as an array of lines.
$result
Run Code Online (Sandbox Code Playgroud)

笔记:

  • | % ToString(%ForEach-Object) 的缩写,确保仅输出字符串2,前提是重定向到 ( >) 的 stderr 行(通过流 )成功输出流 ( &1) 包装在[System.Management.Automation.ErrorRecord]实例中。

    • PowerShell (Core) 7+中,如果您只是想打印结果,则这并不是绝对必要的,因为即使这些结果也字符串一样[System.Management.Automation.ErrorRecord]打印;相比之下,Windows PowerShell会像 PowerShell 错误一样打印它们。
  • 2>&1在 PowerShell 版本高达 7.1 中可能会产生意想不到的副作用 - 请参阅此答案以获取背景信息。

  • 该 RFC 草案的主题是更好地将外部程序调用集成到 PowerShell 的错误处理中,特别是在遇到非零退出代码时可以选择自动中止执行。


小智 9

我使用此脚本运行git命令。由于git即使成功也会写入stderr(例如,同步时拉入),因此这可以处理这些情况并写出输出的第一行,这通常是您需要知道的。

<#
.Synopsis
    Invoke git, handling its quirky stderr that isn't error

.Outputs
    Git messages, and lastly the exit code

.Example
    Invoke-Git push

.Example
    Invoke-Git "add ."
#>
function Invoke-Git
{
param(
[Parameter(Mandatory)]
[string] $Command )

    try {

        $exit = 0
        $path = [System.IO.Path]::GetTempFileName()

        Invoke-Expression "git $Command 2> $path"
        $exit = $LASTEXITCODE
        if ( $exit -gt 0 )
        {
            Write-Error (Get-Content $path).ToString()
        }
        else
        {
            Get-Content $path | Select-Object -First 1
        }
        $exit
    }
    catch
    {
        Write-Host "Error: $_`n$($_.ScriptStackTrace)"
    }
    finally
    {
        if ( Test-Path $path )
        {
            Remove-Item $path
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 9

我只是想补充一点,如果像我一样,您更关心 stderr 中的错误且仅错误,并且不关心任何进展,那么有一个非常简单的解决方法 - 您只需添加 -命令的安静(或 -q)。

这告诉 git 完全停止报告进度,除非发生实际错误。

  • 这确实很有帮助并解决了我的问题。谢谢! (2认同)