为什么在 Git Bash 中执行 git diff 命令时,Windows 系统有时会出现 10 秒的延迟

这是 Windows Defender 的行为分析功能,排除规则无法解决此问题

简而言之:在 Windows 系统中,git diffgit loggit show 等 Git 命令会随机出现 10 秒的卡顿。这是因为 Microsoft Defender 防病毒软件在分析 Git 如何启动其页面器(而非扫描文件——这就是为什么排除规则无效)。分析完成后,同一命令会立即运行约 30 秒,随后再次变慢。解决方法:为特定命令禁用页面器或手动管道传输。

谜团

数月来,我一直被 Windows 11 上的一个奇怪 Git 性能问题困扰:

  • git diff 在显示任何内容前会冻结 10 秒
  • 立即再次运行:瞬间完成
  • 等待一分钟后再次运行:10 秒
  • git diff | cat 始终瞬间完成

该模式在 git loggit blame 以及任何使用分页器的 Git 命令中均一致。大约 30 秒后,延迟再次出现。

元素周期表

调查

未能解决的方法

当然,我最初认为是操作系统文件缓存或杀毒软件文件扫描导致的:

  • 将 git.exe 添加到 Windows Defender 排除项
  • 将 less.exe 添加到排除项
  • 将整个 Git 安装文件夹添加到排除列表
  • 将我的仓库文件夹添加到排除列表

结果:没有改善。首次运行时仍存在 10 秒延迟。

第一个线索:不仅仅是 Git

打开 Windows 终端后发现,该模式不仅限于 Git:

  • PowerShell 标签页:始终即时
  • 第一个 Git Bash 标签页:打开需 10 秒
  • 紧接着打开第二个 Git Bash 标签页:立即打开
  • 等待 30 秒后打开另一个 Git Bash 标签页:再次出现 10 秒延迟

这并非 Git 的问题,而是关于 Windows 上的 Unix 风格进程创建

关键证据:进程模式

使用不同分页器进行测试证实了这是模式问题:

# Cold start
git -c core.pager=less diff    # 10 seconds
git -c core.pager=head show    # Instant! (cached)

# After cache expires (~30 seconds)
git -c core.pager=head diff    # 10 seconds
git -c core.pager=less show    # Instant! (cached)

具体启动的程序并不重要。Windows Defender正在分析Git如何创建子进程的模式

真凶:PTY模拟

当Git在Windows上启动分页器时,它会:

  1. 分配一个伪终端(PTY)对
  2. 设置双向 I/O 重定向
  3. 通过此复杂控制台配置启动分页器

这种 Unix 风格的 PTY 模式触发了 Microsoft Defender 杀毒软件的行为分析。启动 Git Bash 时也会发生同样的情况(因为它需要 PTY 模拟)。

PowerShell 不会触发此问题,因为它使用原生 Windows 控制台 API。

为何排除规则无效

文件排除规则可阻止扫描文件内容以检测已知恶意软件签名。

行为分析监控进程交互方式:进程创建模式、I/O 重定向、PTY 分配。无法“排除”特定行为模式。

Windows Defender 检测到:“进程创建伪终端并以重定向 I/O 方式启动子进程”这看起来可疑。经过 10 秒分析后,它确定:“这是安全的 Git 行为”。缓存批准约 30 秒(在我的测试中观察到)。

10 秒超时

延迟与 Microsoft Defender 杀毒软件文档中记录的“云阻断超时”完全匹配,即等待云端对可疑行为做出裁决的时间。默认值:10 秒。[1]

自行测试

以下是显示约30秒缓存的精确测试:

$ sleep 35; time git diff; sleep 20; time git diff; sleep 35; time git diff

real    0m10.105s
user    0m0.015s
sys     0m0.000s

real    0m0.045s
user    0m0.015s
sys     0m0.015s

real    0m10.103s
user    0m0.000s
sys     0m0.062s

即使树中没有变化(即空输出),冷启动时仍存在延迟。

35秒后:慢(10秒)。20秒后:快(缓存)。35秒后:再次变慢。

解决方案

1. 禁用 git diff 的分页器

配置 Git 跳过 diff 的分页器:

git config --global pager.diff false
# Then pipe manually when you need pagination:
# git diff | less

2. 手动管道

完全跳过 Git 的内部分页器:

git diff --color=always | less -R

3. 常用命令的别名

alias gd='git diff --color=always | less -R'

4. 使用 PowerShell 替代 Git Bash

PowerShell 使用原生 Windows 控制台 API,完全避免 PTY 模拟。Git 命令仍可正常工作,但终端功能可能有所不同。

5. 切换至 WSL2

真实 Linux PTY 替代模拟 = 不会触发行为分析

*环境:Windows 11 24H2,Git for Windows 2.49.0

[1] https://learn.microsoft.com/en-us/defender-endpoint/configure-cloud-block-timeout-period-microsoft-defender-antivirus

*更新: * PowerShell 也受到影响。Git for Windows 会为分页器创建 PTY,无论调用它的 shell 是哪个:

PS > foreach ($sleep in 35, 20, 35) {
    Start-Sleep $sleep
    $t = Get-Date
    git diff
    "After {0}s wait: {1:F1}s" -f $sleep, ((Get-Date) - $t).TotalSeconds
}
After 35s wait: 10.2s
After 20s wait: 0.1s
After 35s wait: 10.3s

更新 2: 感谢 u/bitzap_sr 明确了 Defender 实际看到的内容:MSYS2 使用 Windows 命名管道实现 PTY。因此,从 Defender 的角度来看,它正在分析 Git 创建具有复杂双向 I/O 的命名管道并 spawning 一个子进程,这就是可疑模式。

更新 3(周日): 延迟已经改变!今天,在周日,我现在看到的是 ~2 秒,而不是前几天看到的 10 秒:

$ sleep 35; time git diff; sleep 20; time git diff; sleep 35; time git diff

real    0m2.195s
user    0m0.000s
sys     0m0.031s

real    0m0.114s  
user    0m0.030s
sys     0m0.047s

real    0m2.204s
user    0m0.062s
sys     0m0.000s

相同的模式(慢→缓存→慢),但速度快得多。这看起来像是实际的云分析已经完成,而不是触发了10秒的超时。无论这是巧合还是与该问题获得的关注度有关,这都是一项显著的改进。行为分析仍然会发生,但至少不再超时了。

