GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Use subprocess timeout by ngie-eign · Pull Request #2127 · gitpython-developers/GitPython

Conversation

@ngie-eign

@ngie-eign ngie-eign commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

subprocess's APIs in 3.3+ support passing timeout to calls, such as
.communicate(..), .wait(..), etc. Pass kill_after_timeout to those
APIs and remove the watchdog handler code as it's not needed once
timeout= is used.

This enables kill_after_timeout on Windows platforms by side-effect as
upstream implements timeout for all supported platforms.

Requires: #2126

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@ngie-eign
ngie-eign force-pushed the use-subprocess-timeout branch 2 times, most recently from 2d09ccf to 1435486 Compare April 18, 2026 17:29
@ngie-eign
ngie-eign marked this pull request as ready for review April 18, 2026 17:54
@ngie-eign

ngie-eign commented Apr 18, 2026

Copy link
Copy Markdown
Contributor Author

The failure may have been caused by a sporadic network outage. Let's try again.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ngie-eign
ngie-eign force-pushed the use-subprocess-timeout branch from 1435486 to 14190cb Compare April 18, 2026 17:55
@ngie-eign
ngie-eign marked this pull request as draft April 18, 2026 17:55
@ngie-eign
ngie-eign marked this pull request as ready for review April 18, 2026 18:05
@ngie-eign ngie-eign mentioned this pull request Apr 18, 2026
git.cmd.Git.execute(..): fix with_stdout=False #2126
Merged
@Byron
Byron requested a review from Copilot April 19, 2026 04:20
Copilot started reviewing on behalf of Byron April 19, 2026 04:20
View session
Copilot AI reviewed Apr 19, 2026
View reviewed changes

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates process execution to rely on subprocess’s native timeout= support (instead of a custom watchdog) and adjusts related tests/cleanup.

Changes:

  • Remove watchdog-based timeout logic and use timeout= with Popen.communicate() / Popen.wait().
  • Add tests covering Git.execute(..., with_stdout=False) behavior (including with output_stream).
  • Improve test cleanup for unwritable directories/symlink scenarios; update AUTHORS.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 8 comments.

File Description
git/cmd.py Replaces custom watchdog timeout with subprocess timeouts; adjusts stream handling and AutoInterrupt waits.
test/test_git.py Adds regression tests for with_stdout=False with/without output_stream.
test/test_util.py Adds a pytest finalizer to ensure cleanup of unwritable temp directories after the test.
AUTHORS Adds contributor entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread test/test_util.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@Byron

Byron commented Apr 19, 2026

Copy link
Copy Markdown
Member

Thanks a lot for your continued work on this.

Let's take a look at the auto review before I merge it.

ngie-eign reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ngie-eign
ngie-eign force-pushed the use-subprocess-timeout branch from 14190cb to 5124e0c Compare April 21, 2026 07:27
github-advanced-security[bot]
github-advanced-security Bot found potential problems Apr 21, 2026
View reviewed changes
Comment thread git/cmd.py Fixed

Uh oh!

There was an error while loading. Please reload this page.

@ngie-eign
ngie-eign force-pushed the use-subprocess-timeout branch 4 times, most recently from 8ddff20 to d946809 Compare April 21, 2026 16:51
@ngie-eign

ngie-eign commented Apr 21, 2026

Copy link
Copy Markdown
Contributor Author

@Byron : this is ready for a re-review.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ngie-eign
ngie-eign force-pushed the use-subprocess-timeout branch from d946809 to 07362e7 Compare April 21, 2026 17:12
@Byron
Byron requested a review from Copilot April 22, 2026 02:02
Copilot started reviewing on behalf of Byron April 22, 2026 02:03
View session
Byron
Byron requested changes Apr 22, 2026
View reviewed changes

@Byron Byron left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot, and sorry forward shall follow.

Because I realized that we are definitely missing an actual timeout test. So maybe just make it so that it runs some fixture binary that sleeps for a while and set the timeout short enough so it reliably times out. What matters here is that we validate that communicate still picks up the stdout and stderr that was emitted so far.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Copilot AI reviewed Apr 22, 2026
View reviewed changes

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread git/cmd.py
Comment on lines +334 to +343
def __init__(
self,
proc: subprocess.Popen | None,
args: Any,
timeout: float | None = None,
) -> None:
self.proc = proc
self.args = args
self.status: Union[int, None] = None
self.timeout = timeout

Copilot AI Apr 22, 2026

Copy link

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_AutoInterrupt now has a timeout attribute and uses it in wait(timeout=...), but no callers pass a value (the only construction is self.AutoInterrupt(proc, command)). As a result, timeout stays None and the new timeout-aware wait()/_terminate() behavior is never applied. If the intent is to enforce kill_after_timeout for as_process=True flows (e.g., via handle_process_output), wire the timeout through when constructing AutoInterrupt or set it before calling _terminate()/wait().

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Copilot uses AI. Check for mistakes.
Comment thread git/cmd.py
Comment on lines 371 to 381
try:
proc.terminate()
status = proc.wait() # Ensure the process goes away.
status = proc.wait(timeout=self.timeout) # Ensure the process goes away.

self.status = self._status_code_if_terminate or status
except (OSError, AttributeError) as ex:
except (OSError, AttributeError, subprocess.TimeoutExpired) as ex:
# On interpreter shutdown (notably on Windows), parts of the stdlib used by
# subprocess can already be torn down (e.g. `subprocess._winapi` becomes None),
# which can cause AttributeError during terminate(). In that case, we prefer
# to silently ignore to avoid noisy "Exception ignored in: __del__" messages.
_logger.info("Ignored error while terminating process: %r", ex)

Copilot AI Apr 22, 2026

Copy link

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In _terminate(), if proc.wait(timeout=self.timeout) raises TimeoutExpired, the exception is logged and ignored, potentially leaving the child process running and leaked. Consider escalating to proc.kill() (or another stronger termination strategy) after a terminate+wait timeout, and/or ensuring the process is reaped.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Copilot uses AI. Check for mistakes.
Comment thread git/cmd.py Outdated
Comment on lines +1325 to +1329
"error: process killed because it timed out. kill_after_timeout=%s seconds",
kill_after_timeout,
)
proc.terminate()
stdout_value, stderr_value = proc.communicate()

Copilot AI Apr 22, 2026

Copy link

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

execute()'s TimeoutExpired handling calls proc.terminate() and then proc.communicate() without any timeout, which can hang indefinitely if the process ignores termination. Also, status is not updated in this path, so with with_exceptions=False the method may return status=0 even though a timeout occurred. Consider: (1) setting status = proc.returncode after reaping, (2) using a bounded second communicate(timeout=...) followed by proc.kill() as a fallback, and (3) avoiding log text that claims the process was "killed" when only terminate() was attempted.

Suggested change
"error: process killed because it timed out. kill_after_timeout=%s seconds",
kill_after_timeout,
)
proc.terminate()
stdout_value, stderr_value = proc.communicate()
"error: process timed out after %s seconds; attempting to terminate it",
kill_after_timeout,
)
proc.terminate()
try:
stdout_value, stderr_value = proc.communicate(timeout=kill_after_timeout)
except subprocess.TimeoutExpired:
_logger.info("error: process did not terminate in time; killing it")
proc.kill()
stdout_value, stderr_value = proc.communicate()
if stdout_value is not None and stdout_value.endswith(newline) and strip_newline_in_stdout: # type: ignore[arg-type]
stdout_value = stdout_value[:-1]
if stderr_value is not None and stderr_value.endswith(newline): # type: ignore[arg-type]
stderr_value = stderr_value[:-1]
status = proc.returncode

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Copilot uses AI. Check for mistakes.
Comment thread git/remote.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread git/cmd.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@ngie-eign
Use subprocess's timeout feature instead of reinventing the wheel
e2d689f
subprocess's APIs in 3.3+ support passing timeout to calls, such as
.communicate(..), .wait(..), etc. Pass `kill_after_timeout` to those
APIs and remove the watchdog handler code as it's not needed once
`timeout=` is used.

This enables `kill_after_timeout` on Windows platforms by side-effect as
upstream implements `timeout` for all supported platforms.

Signed-off-by: Enji Cooper <[email protected]>
@ngie-eign
ngie-eign force-pushed the use-subprocess-timeout branch 2 times, most recently from 1c08f40 to 4c1fda8 Compare April 22, 2026 21:25
@ngie-eign
fixup! Use subprocess's timeout feature instead of reinventing the wheel
ec130d6
@ngie-eign
ngie-eign force-pushed the use-subprocess-timeout branch from 4c1fda8 to ec130d6 Compare April 22, 2026 21:26
@ngie-eign
ngie-eign marked this pull request as draft April 23, 2026 01:03
@ngie-eign

ngie-eign commented Apr 23, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

Some of my recent changes upset win32 according to the test failures. Let me see if I can track down what's going on there then bring this out of draft again.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Byron

Byron commented Apr 25, 2026

Copy link
Copy Markdown
Member

I think it's unrelated.

The following was suggested elsewhere: #2128 (comment). I recommend to watch it and rebase once the PR is merged.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Byron

Byron commented May 6, 2026

Copy link
Copy Markdown
Member

This is a supposed fix, maybe fragile, maybe too specific, but I also don't know what else to do here.
Also it seems unrelated to this PR.

diff --git a/git/index/base.py b/git/index/base.py
index 2276343f..xxxxxxx 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -1284,6 +1284,18 @@ class IndexFile(LazyMixin, git_diff.Diffable, Serializable):
             )
             for line in stderr.splitlines():
+                # Git for Windows may emit non-fatal warnings when creating symlinks, e.g.:
+                # "warning: created file symlink 'name' pointing to 'target';"
+                # followed by:
+                # "set the `symlink` gitattribute to `dir` if a directory symlink is required"
+                # These are not checkout failures and should not be treated as unknown errors.
+                if line.startswith("warning: created file symlink "):
+                    continue
+                if line.startswith("set the `symlink` gitattribute to `dir`"):
+                    continue
+
                 if not line.startswith("git checkout-index: ") and not line.startswith("git-checkout-index: "):
                     is_a_dir = " is a directory"
                     unlink_issue = "unable to unlink old '"

Better would be to set xfail:

@pytest.mark.xfail(
    sys.platform == "win32" and Git().config("core.symlinks") == "true",
    ...
)

@ngie-eign Your help here would be appreciated. Maybe then the PR can be taken out of draft as well.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Byron

Byron commented Jul 20, 2026

Copy link
Copy Markdown
Member

Closing as the PR is conflicted and lacks interaction. Please feel free to recreate the PR if there is still interest.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Byron Byron closed this Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

Copilot code review Copilot
Copilot review effort
Applies to this pull request for everyone.Learn more about Copilot code review.
Copilot left review comments
@Byron Byron Byron requested changes
+1 more reviewer
@github-advanced-security github-advanced-security[bot] github-advanced-security[bot] left review comments
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@ngie-eign @Byron @github-advanced-security
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.