Skip to content

fix(git): keep machine output raw - #2573

Closed
YOMXXX wants to merge 1 commit into
rtk-ai:developfrom
YOMXXX:fix/issue-2487-git-machine-output
Closed

YOMXXX wants to merge 1 commit into
rtk-ai:developfrom
YOMXXX:fix/issue-2487-git-machine-output

Conversation

@YOMXXX

@YOMXXX YOMXXX commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #2487.

Summary

  • Keep git commands raw in hook rewrite when stdout is piped, redirected to a file, or explicitly machine-readable (--porcelain, --format, --name-only, -z, etc.).
  • Preserve normal model-facing rewrites such as bare git diff and later segments in compound commands.
  • Make direct rtk git status --porcelain, rtk git log --format=..., and rtk git diff --name-only pass through byte-for-byte instead of compacting.

Verification

  • cargo +1.93.0 test rewrite_git_ -- --nocapture
  • cargo +1.93.0 test rewrite_redirect -- --nocapture
  • cargo +1.93.0 test registry -- --nocapture
  • cargo +1.93.0 test git::git::tests::test_ -- --nocapture
  • CLI smoke: rewrite passthrough for git status --porcelain | wc -l, git log --format=%H | sort, git diff --name-only HEAD~1..HEAD; rewrite still active for bare git diff
  • CLI smoke: rtk git diff --name-only, rtk git status --porcelain, and rtk git log --format=%H -3 match native git via cmp
  • cargo +1.93.0 fmt --all -- --check
  • cargo +1.93.0 clippy --all-targets
  • cargo +1.93.0 test --all -- --skip small_grep_not_worse_than_plain
  • git diff --check

pidefrem added a commit to pidefrem/rtk that referenced this pull request Jul 18, 2026
rtk git diff --name-only appended a spurious '\n\nChanges:\n' header
(git.rs run_diff compact path), and the rewrite hook rewrote piped
machine-bound git commands (git diff | wc -l), silently corrupting
consumers: wc -l counts, for f in $(git diff --name-only), git apply.

Adds diff/status/log machine-output detection so run_diff/run_log/
run_status pass through raw when a parseable format is requested, and a
registry-level guard so piped/redirected git output stays unrewritten.

Re-derived onto current develop from YOMXXX's PR rtk-ai#2573
(fix/issue-2487-git-machine-output), which was ~154 commits behind.
Fixes rtk-ai#2487, rtk-ai#1918.

Co-authored-by: YOMXXX <YOMXXX@users.noreply.github.com>
pidefrem added a commit to pidefrem/rtk that referenced this pull request Jul 22, 2026
rtk git diff --name-only appended a spurious '\n\nChanges:\n' header
(git.rs run_diff compact path), and the rewrite hook rewrote piped
machine-bound git commands (git diff | wc -l), silently corrupting
consumers: wc -l counts, for f in $(git diff --name-only), git apply.

Adds diff/status/log machine-output detection so run_diff/run_log/
run_status pass through raw when a parseable format is requested, and a
registry-level guard so piped/redirected git output stays unrewritten.

Re-derived onto current develop from YOMXXX's PR rtk-ai#2573
(fix/issue-2487-git-machine-output), which was ~154 commits behind.
Fixes rtk-ai#2487, rtk-ai#1918.

Co-authored-by: YOMXXX <YOMXXX@users.noreply.github.com>
pidefrem added a commit to pidefrem/rtk that referenced this pull request Jul 22, 2026
rtk git diff --name-only appended a spurious '\n\nChanges:\n' header
(git.rs run_diff compact path), and the rewrite hook rewrote piped
machine-bound git commands (git diff | wc -l), silently corrupting
consumers: wc -l counts, for f in $(git diff --name-only), git apply.

Adds diff/status/log machine-output detection so run_diff/run_log/
run_status pass through raw when a parseable format is requested, and a
registry-level guard so piped/redirected git output stays unrewritten.

Re-derived onto current develop from YOMXXX's PR rtk-ai#2573
(fix/issue-2487-git-machine-output), which was ~154 commits behind.
Fixes rtk-ai#2487, rtk-ai#1918.

Co-authored-by: YOMXXX <YOMXXX@users.noreply.github.com>
kylehgc added a commit to kylehgc/rtk that referenced this pull request Jul 28, 2026
… repairing