共有 25 条讨论

  1. 这就是原因。我的员工强制我使用一台被严格限制的笔记本电脑,上面安装了大量无法禁用的垃圾软件安全软件。

    我发现每次在MSYS2或Git Bash终端中操作时,都会出现随机卡顿现象。

    也许我可以申请使用WSL,如果这样能解决问题的话。

    1. 你的情况可能是最常见的,即被锁定的Windows系统搭配无法控制的安全软件。

      好消息是,这只影响特定场景(Git调用分页器)。常规命令如git addgit commitgit push不受影响。

      首先考虑简单的针对性修复:git config --global pager.diff false 等,对于受此 10 秒延迟影响但通常不需要分页器的常见命令。对于 git log,我建议创建一个明确将输出管道传输到分页器的别名以绕过此问题。

    2. 也许我可以获得使用 WSL 的权限,如果这样能解决问题。

      Windows 上的 Docker Desktop 优先使用 WSL2,因此如果需要,您可以从这个方向入手。

    3. 如果我直接安装 Arch Linux 并每次双系统启动,当他们过来时,我只需说这是 Windows(尝试制作一些类似 Windows 的主题)?

      1. 在没有管理员权限且无法访问BitLocker密钥的情况下,重新分区一个BitLocker加密的SSD祝你好运。

        你可以从USB驱动器启动,但如果Linux系统尝试更改任何BIOS设置,BitLocker可能会在下次重启时检测到并拒绝继续启动过程。届时你可能需要向IT部门解释情况……

        1. 如果他们加密了驱动器,那这事就别提了,算了!USB启动很糟糕,因为你得依赖数据传输速度,太糟糕了

    4. 你有Windows许可证的订阅吗?

      创建一个Hyper-V虚拟机并在其中编码。

  2. 对于那些好奇为什么git diff | less能避免10秒延迟的人:

    当你显式地使用管道时,shell会在两个独立的进程之间建立一个简单的管道。Git写入标准输出,less从标准输入读取,仅此而已。

    但当Git自己启动分页器时,它会创建一个伪终端,建立双向I/O,并管理分页器作为子进程。这就是触发Defender行为分析的原因。

    1. 需要注意的是,从 Defender 这样的原生(非 msys2/cygwin)进程的角度来看,Git Bash(原 msys2,原 cygwin)的 PTY 被视为 Windows 的命名管道。如果原生进程通过命名管道以类似方式重定向 I/O 来启动子进程,结果可能相同。我认为 Defender 并不了解 msys2/cygwin PTY 的相关信息。

  3. 老天爷啊,这几乎是我在 2010 年停止使用 Windows 的主要原因。

  4. 我可以补充一点,当我第一次执行新编译的 .exe 文件时,Defender 会在扫描过程中添加一个短暂的延迟。排除规则(不扫描特定文件夹/驱动器)会被忽略。

  5. 有没有人知道其他常见的 Git 命令可能会受到影响?即使在最简单的拉取、检出、提交、推送操作中,我也注意到大量延迟(单个命令耗时5-10秒),这些似乎与杀毒软件和进程启动相关。我之前遇到过ps1提示符问题,同样会启动过多进程导致Windows系统变慢,但问题依然存在。使用Windows 11系统,配备16GB内存,运行于Citrix VDI环境。

    1. 10秒的页面器延迟只是一个具体问题。您遇到的其他延迟(拉取、检出、提交、推送)可能不同,这些涉及实际文件操作,而杀毒软件可能会通过扫描来减慢这些操作。

      对于这些问题,排除项应有所帮助:

      • 排除您的仓库文件夹
      • 排除 Git 安装文件夹(C:Program FilesGit)

      我记录的行为分析延迟仅影响页面器生成,无法通过排除项解决。但您看到的文件扫描延迟绝对可以解决。

      此外,请检查是否有多个安全产品在扫描相同的操作。

  6. 感谢您的分享!我认为我在使用Python时遇到了类似问题。在Windows系统中使用multiprocessing.pool时性能极差,我始终无法确定原因(我推测可能是Windows Defender导致的)。最终我放弃并切换到Linux系统,问题神奇地解决了。

  7. 你在 Windows 终端中运行 Git Bash 吗?

    1. 是的,我使用 Windows 终端与 Git Bash。但这不是终端问题,延迟无论使用哪个终端都会发生。

      在故障排除过程中,我测试了:

      • Windows 终端
      • MinTTY(Git Bash 默认终端)
      • WezTerm
      • Cmder

      所有终端均显示相同的10秒延迟模式。这是因为Git启动进程的方式,而非终端的显示方式。

      1. PowerShell呢?我有点困惑,想确认使用PowerShell是否能避免这个问题。

        编辑:算了,我看到你说不行

  8. 禁用分页器有什么缺点吗?这是为了绕过一个不再那么相关的限制而保留的遗留功能,还是会让情况变得更糟?

    1. 分页器提供功能。没有它,你会失去这些功能。但原帖作者提议了其他调用分页器的方法,这些方法不会受到速度变慢的影响。

      分页器会显示输出内容的开头,并允许您通过滚动或搜索在输出内容中导航。如果没有分页器,您将看到输出内容的结尾,并需要使用终端功能进行滚动(例如滚动条)。通常终端滚动操作会更加笨拙。

      1. 尝试后,我实际上非常高兴禁用了分页器。之前我总是按住空格键将所有内容从分页器中取出,以便能用鼠标滚轮正常滚动。现在它终于按我预期那样工作了。

        坦白说,Git默认使用分页器似乎在配置上有点(非常轻微的)越界

  9. 解决方案:不要使用Git Bash,直接在PowerShell中使用Git。我从未遇到过这些问题

  10. 你试过为Git创建进程豁免而不是文件豁免吗?

    1. 好点子。我的帖子中没有明确说明这一点。

      我已经为git.exe、less.exe和bash.exe设置了进程豁免:

      PS> (Get-MpPreference).ExclusionProcess
      bash.exe
      git.exe
      less.exe
      [... 其他开发工具 ...]
      

      仍然出现10秒延迟。进程排除不起作用,就像路径排除不起作用一样。行为分析似乎在与这些排除机制不同的层面上运行。

      被分析的模式(PTY创建与子进程生成)似乎会触发云端检查,无论是否存在排除规则。

  11. 当我不在VPN上时,Windows上的Git会出现严重的延迟,因此无法访问广告控制器

    我不是开玩笑。Windows上的Git会在域中检查广告

  12. 直到我看到(4. 使用PowerShell …)时,我才明白你在说什么。我从不在Windows上使用Bash,它太糟糕了。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: