Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Git clone:将stderr重定向到stdout,但保持将错误写入stderr_Git_Powershell_Git Clone - Fatal编程技术网

Git clone:将stderr重定向到stdout,但保持将错误写入stderr

Git clone:将stderr重定向到stdout,但保持将错误写入stderr,git,powershell,git-clone,Git,Powershell,Git Clone,git clone将其输出写入stderr,如文档所示。我可以使用以下命令重定向此命令: git clone https://myrepo c:\repo 2>&1 但这会将所有输出(包括错误)从stderr重定向到stdout。是否有方法将进度消息重定向到stdout,但仍将错误消息写入stderr 您可以摆脱stderr 通过此命令: git clone https://myrepo c:\repo 2>$null 这样,所有stderr都不会显示 您不能显示进度,只

git clone
将其输出写入
stderr
,如文档所示。我可以使用以下命令重定向此命令:

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

但这会将所有输出(包括错误)从
stderr
重定向到
stdout
。是否有方法将进度消息重定向到
stdout
,但仍将错误消息写入
stderr

您可以摆脱
stderr

通过此命令:

git clone https://myrepo c:\repo 2>$null
这样,所有
stderr
都不会显示

您不能显示进度,只能丢弃错误。如果命令失败,则所有输出都是
stderr
如果成功
stdout

编辑: 看起来git命令输出将始终是
stderr
,即使命令仅在Windows上成功。
T.

我使用这个脚本来运行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
        }
    }
}

MingW更新提供了一种处理Git 2.15.x/2.16重定向的新方法(2018年第1季度)

参见(2017年11月1日)作者。
(于2017年11月9日合并)

mingw
:添加实验功能以重定向标准句柄 特别是从应用程序(如Visual Studio的团队资源管理器)调用Git时,正确关闭stdin/stdout/stderr非常重要。
但是,在Windows上生成进程时,如果要使用这些句柄,则必须将其标记为可继承,但该标志是一个全局标志,可能会被其他生成的进程使用,这些进程随后不知道如何关闭这些句柄

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

自2.11.0(2)版以来,Git for Windows(标记为实验版)就附带了此功能,因此在此期间,它已经经历了一些严肃的测试

目前的方案包括:

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

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

它还补充说:

mingw
:可选择通过同一句柄重定向stderr/stdout Powershell和Unix shell中的“
2>&1
”符号表示
stderr
重定向到已写入
stdout
的同一句柄

让我们使用这个特殊值来允许使用与
GIT\u REDIRECT\u STDERR
GIT\u REDIRECT\u STDOUT
相同的技巧:如果前者的值为
2>&1
,然后将
stderr
写入与
stdout
相同的句柄

该功能是由Jeff Hostetler提出的


用法示例:
$env:GIT\u REDIRECT\u STDERR='2>&1'
我修改了Invoke GIT以更好地满足我的需要

从我在寻找解决方案时读到的许多帖子中,我猜不止几个人可以使用这个

享受

此版本将:

  • 执行传入的Git命令(假设Git已经在执行路径中)
  • 如果一切顺利,那么所有输出(stdout和stderr)将显示在主机上,而不是通过stderr
  • 检查$LASTEXITCODE以查看是否确实存在错误。如果出现错误,则所有输出都会抛出给调用方处理
&1'
写入主机-ForegroundColor绿色“`nExecuting:git$Command”
$output=调用表达式“git$Command”
if($LASTEXITCODE-gt 0)
{
#注意:下面没有捕获(只有try/finally)。让调用方处理异常。
Throw“执行'git$Command'时遇到错误”
}
其他的
{
#因为$output可能有多行(字符串数组),通过管道将其传输到写入主机,我们可以得到多行。
$output |写主机
}
}
#注意:这里没有陷阱。让打电话的人来处理。
最后
{
$env:GIT\u REDIRECT\u STDERR=$old\u env
}
}
一般来说:

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

    • stdout(标准输出)数据(“返回值”)就在这里
    • stderr(标准错误)-这是错误消息和其他非数据流(如进度和状态信息)出现的地方
  • 因此,您不能也不应该从stderr输出的存在推断成功与失败

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

      • 0
        表示成功
      • 任何非零值表示故障
    • 在PowerShell中,**进程退出代码为refle
      <#
      .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
          }
      }
      
      # 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 
      
      <#
      .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