Skip to content

Commit 46d16ea

Browse files
YOMXXXkylehgc
authored andcommitted
fix(git): keep machine output raw
1 parent e84fdfd commit 46d16ea

1 file changed

Lines changed: 138 additions & 2 deletions

File tree

‎src/cmds/git/git.rs‎

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,39 @@ fn uses_compact_status_path(args: &[String]) -> bool {
7676
saw_branch
7777
}
7878

79+
fn status_args_request_machine_output(args: &[String]) -> bool {
80+
args.iter()
81+
.any(|arg| arg == "-z" || arg == "--porcelain" || arg.starts_with("--porcelain="))
82+
}
83+
84+
fn log_args_request_machine_output(args: &[String]) -> bool {
85+
args.iter().enumerate().any(|(idx, arg)| {
86+
arg == "--format"
87+
|| arg.starts_with("--format=")
88+
|| arg.starts_with("--pretty=format:")
89+
|| arg.starts_with("--pretty=tformat:")
90+
|| (arg == "--pretty"
91+
&& args
92+
.get(idx + 1)
93+
.is_some_and(|next| next.starts_with("format:") || next.starts_with("tformat:")))
94+
})
95+
}
96+
97+
fn diff_args_request_machine_output(args: &[String]) -> bool {
98+
args.iter().any(|arg| {
99+
matches!(
100+
arg.as_str(),
101+
"-z"
102+
| "--no-color"
103+
| "--name-only"
104+
| "--name-status"
105+
| "--numstat"
106+
| "--raw"
107+
| "--word-porcelain"
108+
)
109+
})
110+
}
111+
79112
fn build_status_command(args: &[String], global_args: &[String]) -> Command {
80113
let mut cmd = git_cmd(global_args);
81114
cmd.arg("status");
@@ -129,10 +162,12 @@ fn run_diff(
129162
.iter()
130163
.any(|arg| arg == "--stat" || arg == "--numstat" || arg == "--shortstat");
131164

165+
let wants_machine_output = diff_args_request_machine_output(args);
166+
132167
// Check if user wants compact diff (default RTK behavior)
133168
let wants_compact = !args.iter().any(|arg| arg == "--no-compact");
134169

135-
if wants_stat || !wants_compact {
170+
if wants_machine_output || wants_stat || !wants_compact {
136171
// User wants stat or explicitly no compacting - pass through directly
137172
let mut cmd = git_cmd(global_args);
138173
cmd.arg("diff");
@@ -150,7 +185,11 @@ fn run_diff(
150185
return Ok(result.exit_code);
151186
}
152187

153-
println!("{}", result.stdout.trim());
188+
if wants_machine_output {
189+
print!("{}", result.stdout);
190+
} else {
191+
println!("{}", result.stdout.trim());
192+
}
154193

155194
timer.track(
156195
&format!("git diff {}", args.join(" ")),
@@ -444,6 +483,31 @@ fn run_log(
444483

445484
let timer = tracking::TimedExecution::start();
446485

486+
if log_args_request_machine_output(args) {
487+
let mut cmd = git_cmd(global_args);
488+
cmd.arg("log");
489+
for arg in args {
490+
cmd.arg(arg);
491+
}
492+
493+
let result = exec_capture(&mut cmd).context("Failed to run git log")?;
494+
if !result.success() {
495+
eprintln!("{}", result.stderr);
496+
return Ok(result.exit_code);
497+
}
498+
499+
print!("{}", result.stdout);
500+
501+
timer.track(
502+
&format!("git log {}", args.join(" ")),
503+
&format!("rtk git log {} (passthrough)", args.join(" ")),
504+
&result.stdout,
505+
&result.stdout,
506+
);
507+
508+
return Ok(0);
509+
}
510+
447511
let mut cmd = git_cmd(global_args);
448512
cmd.arg("log");
449513

@@ -856,6 +920,40 @@ fn filter_status_with_args(output: &str) -> String {
856920
fn run_status(args: &[String], verbose: u8, global_args: &[String]) -> Result<i32> {
857921
let timer = tracking::TimedExecution::start();
858922

923+
if status_args_request_machine_output(args) {
924+
let mut cmd = git_cmd(global_args);
925+
cmd.arg("status");
926+
cmd.args(args);
927+
let result = exec_capture(&mut cmd).context("Failed to run git status")?;
928+
929+
if !result.success() {
930+
if !result.stderr.trim().is_empty() {
931+
eprint!("{}", result.stderr);
932+
}
933+
timer.track(
934+
&format!("git status {}", args.join(" ")),
935+
&format!("rtk git status {} (passthrough)", args.join(" ")),
936+
&result.stdout,
937+
&result.stdout,
938+
);
939+
return Ok(result.exit_code);
940+
}
941+
942+
if verbose > 0 || !result.stderr.is_empty() {
943+
eprint!("{}", result.stderr);
944+
}
945+
print!("{}", result.stdout);
946+
947+
timer.track(
948+
&format!("git status {}", args.join(" ")),
949+
&format!("rtk git status {} (passthrough)", args.join(" ")),
950+
&result.stdout,
951+
&result.stdout,
952+
);
953+
954+
return Ok(0);
955+
}
956+
859957
// Keep a narrow compact path for no-arg status and branch/short-only flags.
860958
// More complex explicit args still use the existing minimal-filter path.
861959
if !uses_compact_status_path(args) {
@@ -2176,6 +2274,44 @@ mod tests {
21762274
assert!(envs.contains(&("LC_ALL".to_string(), "C".to_string())));
21772275
}
21782276

2277+
#[test]
2278+
fn test_git_status_machine_output_args_passthrough() {
2279+
assert!(status_args_request_machine_output(&["--porcelain".to_string()]));
2280+
assert!(status_args_request_machine_output(&[
2281+
"--porcelain=v2".to_string()
2282+
]));
2283+
assert!(status_args_request_machine_output(&["-z".to_string()]));
2284+
assert!(!status_args_request_machine_output(&["--short".to_string()]));
2285+
}
2286+
2287+
#[test]
2288+
fn test_git_log_machine_output_args_passthrough() {
2289+
assert!(log_args_request_machine_output(&["--format=%H".to_string()]));
2290+
assert!(log_args_request_machine_output(&[
2291+
"--pretty=format:%H".to_string()
2292+
]));
2293+
assert!(log_args_request_machine_output(&[
2294+
"--format".to_string(),
2295+
"%H".to_string()
2296+
]));
2297+
assert!(!log_args_request_machine_output(&["--oneline".to_string()]));
2298+
}
2299+
2300+
#[test]
2301+
fn test_git_diff_machine_output_args_passthrough() {
2302+
for args in [
2303+
vec!["--name-only".to_string()],
2304+
vec!["--name-status".to_string()],
2305+
vec!["--numstat".to_string()],
2306+
vec!["--raw".to_string()],
2307+
vec!["--word-porcelain".to_string()],
2308+
vec!["-z".to_string(), "--name-only".to_string()],
2309+
] {
2310+
assert!(diff_args_request_machine_output(&args), "{args:?}");
2311+
}
2312+
assert!(!diff_args_request_machine_output(&[]));
2313+
}
2314+
21792315
#[test]
21802316
fn test_build_status_command_default_compact() {
21812317
let cmd = build_status_command(&[], &[]);

0 commit comments

Comments
 (0)