简体   繁体   English

git 进程作为 Python 子进程运行时从不退出

[英]The git process never exits when running as a Python subprocess

Background背景

I'm writing a Python program to process LFS error messages as I have some repos with missing LFS files in Bitbucket Server.我正在编写一个 Python 程序来处理 LFS 错误消息,因为我在 Bitbucket 服务器中有一些缺少 LFS 文件的回购协议。 The output when running git lfs fetch --all isn't very helpful when you want to find out which LFS files are missing from a repo.运行git lfs fetch --all时的 output 当您想找出存储库中缺少哪些 LFS 文件时不是很有帮助。 That's why I'm making a tool for it.这就是为什么我要为它制作一个工具。 Maybe it can be contributed back to the git project in some form when I'm done with it?也许它可以在我完成后以某种形式回馈给 git 项目?

Code snippet代码片段

import subprocess

def git_lfs_fetch(repo_dir) -> list:
    timeout_sec = 120
    try:
        completed_process = subprocess.run(
            ["git", "lfs", "fetch", "--all"], check=False, cwd=repo_dir, 
            capture_output=True, text=True, timeout=timeout_sec, shell=False)
        return completed_process.stderr.split('\n')
    except subprocess.TimeoutExpired as ex:
        print(f'ERROR Could not complete "{ex.cmd}" before timeout of {timeout_sec} s!')
        print(ex.stderr)
        return []

Environment环境

  • Windows 10, 64 bit Windows 10, 64 位
  • Python 3.10.7 Python 3.10.7
  • git version 2.35.2.windows.1 git 版本 2.35.2.windows.1
  • git-lfs/3.0.2 (GitHub; windows amd64; go 1.17.2) git-lfs/3.0.2(GitHub;windows amd64;go 1.17.2)

Problem问题

Sometimes, and not in any consistent way, the subprocess.run() method never returns because the git-lfs process never exits.有时, subprocess.run()方法不会以任何一致的方式返回,因为git-lfs进程永远不会退出。 Usually running the git lfs fetch --all command in my test repos takes a few seconds to complete.通常在我的测试存储库中运行git lfs fetch --all命令需要几秒钟才能完成。 As a workaround, I added a 2 min timeout to the subprocess.run() call.作为解决方法,我向subprocess.run()调用添加了 2 分钟的timeout I figured I could get the output I'm interested in from stderr from the exception, since the git-lfs was done with all it should do.我想我可以从异常中从 stderr 得到我感兴趣的 output,因为git-lfs已经完成了它应该做的所有事情。 However, that did not help.然而,这并没有帮助。 Python does not seem to be able to kill the git subprocess. Python 似乎无法杀死git子进程。 I understand from the doc that it sends a SIGKILL to the process and then waits for it to exit.我从文档中了解到它向进程发送一个SIGKILL ,然后等待它退出。 But it never exits, even with the timeout set.但它永远不会退出,即使设置了超时。

If I manually kill the git-lfs process from the outside I get the expected output printed from ex.stderr so git-lfs sure looks like it is done, and my workaround does what it should.如果我从外部手动终止git-lfs进程,我会从 ex.stderr 打印出预期的ex.stderr ,因此git-lfs确实看起来已经完成,并且我的解决方法可以完成它应该做的事情。

Fixing my workaround修复我的解决方法

As I was writing this, in a typical rubberducking fashion, I had an idea.在我写这篇文章时,以一种典型的橡皮鸭式方式,我有了一个主意。

Since Python fails to forcibly terminate the git subprocess I tried using git-lfs directly, instead of letting git call it.由于 Python 无法强制终止git子进程,我尝试直接使用git-lfs ,而不是让git调用它。 This made the timeout work.这使超时工作。

subprocess.run(["git-lfs", "fetch", "--all"], ...)

What I'm looking for我在找什么

The solution I'm looking for is a way to figure out why git-lfs and consequently git won't terminate properly.我正在寻找的解决方案是一种找出git-lfsgit无法正常终止的原因的方法。 Even better would be a fix for that problem.更好的方法是解决该问题。

I have seen similar problems when calling git from Java and C# on both Linux and Windows (several years ago), ie the git command actually completes all it should do but the git process never terminates.我在 Linux 和 Windows(几年前)上从 Java 和 C# 调用git时看到了类似的问题,即git命令实际上完成了它应该做的所有事情,但git从未终止。 So I'm thinking this "hanging" could be a problem in git itself.所以我认为这种“挂起”可能是 git 本身的问题。 I really would like to be able to find out why the git-lfs process won't exit.我真的很想知道为什么git-lfs进程不会退出。 I don't know where to start looking.我不知道从哪里开始寻找。

By using this method通过使用这种方法

def git_lfs_fetch(repo_dir) -> list:
    timeout_sec = 120
    try:
        completed_process = subprocess.run(
            ["git", "lfs", "fetch", "--all"], check=False, cwd=repo_dir, 
            capture_output=True, text=True, timeout=timeout_sec, shell=False)
        return completed_process.stderr.split('\n')
    except subprocess.TimeoutExpired as ex:
        print(f'ERROR Could not complete "{ex.cmd}" before timeout of {timeout_sec} s!')
        print(ex.stderr)
        return []

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM