@@ -24,11 +24,12 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
2424static GIT_PATH_FUNC (git_path_bisect_log , "BISECT_LOG ")
2525static GIT_PATH_FUNC (git_path_bisect_names , "BISECT_NAMES ")
2626static GIT_PATH_FUNC (git_path_bisect_first_parent , "BISECT_FIRST_PARENT ")
27+ static GIT_PATH_FUNC (git_path_bisect_auto_reset , "BISECT_AUTO_RESET ")
2728static GIT_PATH_FUNC (git_path_bisect_run , "BISECT_RUN ")
2829
2930#define BUILTIN_GIT_BISECT_START_USAGE \
3031 N_ ("git bisect start [--term-(bad|new)=<term-new> --term-(good|old)=<term-old>]\n" \
31- " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]" )
32+ " [--no-checkout] [--first-parent] [--auto-reset[=<where>]] [ <bad> [<good>...]] [--] [<pathspec>...]" )
3233#define BUILTIN_GIT_BISECT_BAD_USAGE \
3334 N_("git bisect (bad|new|<term-new>) [<rev>]")
3435#define BUILTIN_GIT_BISECT_GOOD_USAGE \
@@ -48,7 +49,7 @@ static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
4849#define BUILTIN_GIT_BISECT_LOG_USAGE \
4950 "git bisect log"
5051#define BUILTIN_GIT_BISECT_RUN_USAGE \
51- N_("git bisect run <cmd> [<arg>...]")
52+ N_("git bisect run [--auto-reset[=<where>]] <cmd> [<arg>...]")
5253#define BUILTIN_GIT_BISECT_HELP_USAGE \
5354 "git bisect help"
5455
@@ -68,6 +69,12 @@ static const char * const git_bisect_usage[] = {
6869 NULL
6970};
7071
72+ enum auto_reset_mode {
73+ AUTO_RESET_NONE ,
74+ AUTO_RESET_ORIGINAL ,
75+ AUTO_RESET_FOUND ,
76+ };
77+
7178struct add_bisect_ref_data {
7279 struct rev_info * revs ;
7380 unsigned int object_flags ;
@@ -178,17 +185,13 @@ static int append_to_file(const char *path, const char *format, ...)
178185 return res ;
179186}
180187
181- static int print_file_to_stdout ( const char * path )
188+ static int print_fd_to_stdout ( int fd )
182189{
183- int fd = open (path , O_RDONLY );
184- int ret = 0 ;
185-
186- if (fd < 0 )
187- return error_errno (_ ("cannot open file '%s' for reading" ), path );
190+ if (lseek (fd , 0 , SEEK_SET ) < 0 )
191+ return error_errno (_ ("failed to rewind BISECT_RUN output" ));
188192 if (copy_fd (fd , 1 ) < 0 )
189- ret = error_errno (_ ("failed to read '%s'" ), path );
190- close (fd );
191- return ret ;
193+ return error_errno (_ ("failed to read BISECT_RUN output" ));
194+ return 0 ;
192195}
193196
194197static int check_term_format (const char * term , const char * orig_term )
@@ -234,7 +237,7 @@ static int write_terms(const char *bad, const char *good)
234237 return res ;
235238}
236239
237- static int bisect_reset (const char * commit )
240+ static int bisect_reset (const char * commit , int quiet )
238241{
239242 struct strbuf branch = STRBUF_INIT ;
240243
@@ -255,8 +258,10 @@ static int bisect_reset(const char *commit)
255258 struct child_process cmd = CHILD_PROCESS_INIT ;
256259
257260 cmd .git_cmd = 1 ;
258- strvec_pushl (& cmd .args , "checkout" , "--ignore-other-worktrees" ,
259- branch .buf , "--" , NULL );
261+ strvec_pushl (& cmd .args , "checkout" , "--ignore-other-worktrees" , NULL );
262+ if (quiet )
263+ strvec_push (& cmd .args , "--quiet" );
264+ strvec_pushl (& cmd .args , branch .buf , "--" , NULL );
260265 if (run_command (& cmd )) {
261266 error (_ ("could not check out original"
262267 " HEAD '%s'. Try 'git bisect"
@@ -270,6 +275,59 @@ static int bisect_reset(const char *commit)
270275 return bisect_clean_state ();
271276}
272277
278+ static int parse_auto_reset (const char * value , enum auto_reset_mode * mode )
279+ {
280+ if (!strcmp (value , "original" ))
281+ * mode = AUTO_RESET_ORIGINAL ;
282+ else if (!strcmp (value , "found" ))
283+ * mode = AUTO_RESET_FOUND ;
284+ else
285+ return error (_ ("invalid value for '--auto-reset': '%s'" ), value );
286+
287+ return 0 ;
288+ }
289+
290+ static const char * auto_reset_mode_name (enum auto_reset_mode mode )
291+ {
292+ switch (mode ) {
293+ case AUTO_RESET_ORIGINAL :
294+ return "original" ;
295+ case AUTO_RESET_FOUND :
296+ return "found" ;
297+ case AUTO_RESET_NONE :
298+ BUG ("no name for unset auto-reset mode" );
299+ }
300+ BUG ("unknown auto-reset mode %d" , mode );
301+ }
302+
303+ static int bisect_auto_reset (struct bisect_terms * terms )
304+ {
305+ struct strbuf value = STRBUF_INIT ;
306+ enum auto_reset_mode mode ;
307+ char * commit = NULL ;
308+ int res ;
309+
310+ if (strbuf_read_file (& value , git_path_bisect_auto_reset (), 0 ) < 0 ) {
311+ res = error_errno (_ ("could not read '%s'" ),
312+ git_path_bisect_auto_reset ());
313+ goto cleanup ;
314+ }
315+ strbuf_trim (& value );
316+ if (parse_auto_reset (value .buf , & mode )) {
317+ res = -1 ;
318+ goto cleanup ;
319+ }
320+
321+ if (mode == AUTO_RESET_FOUND )
322+ commit = xstrfmt ("refs/bisect/%s" , terms -> term_bad );
323+ res = bisect_reset (commit , 1 );
324+
325+ cleanup :
326+ free (commit );
327+ strbuf_release (& value );
328+ return res ;
329+ }
330+
273331static void log_commit (FILE * fp ,
274332 const char * fmt , const char * state ,
275333 struct commit * commit )
@@ -701,6 +759,8 @@ static enum bisect_error bisect_next(struct bisect_terms *terms, const char *pre
701759
702760 if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ) {
703761 res = bisect_successful (terms );
762+ if (!res && !is_empty_or_missing_file (git_path_bisect_auto_reset ()))
763+ res = bisect_auto_reset (terms );
704764 return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ;
705765 } else if (res == BISECT_ONLY_SKIPPED_LEFT ) {
706766 res = bisect_skipped_commits (terms );
@@ -724,6 +784,7 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
724784{
725785 int no_checkout = 0 ;
726786 int first_parent_only = 0 ;
787+ enum auto_reset_mode auto_reset = AUTO_RESET_NONE ;
727788 int i , has_double_dash = 0 , must_write_terms = 0 , bad_seen = 0 ;
728789 int flags , pathspec_pos ;
729790 enum bisect_error res = BISECT_OK ;
@@ -756,6 +817,13 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
756817 no_checkout = 1 ;
757818 } else if (!strcmp (arg , "--first-parent" )) {
758819 first_parent_only = 1 ;
820+ } else if (!strcmp (arg , "--auto-reset" )) {
821+ auto_reset = AUTO_RESET_ORIGINAL ;
822+ } else if (skip_prefix (arg , "--auto-reset=" , & arg )) {
823+ if (parse_auto_reset (arg , & auto_reset )) {
824+ res = BISECT_FAILED ;
825+ goto finish ;
826+ }
759827 } else if (!strcmp (arg , "--term-good" ) ||
760828 !strcmp (arg , "--term-old" )) {
761829 i ++ ;
@@ -793,6 +861,10 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
793861 break ;
794862 }
795863 }
864+ if (auto_reset != AUTO_RESET_NONE && no_checkout ) {
865+ res = error (_ ("'--auto-reset' cannot be used with '--no-checkout'" ));
866+ goto finish ;
867+ }
796868 pathspec_pos = i ;
797869
798870 /*
@@ -872,6 +944,10 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
872944 if (first_parent_only )
873945 write_file (git_path_bisect_first_parent (), "\n" );
874946
947+ if (auto_reset != AUTO_RESET_NONE )
948+ write_file (git_path_bisect_auto_reset (), "%s\n" ,
949+ auto_reset_mode_name (auto_reset ));
950+
875951 if (no_checkout ) {
876952 if (repo_get_oid (the_repository , start_head .buf , & oid ) < 0 ) {
877953 res = error (_ ("invalid ref: '%s'" ), start_head .buf );
@@ -1104,7 +1180,7 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
11041180 if (is_empty_or_missing_file (filename ))
11051181 return error (_ ("cannot read file '%s' for replaying" ), filename );
11061182
1107- if (bisect_reset (NULL ))
1183+ if (bisect_reset (NULL , 0 ))
11081184 return BISECT_FAILED ;
11091185
11101186 fp = fopen (filename , "r" );
@@ -1252,13 +1328,31 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
12521328{
12531329 int res = BISECT_OK ;
12541330 struct strbuf command = STRBUF_INIT ;
1331+ enum auto_reset_mode auto_reset = AUTO_RESET_NONE ;
1332+ const char * auto_reset_arg ;
12551333 const char * new_state ;
12561334 int temporary_stdout_fd , saved_stdout ;
12571335 int is_first_run = 1 ;
12581336
12591337 if (bisect_next_check (terms , NULL ))
12601338 return BISECT_FAILED ;
12611339
1340+ if (argc && !strcmp (argv [0 ], "--auto-reset" ))
1341+ auto_reset = AUTO_RESET_ORIGINAL ;
1342+ else if (argc && skip_prefix (argv [0 ], "--auto-reset=" , & auto_reset_arg )) {
1343+ if (parse_auto_reset (auto_reset_arg , & auto_reset ))
1344+ return BISECT_FAILED ;
1345+ }
1346+
1347+ if (auto_reset != AUTO_RESET_NONE ) {
1348+ if (refs_ref_exists (get_main_ref_store (the_repository ), "BISECT_HEAD" ))
1349+ return error (_ ("'--auto-reset' cannot be used with '--no-checkout'" ));
1350+ write_file (git_path_bisect_auto_reset (), "%s\n" ,
1351+ auto_reset_mode_name (auto_reset ));
1352+ argc -- ;
1353+ argv ++ ;
1354+ }
1355+
12621356 if (!argc ) {
12631357 error (_ ("bisect run failed: no command provided." ));
12641358 return BISECT_FAILED ;
@@ -1306,7 +1400,7 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
13061400 else
13071401 new_state = terms -> term_bad ;
13081402
1309- temporary_stdout_fd = open (git_path_bisect_run (), O_CREAT | O_WRONLY | O_TRUNC , 0666 );
1403+ temporary_stdout_fd = open (git_path_bisect_run (), O_CREAT | O_RDWR | O_TRUNC , 0666 );
13101404
13111405 if (temporary_stdout_fd < 0 ) {
13121406 res = error_errno (_ ("cannot open file '%s' for writing" ), git_path_bisect_run ());
@@ -1327,9 +1421,9 @@ static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
13271421 fflush (stdout );
13281422 dup2 (saved_stdout , 1 );
13291423 close (saved_stdout );
1330- close (temporary_stdout_fd );
13311424
1332- print_file_to_stdout (git_path_bisect_run ());
1425+ print_fd_to_stdout (temporary_stdout_fd );
1426+ close (temporary_stdout_fd );
13331427
13341428 if (res == BISECT_ONLY_SKIPPED_LEFT )
13351429 error (_ ("bisect run cannot continue any more" ));
@@ -1358,7 +1452,7 @@ static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNU
13581452 if (argc > 1 )
13591453 return error (_ ("'%s' requires either no argument or a commit" ),
13601454 "git bisect reset" );
1361- return bisect_reset (argc ? argv [0 ] : NULL );
1455+ return bisect_reset (argc ? argv [0 ] : NULL , 0 );
13621456}
13631457
13641458static int cmd_bisect__terms (int argc , const char * * argv , const char * prefix UNUSED ,
0 commit comments