@@ -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+
79112fn 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 {
856920fn 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