从各自的控制台(特别是在git上)单击和运行时,bat和Powershell的行为是不同的 [英] Behavior of bat and Powershell is different when clicked vs run from respective consoles, specifically with git

查看:51
本文介绍了从各自的控制台(特别是在git上)单击和运行时,bat和Powershell的行为是不同的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇文章看起来有些罗word,但实际上这里没有太多需要阅读的内容.只是想出了更多细节>更少细节.

我正在开发一些工具来加快git工作流程.我发现/修改了一个试图更新所有git分支的PowerShell脚本:

function PullAllBranches() {
$branches = git branch
foreach($branch in $branches){
    $fixedBranch = $branch.Substring(2, $branch.Length - 2) # extract actual name
    $trackedExpression = "branch." + $fixedBranch + ".merge"
    $trackedBranch = git config --get $trackedExpression # returns refs/heads/master (?)
 #  Write-Host($trackedBranch)
    if(![string]::IsNullOrEmpty($trackedBranch))
    {
        Write-Host('Pulling branch: ' + $fixedBranch)
        git checkout "$fixedBranch" | Out-Null # Pipe to stdout
        git pull 
    }
    else {
        Write-Host('Branch "' + $fixedBranch + '" has no tracked remote')
    }
}
}

PullAllBranches

Read-Host -Prompt "Press Enter to exit"

无法说回购不存在:

Pulling branch: master
git : Switched to branch 'master'
At C:\Users\username\Git\username\csv-plottr\pull_updates.ps1:15 char:9
+         git checkout "$fixedBranch" | Out-Null # Pipe to stdout
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Switched to branch 'master':String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

git : Unable to open connection:
At C:\Users\username\Git\username\csv-plottr\pull_updates.ps1:16 char:9
+         git pull
+         ~~~~~~~~
    + CategoryInfo          : NotSpecified: (Unable to open connection::String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Host does not exist
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.

但是,单步执行代码,似乎它应该可以工作.深入了解这一点,我在PowerShell CLI中尝试了一个简单的git pull origin master:

PS C:\Users\username\Git\username\csv-plottr> git pull origin master
From gh-gitlab:username/csv-plottr
 * branch            master     -> FETCH_HEAD
Already up to date.
PS C:\Users\username\Git\username\csv-plottr>

其中"gh-gitlab"是指向我局域网上的gitlab服务器的SSH身份(相当于10.0.0.xxx:username/csv-plottr).这种方法效果很好,使我认为运行PowerShell脚本是在从PowerShell ISE或其他类型的环境中执行的,而不是在CLI中键入内容.在这两种情况下,我都打印了工作目录,并且它是相同的.有没有比我拥有更多经验的PowerShell/Windows,谁能给我一些启示或向我指出Google的正确方向?

奇怪的是,我在批处理文件中尝试了相同的事情,试图摆脱使用的结果,结果相似.来自cmd:

C:\Users\username\Git\username\csv-plottr>git pull origin master
From gh-gitlab:username/csv-plottr
 * branch            master     -> FETCH_HEAD
Already up to date.

从批处理文件中仅包含:

git pull origin master
pause

双击运行,我得到:

C:\Users\username\Git\username\csv-plottr>git pull origin master
Unable to open connection:
Host does not existfatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

C:\Users\username\Git\username\csv-plottr>pause
Press any key to continue . . .

但是CD到目录并通过键入脚本名称来运行它会给出:

C:\Users\username\Git\username\csv-plottr>.\pull_updates.bat

C:\Users\username\Git\username\csv-plottr>git pull origin master
From gh-gitlab:username/csv-plottr
 * branch            master     -> FETCH_HEAD
Already up to date.

C:\Users\username\Git\username\csv-plottr>pause
Press any key to continue . . .

成功!它说在这种情况下回购是最新的.

有什么作用???为什么这种行为会有所不同,我该怎么做(或用谷歌搜索)来创建相同的行为?我回声了%CD%(pwd),它签出了.我整整一天都在战斗,终于想到我会寻求帮助,因为我认为这将是一份15分钟的工作.我很困惑预先感谢.


编辑/u/mklement0:

我想要Powershell的双击功能,因此我设置了此注册表项: HKCR \ Microsoft.PowerShellScript.1 \ Shell \ Open \ Command

"C:\ Windows \ System32 \ WindowsPowerShell \ v1.0 \ powershell.exe" -NoLogo -ExecutionPolicy不受限制-文件%1"%*

这既解决了运行Powershell和执行策略的麻烦,又解决了双击的麻烦.尽我所能告诉,这应该等同于进入Powershell窗口,将CD下载到正确的目录并调用ps1脚本.

但是当双击我的ps1脚本时,我遇到了同样的问题:

Pulling branch: dev
Switched to branch 'dev'
Unable to open connection:
Host does not existfatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Pulling branch: master
Switched to branch 'master'
Unable to open connection:
Host does not existfatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Press Enter to exit:

vs从PS控制台进行呼叫:

PS C:\Users\username\Git\username\csv-plottr> .\pull_updates.ps1
Pulling branch: dev
Switched to branch 'dev'
Already up to date.
Pulling branch: master
Switched to branch 'master'
Already up to date.
Press Enter to exit:

成功!

批处理文件也会发生这种情况.在Powershell ISE中也没有这样做,只是为了排除这一点.

解决方案

请勿使用PowerShell ISE 运行您的脚本(对于开发而言,可以,但您应该知道陷阱)

  • ISE的PowerShell host 不是真正的控制台,其行为有所不同,在这种情况下可能是问题所在(请参见下文).

  • 所有代码调用都通过 dot-sourcing 同一会话中运行,因此先前调用的操作会影响后续操作调用.

具体地说,每当外部程序(例如git)写入 stderr 时,ISE都会报告一个(非终止)错误,即使这可能并不表示实际的错误.错误(外部实用程序将任何 non-data 消息(例如状态信息)写入stderr);仅外部程序的退出代码(反映在PowerShell中的$LASTEXITCODE中)真正表示成功与失败.

但是请注意,尽管有错误"noise",但除非将$ErrorActionPreference设置为'Stop',否则执行将继续.

示例:

cmd /c 'echo hi >&2'

上面的代码通常在常规控制台中显示"hi",但在ISE中显示为错误.


通常,考虑从ISE切换到 Visual Studio代码及其 PowerShell扩展 :

  • 所有未来的开发工作都将集中于此
  • 它没有表现出手头有问题的行为

但是,请注意,与ISE中一样,默认情况下,所有代码都在同一会话中以点源方式运行,如上所述,当重复运行代码时,这有潜在的不良影响.

为避免这种情况,请使用设置"powershell.debugging.createTemporaryIntegratedConsole": true 创建一个临时会话进行调试(通过settings.json >,或在设置对话框中检查设置PowerShell > Debugging > Create Temporary Console.

但是,默认情况下也会重复使用此临时会话,因此要每次在干净的会话中运行,您必须手动终止先前的临时会话 :

  • 每当终端面板的运行中的shell列表显示上一个临时会话([TEMP] PowerShell Integrated Console)时,请单击右侧的垃圾桶图标()将其杀死,这将在下次执行时创建一个新的临时会话.

This post appears wordy, but there's actually not much here to read. Just figured more details > less details.

I am working on some tools to speed up my git workflow. I found/modified a PowerShell script that attempts to update all git branches:

function PullAllBranches() {
$branches = git branch
foreach($branch in $branches){
    $fixedBranch = $branch.Substring(2, $branch.Length - 2) # extract actual name
    $trackedExpression = "branch." + $fixedBranch + ".merge"
    $trackedBranch = git config --get $trackedExpression # returns refs/heads/master (?)
 #  Write-Host($trackedBranch)
    if(![string]::IsNullOrEmpty($trackedBranch))
    {
        Write-Host('Pulling branch: ' + $fixedBranch)
        git checkout "$fixedBranch" | Out-Null # Pipe to stdout
        git pull 
    }
    else {
        Write-Host('Branch "' + $fixedBranch + '" has no tracked remote')
    }
}
}

PullAllBranches

Read-Host -Prompt "Press Enter to exit"

It fails saying the repo does not exist:

Pulling branch: master
git : Switched to branch 'master'
At C:\Users\username\Git\username\csv-plottr\pull_updates.ps1:15 char:9
+         git checkout "$fixedBranch" | Out-Null # Pipe to stdout
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Switched to branch 'master':String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

git : Unable to open connection:
At C:\Users\username\Git\username\csv-plottr\pull_updates.ps1:16 char:9
+         git pull
+         ~~~~~~~~
    + CategoryInfo          : NotSpecified: (Unable to open connection::String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

Host does not exist
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.

However, stepping through the code, appears it should work. Digging into this, I tried a simple git pull origin master in PowerShell CLI:

PS C:\Users\username\Git\username\csv-plottr> git pull origin master
From gh-gitlab:username/csv-plottr
 * branch            master     -> FETCH_HEAD
Already up to date.
PS C:\Users\username\Git\username\csv-plottr>

Where 'gh-gitlab' is a SSH identity pointing to a gitlab server on my LAN(equivalent to 10.0.0.xxx:username/csv-plottr). This approach works fine, making me think running a PowerShell script executes in a different environment when run from PowerShell ISE or something than typing into the CLI. I printed working directory in both cases and it is the same. Are there any PowerShell/Windows with more experience than I have who could shed some light or point me in the right direction on google?

Curiously, I tried the same thing in a batch file, what I am trying to get away from using, with similar results. From cmd:

C:\Users\username\Git\username\csv-plottr>git pull origin master
From gh-gitlab:username/csv-plottr
 * branch            master     -> FETCH_HEAD
Already up to date.

And from the batch file merely containing:

git pull origin master
pause

Running by double clicking, I get:

C:\Users\username\Git\username\csv-plottr>git pull origin master
Unable to open connection:
Host does not existfatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

C:\Users\username\Git\username\csv-plottr>pause
Press any key to continue . . .

But CDing to the directory and running it by typing the name of the script gives:

C:\Users\username\Git\username\csv-plottr>.\pull_updates.bat

C:\Users\username\Git\username\csv-plottr>git pull origin master
From gh-gitlab:username/csv-plottr
 * branch            master     -> FETCH_HEAD
Already up to date.

C:\Users\username\Git\username\csv-plottr>pause
Press any key to continue . . .

success! It says the repo is up to date in this case.

What gives??? Why is this behavior different and what could I do (or google about) to create the same behavior? I echo'd %CD% (pwd) and it checks out. I have fought this all day, and finally figured I'd ask for help with what I thought would be a 15 minute job. I'm stumped. Thanks in advance.


Edit for /u/mklement0:

I wanted double click functionality for powershell, so I set this registry key: HKCR\Microsoft.PowerShellScript.1\Shell\Open\Command

to

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -ExecutionPolicy unrestricted -File "%1"%*

Which fixes both troubles with running powershell and execution policy, and convenience of just double clicking. As best I can tell, this should be identical to going into a powershell window, CDing to the correct dir, and calling your ps1 script.

But when double clicking my ps1 script I get the same issues:

Pulling branch: dev
Switched to branch 'dev'
Unable to open connection:
Host does not existfatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Pulling branch: master
Switched to branch 'master'
Unable to open connection:
Host does not existfatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Press Enter to exit:

vs calling from a PS console:

PS C:\Users\username\Git\username\csv-plottr> .\pull_updates.ps1
Pulling branch: dev
Switched to branch 'dev'
Already up to date.
Pulling branch: master
Switched to branch 'master'
Already up to date.
Press Enter to exit:

success!

This happens with batch files too. This was not done in the PowerShell ISE either, just to rule that out.

解决方案

Do not use the PowerShell ISE to run your scripts (for development, it may be OK, but you should know the pitfalls):

  • The ISE's PowerShell host is not a true console and behaves differently, which is likely the problem in this case (see below).

  • All code invocations run in the same session, via dot-sourcing, so that actions of previous invocations can affect subsequent invocations.

Specifically, the ISE reports a (non-terminating) error whenever an external program such as git writes to stderr, even though that may not indicate an actual error (external utilities write any non-data messages, such as status information, to stderr); only an external program's exit code - reflected in $LASTEXITCODE in PowerShell - truly signals success vs. failure.

Note, however, that despite the error "noise", execution continues, unless you've set $ErrorActionPreference to 'Stop'.

Example:

cmd /c 'echo hi >&2'

The above prints 'hi' normally in the regular console, but presents like an error in the ISE.


Generally, consider switching from the ISE to Visual Studio Code and its PowerShell extension:

  • all future development effort will focus there
  • it doesn't exhibit the problematic behavior at hand

However, note that, as in the ISE, all code runs dot-sourced in the same session by default, which, as stated, has potentially unwanted side effects when running code repeatedly.

To avoid that, use setting "powershell.debugging.createTemporaryIntegratedConsole": true to create a temporary session for debugging (add it to settings.json via >Preferences: Open Settings, or check setting PowerShell > Debugging > Create Temporary Console in the settings dialog).

However, this temporary session too is reused by default, so to run in a clean session every time, you you must manually kill a previous temporary session:

  • Whenever the terminal panel's list of running shells shows a previous temporary session ([TEMP] PowerShell Integrated Console), click on the trash icon to the right () to kill it, which will create a new temporary session on the next execution.

这篇关于从各自的控制台(特别是在git上)单击和运行时,bat和Powershell的行为是不同的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