web-dev-qa-db-ja.com

Gitクローン:stderrをstdoutにリダイレクトしますが、エラーがstderrに書き込まれ続ける

git cloneは、ドキュメント化された here として、その出力をstderrに書き込みます。これを次のコマンドでリダイレクトできます。

git clone https://myrepo c:\repo 2>&1

ただし、これにより、エラーを含むすべての出力がstderrからstdoutにリダイレクトされます。進捗メッセージをstdoutにリダイレクトする方法はありますが、エラーメッセージがstderrに書き込まれます。

22
Pascal Berger

このスクリプトを使用して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
        }
    }
}
12
Jim W

MingWの更新により、Git 2.15.x/2.16(2018年第1四半期)でリダイレクトを処理する新しい方法が提供されます

commit b2f5571commit 1a172e4commit 3f94442 (2017年11月1日)を参照 Johannes Schindelin(dscho によって。
Junio C Hamanoによってマージ-gitster- in commit 421f21c 、2017年11月9日)

mingw:標準のハンドルをリダイレクトする実験的な機能を追加します

特に、Visual StudioのチームエクスプローラーなどのアプリケーションからGitを呼び出す場合、stdin/stdout/stderrが適切に閉じられていることが重要です。
ただし、Windowsでプロセスを生成する場合、それらのハンドルを使用する場合は、それらのハンドルを継承可能としてマークする必要がありますが、そのフラグはグローバルフラグであり、他の生成されたプロセスでは使用できない可能性があります。それらのハンドルを閉じます。

ファイルまたはさらに良い名前付きパイプ(Unixソケットに類似)へのパスを指定し、生成されたGitプロセスで使用される環境変数(_GIT_REDIRECT_STDIN_およびその仲間)のセットを紹介しましょう。
これは、上記の問題を回避するのに役立ちます。これらの名前付きパイプは、起動時に継承不可能な方法で開かれ、ハンドルは渡されません(したがって、継承されたハンドルは、生成された子によって閉じる必要はありません)。 。

この機能は、v2.11.0(2)以降、Git for Windows(実験的としてマークされている)に同梱されているため、しばらくの間深刻なテストが行​​われてきました。

Gitドキュメント に以下が含まれるようになりました:

_GIT_REDIRECT_STDIN:
GIT_REDIRECT_STDOUT:
GIT_REDIRECT_STDERR:
_

Windowsのみ:標準の入力/出力/エラーハンドルを環境変数で指定されたパスにリダイレクトできます。これは、CreateProcess()を介して標準ハンドルを渡す正規の方法がオプションではないマルチスレッドアプリケーションで特に役立ちます。これは、ハンドルを継承可能としてマークする必要があるためです(その結果every生成されたプロセスはそれらを継承し、通常のGit操作をブロックする可能性があります)。

主な使用目的は、通信に名前付きパイプを使用することです(例:_\\.\pipe\my-git-stdin-123_)。

そしてそれは追加します:

mingw:オプションで、同じハンドルを介してstderr/stdoutをリダイレクトします

PowershellおよびUnixシェルの「_2>&1_」表記は、stderrstdoutがすでに書き込まれているのと同じハンドルにリダイレクトされることを意味します。

この特別な値を使用して、_GIT_REDIRECT_STDERR_および_GIT_REDIRECT_STDOUT_で同じトリックを許可しましょう。前者の値が_2>&1_の場合、stderrは単純に同じハンドルに書き込まれますstdout

この機能はJeff Hostetlerによって提案されました。

使用例:_$env:GIT_REDIRECT_STDERR = '2>&1'_

13
VonC

stderrから取り除くことができます。

このコマンドで:

git clone https://myrepo c:\repo 2>$null

そうすることで、すべてのstderrは表示されなくなります。

進行状況を表示してエラーのみを破棄することはできません。コマンドが失敗した場合、すべての出力はstderr成功した場合stdout

編集:Windowsでのみコマンドが成功した場合でも、gitコマンドの出力は常にstderrになるようです。 T.

