Skip to content

fix(git): stream push output to avoid spurious 30s timeout (#963)#1531

Open
ousamabenyounes wants to merge 1 commit into
rtk-ai:developfrom
ousamabenyounes:fix/issue-963
Open

fix(git): stream push output to avoid spurious 30s timeout (#963)#1531
ousamabenyounes wants to merge 1 commit into
rtk-ai:developfrom
ousamabenyounes:fix/issue-963

Conversation

@ousamabenyounes
Copy link
Copy Markdown
Contributor

@ousamabenyounes ousamabenyounes commented Apr 25, 2026

Problem (#963)

`rtk git push` reportedly times out: users see `bash tool terminated command after exceeding timeout 30000 ms` while plain `git push` to the same remote completes fine. P1-critical because every Claude Code git push goes through rtk.

Root cause

`run_push` used `cmd.stdin(Stdio::inherit()).output()`. `Command::output()` captures both stdout and stderr until the child exits.

Git push prints its progress (`Counting objects` / `Compressing objects` / `Writing objects`) to stderr and may prompt for SSH passphrases or HTTPS credentials. With stderr captured nothing reached the terminal until the process finished, so:

  1. Claude Code's bash tool saw zero output for 30+ seconds and killed the command — exactly the 30000 ms message in the issue.
  2. Long pushes / slow remotes / 2FA prompts looked like a hang to humans.
  3. Auth prompts that git writes to stderr (rather than `/dev/tty`) were invisible until the user gave up and Ctrl+C'd.

The original code traded interactivity for a one-line compact summary (`ok master`). Push output is small — a handful of lines — so the saving was negligible while the cost (timeout, hidden prompts) was severe.

Fix

Inherit all three streams and use `cmd.status()` instead of `.output()`. Progress and auth prompts now flow through in real time, the bash tool keeps seeing output, and the exit code propagates via the existing `exit_code_from_status` helper. Tracking still records the invocation; raw/filtered token counts deliberately collapse to 0 because we don't capture.

Test plan

  • `cargo fmt --all`
  • `cargo test --all` — 1681 passed, 0 failed
  • `cargo build --release` clean
  • No new unit test: the bug is wall-clock + stream buffering against a real network remote, which can't be exercised hermetically. Existing git fetch/pull/clone tests cover the surrounding plumbing; this change only swaps the IO mode for `push`.

Notes

  • Behaviour change: users will now see git's native progress output instead of `ok master`. This matches plain `git push` behaviour and is what the issue reporter expects.
  • No filter regressions: `run_pull`, `run_fetch`, `run_clone` are untouched; only `run_push` is modified.

Closes #963

🤖 Generated with Claude Code


Vibe Coded by Ousama Ben Younes
Developed With Ora Studio (Claude Code)

@pszymkowiak pszymkowiak added bug Something isn't working effort-small Quelques heures, 1 fichier filter-quality Filter produces incorrect/truncated signal labels Apr 25, 2026
@pszymkowiak
Copy link
Copy Markdown
Collaborator

[w] wshm · Automated triage by AI

📊 Automated PR Analysis

🐛 Type bug-fix
🟡 Risk medium

Summary

Fixes a critical timeout issue where rtk git push would be killed by Claude Code's 30-second bash timeout because stdout/stderr were buffered until process exit. The fix switches from Command::output() (which captures streams) to Command::status() with all three stdio streams inherited, allowing git's progress output and auth prompts to flow through in real time.

Review Checklist

  • Tests present
  • Breaking change
  • Docs updated

Linked issues: #963


Analyzed automatically by wshm · This is an automated analysis, not a human review.

@aeppling
Copy link
Copy Markdown
Contributor

Hello @ousamabenyounes , thanks for addressing this.

The fix is not correct because loose of filtering, to fix this we need to use run_streaming + FilterMode::Streaming existing infrastructure that has been added in 0.37.0 for streaming commands.

@aeppling aeppling self-assigned this May 14, 2026
## Problem (rtk-ai#963)

`rtk git push` reportedly times out: users see
`bash tool terminated command after exceeding timeout 30000 ms` while
plain `git push` to the same remote completes fine. P1-critical because
every Claude Code git push goes through rtk.

## Root cause

`run_push` used `cmd.stdin(Stdio::inherit()).output()`. `Command::output()`
captures both stdout and stderr until the child exits. Git push prints
its progress (`Counting objects` / `Compressing objects` / `Writing
objects`) to stderr and may prompt for SSH passphrases or HTTPS
credentials. With stderr captured, Claude Code's bash tool saw zero
output for 30+ seconds and killed the command — exactly the 30000 ms
message in the issue.

## Fix

Rewrite `run_push` on top of the streaming infrastructure that already
exists for this exact purpose (`stream::run_streaming` +
`FilterMode::Streaming`, added in 0.37.0).

A custom `GitPushStreamFilter` implements `StreamFilter`:

- `feed_line` drops the high-volume progress phases (Enumerating /
  Counting / Compressing / Writing objects, Delta compression, Total)
  and passes every other line through (remote: messages, To <url>, ref
  updates, errors). Lines flow to the terminal as git emits them, so
  the bash tool never sees a 30s silence.
- `on_exit` appends a compact `ok <ref>` / `ok (up-to-date)` summary on
  success, preserving the token-saving payoff of the previous filter.
- Stdin is inherited (StdinMode::Inherit) so SSH passphrase and HTTPS
  credential prompts still reach the user.

Tracking now records the actual raw output and the filtered output
(rather than empty strings).

## Test plan

- [x] `cargo fmt --all -- --check`
- [x] `cargo clippy --all-targets -- -D warnings` — clean
- [x] `cargo test --all` — 1876 passed, 0 failed, 6 ignored
- Six new unit tests cover: progress-prefix drop, up-to-date summary,
  remote message passthrough, no-summary-on-failure, first-ref-wins,
  verbose-output token savings (>=40% on a representative payload).
- End-to-end behaviour cannot be exercised hermetically (the bug is
  wall-clock + stream buffering against a real network remote), but the
  underlying `run_streaming` path is already covered by existing tests
  in `src/core/stream.rs`.

## Notes

- Behaviour change: users now see git's native output line-by-line (with
  progress phases stripped) plus a final `ok <ref>` summary, instead of
  just the compact summary. This matches plain `git push` more closely
  and is what the issue reporter expects.
- No regression for other filters: `run_pull`, `run_fetch`, `run_clone`
  are untouched; only `run_push` is modified.

Closes rtk-ai#963

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
_Vibe Coded by Ousama Ben Younes_
_Developed With Ora Studio (Claude Code)_

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ousamabenyounes
Copy link
Copy Markdown
Contributor Author

Thanks for the steer @aeppling — rewritten on top of stream::run_streaming + FilterMode::Streaming in a402997.

GitPushStreamFilter (StreamFilter) now:

  • feed_line drops the high-volume progress phases (Enumerating / Counting / Compressing / Writing objects, Delta compression, Total) and passes through everything else (remote: messages, To <url>, ref updates, errors). Lines flow to the terminal as git emits them — so the bash tool never sees the 30 s silence — while still cutting the bulk of the noise.
  • on_exit appends a compact ok <ref> / ok (up-to-date) summary on success, restoring the token-saving payoff of the previous filter.
  • StdinMode::Inherit so SSH passphrase / HTTPS credential prompts still reach the user.
  • Tracking now records the real raw + filtered output (the previous force-passthrough commit was zeroing both).

Six new unit tests in src/cmds/git/git.rs cover progress-prefix drop, up-to-date, remote passthrough, no-summary-on-failure, first-ref-wins-for-summary, and a token-savings assertion (>=40% on a representative payload).

cargo fmt --all -- --check, cargo clippy --all-targets -- -D warnings, and cargo test --all (1876 passed, 0 failed) all green locally. Ready for re-review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working effort-small Quelques heures, 1 fichier filter-quality Filter produces incorrect/truncated signal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

When using the rtk git push command, it sometimes times out

3 participants