Three changes to the fork-maintenance rules, in CONTEXT.md (the authority) and
mirrored into the do-issue skill (its executable form).

1. Sync conflicts: upstream wins, always.

CONTEXT.md previously asked the Conflicted Sync PR to record "why the upstream
version won (or why the fork's was kept)". That parenthetical licensed drift.
The fork is additive to upstream: it adds what upstream lacks, it does not hold
a different opinion about what upstream already has. If upstream covers it at
all — code, test, or comment — upstream's version is taken verbatim. No keeping
the fork's wording, no blending, no grafting fork comments onto upstream code.

Only genuinely additive fork code survives a conflict, and "additive" must be
proven, not assumed:

    git show upstream/develop:<file> | grep -n '<symbol>'

A fork fix upstream has since solved its own way is a duplicate, not an
addition. Surviving additive code also adopts upstream's current style even
when the fork's still compiles.

This is easy to get backwards, so both files cite the worked example: two
resolutions on 2026-07-28 kept fork wording as "additive" when upstream already
had run_in_terminal handling; corrected by e928f0f.

2. Declined adoption: don't repair a candidate that doesn't hold up.

New CONTEXT.md term plus a Phase 3 section in the skill. If an upstream PR is
incorrect, or its bug won't reproduce on current develop, close the fork ticket
with a note rather than fixing the PR up and shipping it.

Repairing one silently converts an Adoption into an Original fix that still
carries the contributor's name, hides that the fork ships code upstream never
validated, and takes on the Phase 7 Upstream PR obligation with nobody deciding
to. A real bug with a wrong fix is a new Original fix with its own ticket.

Declining never touches the upstream PR — that is Contributor outreach, a
separate decision. Partial decline is explicitly allowed; rtk-ai#2573 is the worked
example (git.rs half adopted, registry.rs half dropped as superseded).

3. No change needed for never-squash — already enforced in CONTEXT.md's
Adoption entry and the skill's Phase 6. Not duplicated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
kylehgc added a commit to kylehgc/rtk that referenced this pull request Jul 28, 2026
…stats

Fork-authored amendment on top of 46d16ea (cherry-picked from upstream rtk-ai#2573).
Kept separate so the contributor's commit stays intact and attributable.

Three defects found by code review on PR #68, each reproduced against native
git before and after.

1. `--word-porcelain` is not a git flag.

   `git diff --word-porcelain` exits 129 (unknown option). The real
   machine-readable spelling is `--word-diff=porcelain`, and because the guard
   uses `matches!` on exact equality it never matched. So the adopted list had
   one dead arm and one real gap. Replaced the former with the latter.

   `--word-diff=plain` and `--word-diff=color` are human-facing and stay
   compacted; only the porcelain variant passes through.

     before: rtk git diff --word-diff=porcelain -> compacted
     after : native 6706 bytes | rtk 6706 bytes

2. `-z` was unhandled for `git log`.

   Issue #48 names `-z` explicitly, but log_args_request_machine_output only
   matched --format/--pretty variants. `git log -z --name-only` carries no
   custom format, so it fell to the compact path — which injects its own
   --pretty=format:<MARKER>, -10 and --no-merges and then filters. That is
   precisely the corruption this guard exists to prevent.

     before: native 2267 bytes | rtk  564 bytes (decorated)
     after : native 2267 bytes | rtk 2267 bytes

3. `--no-color` was treated as machine output.

   It only suppresses ANSI and says nothing about the format, so listing it
   bought a full passthrough and silently disabled compaction for a commonly
   passed flag — a cost with no faithfulness gain. Removed.

     before: native 6456 bytes | rtk 6456 bytes (passthrough)
     after : native 6456 bytes | rtk 6365 bytes (compacted)

Also switches the three new log/status tracking calls from
`timer.track(.., &stdout, &stdout)` to `timer.track_passthrough(..)`. Equal
non-zero token counts record 0%-savings rows that dilute `rtk gain`;
tracking.rs documents track_passthrough for exactly this, and run_passthrough
in this same file already uses it. The pre-existing calls in run_diff and
run_show are left alone — they predate this change.

Tests: the contributor's diff-flag test asserted `--word-porcelain` is machine
output, encoding the belief that it is a git flag. Updated to assert the intent
instead — the real flag matches, the non-flag does not, and the human-facing
word-diff modes stay compacted.

Adds tests/git_machine_output_test.rs. The existing unit tests only cover the
flag predicates, so swapping `print!` back to `println!("{}", stdout.trim())`
would still pass all of them while dropping the trailing newline. The new test
runs the built binary (CARGO_BIN_EXE_rtk, no install needed) against real git
and compares bytes, with a counterweight case asserting bare `git status` and
`git diff --no-color` stay compacted so the guard can't be widened until
byte-equality passes trivially.

Not addressed, deliberately: the ~90 lines duplicating run_passthrough, and the
pre-existing loss of stdout on non-zero exit in run_diff (verified present
before this change on --numstat/--name-only/--raw alike). Both are separate
concerns from this adoption.

Quality gate: fmt clean, clippy 0 warnings, cargo test --all 2585 passed,
0 failed (LASTEXITCODE=0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@KuSh KuSh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for tackling #2487 — the shape of the fix (detect a machine-output request, pass the command through raw) is the right one, and the status / --porcelain path looks good.

I built this branch and probed the resulting binary. A few things block a merge:

  • A panic. git -C (or -c / --git-dir / --work-tree) as the final token indexes past the token slice and aborts the whole rtk discover run.
  • The original bug still reproduces. --pretty=%H is git's implicit tformat: but isn't detected, so rtk git log --pretty=%H still truncates 1185 commits to 50 — in both the filter and the rewriter.
  • Two false positives in the machine-output lists: --no-color (disables diff compaction for any agent that passes it) and --word-porcelain (not a real git flag — the real one, --word-diff=porcelain, is missed).
  • A regression against develop. Making a piped git segment unrewritable also drops the downstream rewrite develop already performs (git log -10 | grep feat → git log -10 | rtk grep feat).
  • Plus an unbounded git log passthrough and a quote-blind token scan.

One process note: the branch is based on ee9e2f8 and is currently conflicting. Develop has since reworked pipe handling (TokenKind::Pipe(PipeKind), |&) and already returns None for cases like git status --porcelain | wc -l — so a good part of the pipe hunk should be redundant once you rebase. Worth re-deriving what's still needed on top of the new pipe handling rather than porting it verbatim.

Details inline.

Comment thread src/discover/registry.rs
Comment on lines +915 to +926
let mut i = 1;
while i < tokens.len() {
let token = tokens[i].0;
match token {
"-C" | "-c" | "--git-dir" | "--work-tree" => i += 2,
"--no-pager" | "--no-optional-locks" | "--bare" | "--literal-pathspecs" => i += 1,
_ if token.starts_with("--git-dir=") || token.starts_with("--work-tree=") => i += 1,
_ => break,
}
}

Some(tokens[i..].iter().map(|token| token.0).collect())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[high] Slice-index panic when a git global option is the last token.

i += 2 for -C | -c | --git-dir | --work-tree is unbounded, so when one of those is the final token i becomes len + 1 and tokens[i..] panics.

Repro on this branch:

rewrite_command("git -C")
// panicked at src/discover/registry.rs:926:
// range start index 3 out of range for slice of length 2

Reachable from any command string the hook or rtk discover processes — git -c, git --git-dir, or a truncated/typo'd entry in shell history — and it takes down the whole rtk discover run.

Fix: i = i.saturating_add(2).min(tokens.len()), or return None when the value token is missing.

Comment thread src/cmds/git/git.rs
Comment on lines +75 to +86
fn log_args_request_machine_output(args: &[String]) -> bool {
args.iter().enumerate().any(|(idx, arg)| {
arg == "--format"
|| arg.starts_with("--format=")
|| arg.starts_with("--pretty=format:")
|| arg.starts_with("--pretty=tformat:")
|| (arg == "--pretty"
&& args
.get(idx + 1)
.is_some_and(|next| next.starts_with("format:") || next.starts_with("tformat:")))
})
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[high] --pretty=%… isn't detected, so the bug from #2487 still reproduces.

Git treats --pretty=<string containing a % placeholder> as an implicit --pretty=tformat:<string>, but this only matches --format, --format=, --pretty=format: and --pretty=tformat:.

Verified against a build of this branch, in this repo:

rtk git log --pretty=%H   →     50 commits
git log --pretty=%H       →   1185 commits

The RTK -50 default is still injected and the output is silently truncated — exactly the class of bug this PR sets out to fix. Needs a "value contains %" rule for --pretty= (and for the separated --pretty <value> form below).

Comment thread src/discover/registry.rs
Comment on lines +954 to +959
|| arg.starts_with("--pretty=format:")
|| arg.starts_with("--pretty=tformat:")
|| (*arg == "--pretty"
&& args.get(idx + 1).is_some_and(|next| {
next.starts_with("format:") || next.starts_with("tformat:")
}))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[high] Same --pretty=%… gap in the hook rewriter.

Verified: rewrite_command("git log --pretty=%H") → Some("rtk git log --pretty=%H"), so an unpiped, unredirected git log --pretty=%H still gets routed into the truncating filter.

Both detectors need the % rule, and they need to stay in sync with log_args_request_machine_output in src/cmds/git/git.rs.

Comment thread src/cmds/git/git.rs
matches!(
arg.as_str(),
"-z"
| "--no-color"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[medium] --no-color is not a machine-output signal — this kills diff compaction.

--no-color says nothing about machine readability; it's precisely what an agent passes to avoid ANSI in its capture. Classifying it as machine output means any agent that habitually passes it gets 0% savings on git.

Verified on this branch: rtk git diff --no-color emitted 2602 bytes — byte-identical to raw git diff --no-color — where develop emits the compacted stat+diff form.

The same entry at src/discover/registry.rs:944 makes the rewriter return None for git diff --no-color and git log --no-color -10, so the hook stops rewriting them at all.

Please drop --no-color from both lists.

Comment thread src/discover/registry.rs
| "--name-status"
| "--numstat"
| "--raw"
| "--word-porcelain"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[medium] --word-porcelain is not a git flag; the real machine mode is missed.

git diff --word-porcelain just prints git's usage error, so this arm is dead code. The actual machine-readable word diff is --word-diff=porcelain, which neither this function nor diff_args_request_machine_output (src/cmds/git/git.rs:98) matches — so the real machine format still gets compacted and rewritten.

Replace the dead entry with a --word-diff=porcelain check, in both places.

Comment thread src/discover/registry.rs
seg.to_string()
} else {
rewrite_segment(seg, excluded, transparent_prefixes)
rewrite_segment_for_consumer(seg, excluded, transparent_prefixes, true)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[medium] stdout_is_piped: true makes the whole pipeline unrewritable, dropping downstream rewrites develop already performs.

When the git segment returns None here, any_changed stays false and — with no following operator — rewrite_compound returns None for the entire command. The PR's own test changes encode that (git log -10 | grep feat → None).

But develop (rtk 0.46.0) already keeps piped git raw and still rewrites the consumer:

git log -10 | grep feat   →   git log -10 | rtk grep feat
git status | grep foo     →   git status | rtk grep foo

Merging as-is regresses both.

Also worth flagging for the rebase: this branch is based on ee9e2f8, and develop has since reworked pipe handling (TokenKind::Pipe(PipeKind), |&) and already returns None for cases like git status --porcelain | wc -l. A good part of this hunk should be redundant once rebased — please re-derive what's actually still needed on top of the new pipe handling instead of porting it verbatim.

Comment thread src/cmds/git/git.rs
Comment on lines +467 to +490
if log_args_request_machine_output(args) {
let mut cmd = git_cmd(global_args);
cmd.arg("log");
for arg in args {
cmd.arg(arg);
}

let result = exec_capture(&mut cmd).context("Failed to run git log")?;
if !result.success() {
eprintln!("{}", result.stderr);
return Ok(result.exit_code);
}

print!("{}", result.stdout);

timer.track(
&format!("git log {}", args.join(" ")),
&format!("rtk git log {} (passthrough)", args.join(" ")),
&result.stdout,
&result.stdout,
);

return Ok(0);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[medium] The passthrough drops the implicit commit cap, so output becomes unbounded.

This branch runs git log <args> with no -N and no --no-merges, unlike the path below it which injects -50 / -10.

Verified: rtk git log --format=%H (no explicit limit) now prints the full 1185-commit history in this repo; on develop it printed 50. A single such call can flood the agent's context — the thing RTK exists to prevent.

Suggest keeping a large default cap when the user gave no -n / --max-count, or at minimum documenting the unbounded behaviour.

Comment thread src/discover/registry.rs
}

fn git_command_tail_tokens(cmd: &str) -> Option<Vec<&str>> {
let tokens = split_token_spans(cmd);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[low] split_token_spans is quote-blind, so flag words inside quoted arguments suppress rewriting.

It splits on whitespace only, ignoring the quoting tokenize() already handles.

Verified:

rewrite_command("git commit -m \"add --no-color to diff\"")   →   None
rewrite_command("git log -- --name-only")                    →   None

Both silently lose the rewrite (and the savings) because a flag-looking word appears inside a quoted message or after --. Using tokenize() and stopping the scan at -- handles both.

@KuSh KuSh self-assigned this Aug 29, 2026

@KuSh KuSh left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Followed up on the fork-side amendment kylehgc/rtk@da407dc proposed on top of this PR. It picks up two real defects that didn't come up in my review at all, but the highest-severity items above are untouched, so the request for changes still stands.

Caught by the amendment, not by my review

  • -z was unmatched for git log. git log -z --name-only carries no custom format, so it fell through to the compact path and had --pretty=format:<MARKER>, -10 and --no-merges injected — corruption of a machine-readable format, exactly what this guard exists to prevent. Correctly fixed. It does widen an existing problem, though; see the inline note on run_log.
  • The new passthrough branches were recording 0%-savings rows. timer.track(.., &stdout, &stdout) logs equal non-zero token counts on every passthrough, which dilutes rtk gain. track_passthrough (src/core/tracking.rs:1428) records input_tokens=0, output_tokens=0 for precisely this case — right call, and consistent with run_passthrough in the same file.

The --no-color and --word-porcelain corrections only land on half the path. Both are fixed in src/cmds/git/git.rs but not in src/discover/registry.rs. For --word-diff=porcelain the end-to-end result still comes out right (the rewriter routes it to rtk, git.rs then passes it through raw), but the two lists should come from one source rather than drifting. For --no-color the fix is inert as written — details inline on registry.rs.

Still open: the panic on a trailing git -C; --pretty=%H in both the filter and the rewriter (#2487's headline case); the pipe regression; the uncapped log passthrough; the quote-blind token scan.


New findings, in the amendment's own tests/git_machine_output_test.rs. That file isn't part of this PR, so these can't be pinned inline:

1. [medium] human_facing_git_output_is_still_compacted is flaky. It asserts rtk git diff --no-color HEAD~1..HEAD is strictly smaller than native — which depends entirely on what the tip commit happens to be, since compaction prepends a stat header that outweighs the savings on small diffs. Measured across the last 20 non-merge commits on develop, 2 invert:

6370e79   native 2148 bytes   rtk 2171 bytes   ← test would fail
e5cecd3   native 2206 bytes   rtk 2208 bytes   ← test would fail

That's a ~10% chance of a red build for reasons unrelated to the change. Assert against a fixed synthetic diff or a pinned commit range instead of HEAD~1.

2. [medium] run() ignores exit status, so the byte-equality test passes vacuously in CI. It returns Some(stdout) for anything that spawns. The test job checks out at the default fetch-depth: 1 (.github/workflows/ci.yml:133, cargo test --all at :136), so HEAD~1..HEAD is an unknown revision there: native git returns empty stdout, let Some(native) = … else { continue } does not skip (it's Some(vec![])), rtk returns empty too, and assert_eq!("", "") passes. All four diff … HEAD~1..HEAD cases contribute zero coverage in CI, silently — and the --no-color counterweight is skipped outright by its is_empty() guard. Check out.status.success() and return None on failure so those cases genuinely skip, and ideally build the fixture history with git init in a temp dir instead of depending on the checkout's history.

3. [low] The one case #2487 is actually about stays uncovered. The log cases are --format=%H and --pretty=format:%H; neither exercises --pretty=%H, the spelling that still truncates. That's the regression test for the original issue — worth adding once the predicate is fixed.

4. [nit] The test writes to the developer's real tracking DB. Each run invokes the binary ~13 times with no RTK_DB_PATH override, so rows land in ~/.local/share/rtk/history.db (verified: two invocations moved it 58942 → 58944 rows). This is pre-existing across the suite — tests/guard_integration_test.rs and friends do the same — so not something the amendment introduced. But given the commit's stated motivation is keeping rtk gain undiluted, an .env("RTK_DB_PATH", tmp) would match that intent.

Comment thread src/cmds/git/git.rs
Comment on lines +75 to +86
fn log_args_request_machine_output(args: &[String]) -> bool {
args.iter().enumerate().any(|(idx, arg)| {
arg == "--format"
|| arg.starts_with("--format=")
|| arg.starts_with("--pretty=format:")
|| arg.starts_with("--pretty=tformat:")
|| (arg == "--pretty"
&& args
.get(idx + 1)
.is_some_and(|next| next.starts_with("format:") || next.starts_with("tformat:")))
})
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Update after kylehgc/rtk@da407dc.

The amendment adds -z here, which is a genuine catch I missed: git log -z --name-only carries no custom format, so it was falling to the compact path and getting --pretty=format:<MARKER>, -10 and --no-merges injected — exactly the corruption this guard exists to prevent.

But --pretty=%H is still unmatched, so #2487's headline case is unchanged: rtk git log --pretty=%H returns 50 commits where git returns 1185. Git expands --pretty=<string containing %> to --pretty=tformat:<string>; this predicate needs that rule, and so does the separated --pretty <value> form just below.

This is the case the issue is filed about — it should land before merge.

Comment thread src/cmds/git/git.rs
Comment on lines +467 to +490
if log_args_request_machine_output(args) {
let mut cmd = git_cmd(global_args);
cmd.arg("log");
for arg in args {
cmd.arg(arg);
}

let result = exec_capture(&mut cmd).context("Failed to run git log")?;
if !result.success() {
eprintln!("{}", result.stderr);
return Ok(result.exit_code);
}

print!("{}", result.stdout);

timer.track(
&format!("git log {}", args.join(" ")),
&format!("rtk git log {} (passthrough)", args.join(" ")),
&result.stdout,
&result.stdout,
);

return Ok(0);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Update after kylehgc/rtk@da407dc.

The amendment doesn't change this branch, but it widens what reaches it. Adding -z to log_args_request_machine_output means git log -z --name-only now lands here uncapped, where it previously took the compact path with -10. On this repo that turns a 10-commit summary into the full 1185-commit history, with per-commit file lists.

Both changes are individually right; together they make the missing default cap considerably more reachable. A large default -n when the user gave neither -n nor --max-count keeps the -z fix without the flood.

Comment thread src/discover/registry.rs
args.iter().enumerate().any(|(idx, arg)| {
matches!(
*arg,
"-z" | "--no-color"

@KuSh KuSh Aug 29, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Update after kylehgc/rtk@da407dc.

The amendment removes --no-color from diff_args_request_machine_output in src/cmds/git/git.rs, but not from this list. That leaves the fix inert on the path that actually matters: with --no-color still here, rewrite_command("git diff --no-color") returns None, the hook never rewrites the command, raw git runs, and the compaction restored in git.rs is never reached.

The entry has to come out of both lists — ideally with the two predicates sharing one source so they can't drift apart again.

@KuSh

KuSh commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator

Thank you for working on this. The rewrite side is now handled by the per-rule pipeline safety model from #3128 (merged 2026-07-23) and #3343 (merged 2026-09-07), so commands like git status --porcelain | wc -l, git log --format=%H | sort and git diff > out.patch are no longer rewritten, and #3681 (merged 2026-09-12) moved git status, log and diff argument handling onto the shared argument tokenizer, so the detection added here no longer fits the current code. rtk git diff --name-only, --name-status, --numstat, --raw, -z, rtk git status -z and rtk git log --format=%H already print exactly what git prints. Two cases still differ: rtk git status --porcelain (and --porcelain=v2) drops git's final newline, and rtk git log --pretty=format:%h adds a trailing newline git does not print; an issue or a narrow PR against the current src/cmds/git/git_cmd.rs would be welcome for either. If I missed something this PR still covers, please comment and it can be reopened.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rtk compacts machine-bound git output (--porcelain / --name-only / piped), silently corrupting consumers

2 participants