4
Oz Bar-Shalom

一般的に話す:

  • コンソール(ターミナル)アプリケーション-WindowsかUnixライクなプラットフォームかに関係なく-2つの出力ストリームのみが自由に使用できます。

    • stdout(標準出力)-これは、data(「戻り値」)が続きます。
    • stderr(標準エラー)-これはwhereerror messagesおよび-追加のストリームがない場合-その他のデータではないものは、進行状況やステータス情報などです。
  • したがって、あなたはできません。また、stderr出力の存在から成功と失敗を推測するべきではありません.

    • 代わりに、アプリケーションのプロセス終了コードのみに依存する必要があります(== --- ==)

      • 0は、成功
      • 任意nonzerovalueを示します失敗
    • PowerShellでは、**プロセスの終了コードが自動変数$LASTEXITCODE**に反映されます。


具体的には、これは以下を意味します:

  • 与えられたgitのstderr出力行は、それらがerrorメッセージまたは他の種類の非データ情報、進捗状況やステータスメッセージなど、gitが頻繁に使用します。

    • Stderrの出力をstdoutに明確にリダイレクトするようにgitに指示する(PowerShellで環境変数GIT_REDIRECT_STDERRを文字列2>&1; $env:GIT_REDIRECT_STDERR = '2>&1'に設定することにより)はしないヘルプ。エラーメッセージと進行状況/ステータスメッセージが同様に送信されます。
  • すでに述べたように、ゼロ以外の終了コードからのみ障害を推測する必要があります。


実用的なアプローチは次のことを行うことです:

# Invoke git and capture both its stdout and stderr streams.
$result = git clone https://myrepo c:\repo 2>&1
# 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 strings
$result | % ToString 

注意:

  • | % ToString stderr行が(ストリーム2を介して)成功出力に(>)にリダイレクトされた場合、stringsのみが出力されるようにしますストリーム(&1)は System.Management.Automation.ErrorRecord インスタンスにラップされます。

  • 2>&1には予期しない副作用が生じる可能性があります-背景情報については この答え を参照してください。

  • PowerShellのエラー処理への外部プログラム呼び出しのより良い統合は、 このRFCドラフト の主題であり、特に、遭遇時に実行を自動的に中止するオプションを持っているゼロ以外の終了コード。

1
mklement0

Invoke-Gitを自分のニーズに合わせて変更しました。

私が解決策を探している間に読んだ多くの投稿から、私は少数の人がこれを使用できると推測しています。

楽しい。

このバージョンは:

  • 渡されたGitコマンドを実行します(Gitがすでに実行パスにあると想定しています)。
  • すべてが順調であれば、すべての出力(stdoutおよびstderr)は、stderrではなくホストに表示されます。
  • $ LASTEXITCODEをチェックして、実際にエラーが発生したかどうかを確認します。エラーが発生した場合は、すべての出力が呼び出し側にスローされて処理されます。
<#
.Synopsis
    Invoke git, handling its quirky stderr that isn't error

.Outputs
    Git messages

.Example
    Invoke-Git Push

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

    try {
        # I could do this in the main script just once, but then the caller would have to know to do that 
        # in every script where they use this function.
        $old_env = $env:GIT_REDIRECT_STDERR
        $env:GIT_REDIRECT_STDERR = '2>&1'

        Write-Host -ForegroundColor Green "`nExecuting: git $Command "
        $output = Invoke-Expression "git $Command "
        if ( $LASTEXITCODE -gt 0 )
        {
            # note: No catch below (only the try/finally). Let the caller handle the exception.
            Throw "Error Encountered executing: 'git $Command '"
        }
        else
        {
            # because $output probably has miultiple lines (array of strings), by piping it to write-Host we get multiple lines.
            $output | Write-Host 
        }
    }
    # note: No catch here. Let the caller handle it.
    finally
    {
        $env:GIT_REDIRECT_STDERR = $old_env
    }
}
1
Jeff Copus