Hey Junio,
A small mistake got unnoticed by me which Lars recently pointed out.
The naming convention is "git_path_<name_of_file>" and underscore
instead of spaces.
Thanks!
The interdiff is:
@@ -100,7 +100,7 @@ static int write_terms(const char *bad, const char *good)if(check_term_format(bad,"bad")||check_term_format(good,"good"))return-1;-fp=fopen(git_path_bisect_write_terms(),"w");+fp=fopen(git_path_bisect_terms(),"w");if(!fp)returnerror_errno(_("could not open the file BISECT_TERMS"));
@@ -134,7 +134,7 @@ static int bisect_clean_state(void)remove_path(git_path_bisect_log());remove_path(git_path_bisect_names());remove_path(git_path_bisect_run());-remove_path(git_path_bisect_write_terms());+remove_path(git_path_bisect_terms());/* Cleanup head-name if it got left by an old version of git-bisect */remove_path(git_path_head_name());/*
Pranit Bauva (9):
bisect--helper: use OPT_CMDMODE instead of OPT_BOOL
bisect: rewrite `check_term_format` shell function in C
bisect--helper: `write_terms` shell function in C
bisect--helper: `bisect_clean_state` shell function in C
t6030: explicitly test for bisection cleanup
wrapper: move is_empty_file() and rename it as
is_empty_or_missing_file()
bisect--helper: `bisect_reset` shell function in C
bisect--helper: `is_expected_rev` & `check_expected_revs` shell
function in C
bisect--helper: `bisect_write` shell function in C
builtin/am.c | 20 +--
builtin/bisect--helper.c | 310 +++++++++++++++++++++++++++++++++++++++++++-
cache.h | 3 +
git-bisect.sh | 146 +++------------------
t/t6030-bisect-porcelain.sh | 17 +++
wrapper.c | 13 ++
6 files changed, 355 insertions(+), 154 deletions(-)
--
2.9.0
Reimplement the `check_term_format` shell function in C and add
a `--check-term-format` subcommand to `git bisect--helper` to call it
from git-bisect.sh
Using `--check-term-format` subcommand is a temporary measure to port
shell function to C so as to use the existing test suite. As more
functions are ported, this subcommand will be retired and will
be called by some other method/subcommand. For eg. In conversion of
write_terms() of git-bisect.sh, the subcommand will be removed and
instead check_term_format() will be called in its C implementation while
a new subcommand will be introduced for write_terms().
Helped-by: Johannes Schindelein [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 31 ++-----------------------
2 files changed, 60 insertions(+), 30 deletions(-)
@@ -2,19 +2,72 @@#include"cache.h"#include"parse-options.h"#include"bisect.h"+#include"refs.h"staticconstchar*constgit_bisect_helper_usage[]={N_("git bisect--helper --next-all [--no-checkout]"),+N_("git bisect--helper --check-term-format <term> <orig_term>"),NULL};+/*+*Checkwhetherthestring`term`belongstothesetofstrings+*includedinthevariablearguments.+*/+staticintone_of(constchar*term,...)+{+intres=0;+va_listmatches;+constchar*match;++va_start(matches,term);+while(!res&&(match=va_arg(matches,constchar*)))+res=!strcmp(term,match);+va_end(matches);++returnres;+}++staticintcheck_term_format(constchar*term,constchar*orig_term)+{+structstrbufnew_term=STRBUF_INIT;+strbuf_addf(&new_term,"refs/bisect/%s",term);++if(check_refname_format(new_term.buf,0)){+strbuf_release(&new_term);+returnerror(_("'%s' is not a valid term"),term);+}+strbuf_release(&new_term);++if(one_of(term,"help","start","skip","next","reset",+"visualize","replay","log","run",NULL))+returnerror(_("can't use the builtin command '%s' as a term"),term);++/*+*Intheory,nothingpreventsswappingcompletelygoodandbad,+*butthissituationcouldbeconfusingandhasn'tbeentested+*enough.Forbiditfornow.+*/++if((strcmp(orig_term,"bad")&&one_of(term,"bad","new",NULL))||+(strcmp(orig_term,"good")&&one_of(term,"good","old",NULL)))+returnerror(_("can't change the meaning of the term '%s'"),term);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){-enum{NEXT_ALL=1}cmdmode=0;+enum{+NEXT_ALL=1,+CHECK_TERM_FMT+}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),+OPT_CMDMODE(0,"check-term-format",&cmdmode,+N_("check format of the term"),CHECK_TERM_FMT),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -29,6 +82,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);+caseCHECK_TERM_FMT:+if(argc!=2)+die(_("--check-term-format requires two arguments"));+returncheck_term_format(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -564,38 +564,11 @@ write_terms () {thendie"$(gettext"please use two different terms")"fi-check_term_format"$TERM_BAD"bad-check_term_format"$TERM_GOOD"good+gitbisect--helper--check-term-format"$TERM_BAD"bad||exit+gitbisect--helper--check-term-format"$TERM_GOOD"good||exitprintf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"}-check_term_format(){-term=$1-gitcheck-ref-formatrefs/bisect/"$term"||-die"$(eval_gettext"'\$term' is not a valid term")"-case"$term"in-help|start|terms|skip|next|reset|visualize|replay|log|run)-die"$(eval_gettext"can't use the builtin command '\$term' as a term")"-;;-bad|new)-iftest"$2"!=bad-then-# In theory, nothing prevents swapping-# completely good and bad, but this situation-# could be confusing and hasn't been tested-# enough. Forbid it for now.-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-good|old)-iftest"$2"!=good-then-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-esac-}- check_and_set_terms(){cmd="$1"case"$cmd"in
Reimplement the `write_terms` shell function in C and add a `write-terms`
subcommand to `git bisect--helper` to call it from git-bisect.sh . Also
remove the subcommand `--check-term-format` as it can now be called from
inside the function write_terms() C implementation.
Also `|| exit` is added when calling write-terms subcommand from
git-bisect.sh so as to exit whenever there is an error.
Using `--write-terms` subcommand is a temporary measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other method.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 36 +++++++++++++++++++++++++++++-------
git-bisect.sh | 22 +++++++---------------
2 files changed, 36 insertions(+), 22 deletions(-)
@@ -56,18 +58,38 @@ static int check_term_format(const char *term, const char *orig_term)return0;}+staticintwrite_terms(constchar*bad,constchar*good)+{+FILE*fp;+intres;++if(!strcmp(bad,good))+returnerror(_("please use two different terms"));++if(check_term_format(bad,"bad")||check_term_format(good,"good"))+return-1;++fp=fopen(git_path_bisect_terms(),"w");+if(!fp)+returnerror_errno(_("could not open the file BISECT_TERMS"));++res=fprintf(fp,"%s\n%s\n",bad,good);+fclose(fp);+return(res<0)?-1:0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-CHECK_TERM_FMT+WRITE_TERMS}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),-OPT_CMDMODE(0,"check-term-format",&cmdmode,-N_("check format of the term"),CHECK_TERM_FMT),+OPT_CMDMODE(0,"write-terms",&cmdmode,+N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -82,10 +104,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);-caseCHECK_TERM_FMT:+caseWRITE_TERMS:if(argc!=2)-die(_("--check-term-format requires two arguments"));-returncheck_term_format(argv[0],argv[1]);+die(_("--write-terms requires two arguments"));+returnwrite_terms(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -557,18 +557,6 @@ get_terms () {fi}-write_terms(){-TERM_BAD=$1-TERM_GOOD=$2-iftest"$TERM_BAD"="$TERM_GOOD"-then-die"$(gettext"please use two different terms")"-fi-gitbisect--helper--check-term-format"$TERM_BAD"bad||exit-gitbisect--helper--check-term-format"$TERM_GOOD"good||exit-printf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"-}- check_and_set_terms(){cmd="$1"case"$cmd"in
`--next-all` is meant to be used as a subcommand to support multiple
"operation mode" though the current implementation does not contain any
other subcommand along side with `--next-all` but further commits will
include some more subcommands.
Helped-by: Johannes Schindelin [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
is_empty_file() can help to refactor a lot of code. This will be very
helpful in porting "git bisect" to C.
Suggested-by: Torsten Bögershausen <redacted>
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/am.c | 20 ++------------------
cache.h | 3 +++
wrapper.c | 13 +++++++++++++
3 files changed, 18 insertions(+), 18 deletions(-)
@@ -30,22 +30,6 @@#include"mailinfo.h"/**-*Returns1ifthefileisemptyordoesnotexist,0otherwise.-*/-staticintis_empty_file(constchar*filename)-{-structstatst;--if(stat(filename,&st)<0){-if(errno==ENOENT)-return1;-die_errno(_("could not stat %s"),filename);-}--return!st.st_size;-}--/***Returnsthelengthofthefirstlineofmsg.*/staticintlinelen(constchar*msg)
@@ -1323,7 +1307,7 @@ static int parse_mail(struct am_state *state, const char *mail)gotofinish;}-if(is_empty_file(am_path(state,"patch"))){+if(is_empty_or_missing_file(am_path(state,"patch"))){printf_ln(_("Patch is empty. Was it split wrong?"));die_user_resolve(state);}
@@ -1870,4 +1870,7 @@ void sleep_millisec(int millisec);*/voidsafe_create_dir(constchar*dir,intshare);+/* Return 1 if the file is empty or does not exists, 0 otherwise. */+externintis_empty_or_missing_file(constchar*filename);+#endif /* CACHE_H */
@@ -696,3 +696,16 @@ void sleep_millisec(int millisec){poll(NULL,0,millisec);}++intis_empty_or_missing_file(constchar*filename)+{+structstatst;++if(stat(filename,&st)<0){+if(errno==ENOENT)+return1;+die_errno(_("could not stat %s"),filename);+}++return!st.st_size;+}
Reimplement `bisect_clean_state` shell function in C and add a
`bisect-clean-state` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
Using `--bisect-clean-state` subcommand is a measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by
bisect_reset() and bisect_start().
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 26 +++--------------------
2 files changed, 57 insertions(+), 24 deletions(-)
@@ -78,11 +87,49 @@ static int write_terms(const char *bad, const char *good)return(res<0)?-1:0;}+staticintmark_for_removal(constchar*refname,conststructobject_id*oid,+intflag,void*cb_data)+{+structstring_list*refs=cb_data;+char*ref=xstrfmt("refs/bisect/%s",refname);+string_list_append(refs,ref);+return0;+}++staticintbisect_clean_state(void)+{+intresult=0;++/* There may be some refs packed during bisection */+structstring_listrefs_for_removal=STRING_LIST_INIT_NODUP;+for_each_ref_in("refs/bisect/",mark_for_removal,(void*)&refs_for_removal);+string_list_append(&refs_for_removal,xstrdup("BISECT_HEAD"));+result=delete_refs(&refs_for_removal);+refs_for_removal.strdup_strings=1;+string_list_clear(&refs_for_removal,0);+remove_path(git_path_bisect_expected_rev());+remove_path(git_path_bisect_ancestors_ok());+remove_path(git_path_bisect_log());+remove_path(git_path_bisect_names());+remove_path(git_path_bisect_run());+remove_path(git_path_bisect_terms());+/* Cleanup head-name if it got left by an old version of git-bisect */+remove_path(git_path_head_name());+/*+*CleanupBISECT_STARTlasttosupportthe--no-checkoutoption+*introducedinthecommit4796e823a.+*/+remove_path(git_path_bisect_start());++returnresult;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-WRITE_TERMS+WRITE_TERMS,+BISECT_CLEAN_STATE}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -90,6 +137,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("perform 'git bisect next'"),NEXT_ALL),OPT_CMDMODE(0,"write-terms",&cmdmode,N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),+OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,+N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -108,6 +157,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=2)die(_("--write-terms requires two arguments"));returnwrite_terms(argv[0],argv[1]);+caseBISECT_CLEAN_STATE:+if(argc!=0)+die(_("--bisect-clean-state requires no arguments"));+returnbisect_clean_state();default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -187,7 +187,7 @@ bisect_start() {## Get rid of any old bisect state.#-bisect_clean_state||exit+gitbisect--helper--bisect-clean-state||exit## Change state.
@@ -196,7 +196,7 @@ bisect_start() {# We have to trap this to be able to clean up using# "bisect_clean_state".#-trap'bisect_clean_state'0+trap'git bisect--helper --bisect-clean-state'0trap'exit 255'12315#
@@ -430,27 +430,7 @@ bisect_reset() {die"$(eval_gettext"Could not check out original HEAD '\$branch'. Try'git bisect reset <commit>'.")"fi-bisect_clean_state-}--bisect_clean_state(){-# There may be some refs packed during bisection.-gitfor-each-ref--format='%(refname) %(objectname)'refs/bisect/\*|-whilereadrefhash-do-gitupdate-ref-d$ref$hash||exit-done-rm-f"$GIT_DIR/BISECT_EXPECTED_REV"&&-rm-f"$GIT_DIR/BISECT_ANCESTORS_OK"&&-rm-f"$GIT_DIR/BISECT_LOG"&&-rm-f"$GIT_DIR/BISECT_NAMES"&&-rm-f"$GIT_DIR/BISECT_RUN"&&-rm-f"$GIT_DIR/BISECT_TERMS"&&-# Cleanup head-name if it got left by an old version of git-bisect-rm-f"$GIT_DIR/head-name"&&-gitupdate-ref-d--no-derefBISECT_HEAD&&-# clean up BISECT_START last-rm-f"$GIT_DIR/BISECT_START"+gitbisect--helper--bisect-clean-state||exit} bisect_replay(){
Add test to explicitly check that 'git bisect reset' is working as
expected. This is already covered implicitly by the test suite.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
I faced this problem while converting `bisect_clean_state` and the tests
where showing breakages but it wasn't clear as to where exactly are they
breaking. This will patch will help in that. Also I tested the test
coverage of the test suite before this patch and it covers this (I did
this by purposely changing names of files in git-bisect.sh and running
the test suite).
Signed-off-by: Pranit Bauva <redacted>
---
t/t6030-bisect-porcelain.sh | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
Reimplement the `bisect_write` shell function in C and add a
`bisect-write` subcommand to `git bisect--helper` to call it from
git-bisect.sh
Using `--bisect-write` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Note: bisect_write() uses two variables namely TERM_GOOD and TERM_BAD
from the global shell script thus we need to pass it to the subcommand
using the arguments. We then store them in a struct bisect_terms and
pass the memory address around functions.
This patch also introduces new methods namely bisect_state_init() and
bisect_terms_release() for easy memory management for the struct
bisect_terms.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 97 ++++++++++++++++++++++++++++++++++++++++++++----
git-bisect.sh | 25 ++-----------
2 files changed, 94 insertions(+), 28 deletions(-)
@@ -188,6 +206,52 @@ static int check_expected_revs(const char **revs, int rev_nr)return0;}+staticintbisect_write(constchar*state,constchar*rev,+conststructbisect_terms*terms,intnolog)+{+structstrbuftag=STRBUF_INIT;+structstrbufcommit_name=STRBUF_INIT;+structobject_idoid;+structcommit*commit;+structpretty_print_contextpp={0};+FILE*fp;++if(!strcmp(state,terms->term_bad.buf))+strbuf_addf(&tag,"refs/bisect/%s",state);+elseif(one_of(state,terms->term_good.buf,"skip",NULL))+strbuf_addf(&tag,"refs/bisect/%s-%s",state,rev);+else+returnerror(_("Bad bisect_write argument: %s"),state);++if(get_oid(rev,&oid)){+strbuf_release(&tag);+returnerror(_("couldn't get the oid of the rev '%s'"),rev);+}++if(update_ref(NULL,tag.buf,oid.hash,NULL,0,+UPDATE_REFS_MSG_ON_ERR)){+strbuf_release(&tag);+return-1;+}+strbuf_release(&tag);++fp=fopen(git_path_bisect_log(),"a");+if(!fp)+returnerror_errno(_("couldn't open the file '%s'"),git_path_bisect_log());++commit=lookup_commit_reference(oid.hash);+format_commit_message(commit,"%s",&commit_name,&pp);+fprintf(fp,"# %s: [%s] %s\n",state,sha1_to_hex(oid.hash),+commit_name.buf);+strbuf_release(&commit_name);++if(!nolog)+fprintf(fp,"git bisect %s %s\n",state,rev);++fclose(fp);+return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -209,10 +274,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("reset the bisection state"),BISECT_RESET),OPT_CMDMODE(0,"check-expected-revs",&cmdmode,N_("check for expected revs"),CHECK_EXPECTED_REVS),+OPT_CMDMODE(0,"bisect-write",&cmdmode,+N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()};+structbisect_termsterms;+bisect_terms_init(&terms);argc=parse_options(argc,argv,prefix,options,git_bisect_helper_usage,0);
@@ -221,24 +290,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)usage_with_options(git_bisect_helper_usage,options);switch(cmdmode){+intnolog;caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);caseWRITE_TERMS:if(argc!=2)die(_("--write-terms requires two arguments"));-returnwrite_terms(argv[0],argv[1]);+res=write_terms(argv[0],argv[1]);+break;caseBISECT_CLEAN_STATE:if(argc!=0)die(_("--bisect-clean-state requires no arguments"));-returnbisect_clean_state();+res=bisect_clean_state();+break;caseBISECT_RESET:if(argc>1)die(_("--bisect-reset requires either zero or one arguments"));-returnbisect_reset(argc?argv[0]:NULL);+res=bisect_reset(argc?argv[0]:NULL);+break;caseCHECK_EXPECTED_REVS:-returncheck_expected_revs(argv,argc);+res=check_expected_revs(argv,argc);+break;+caseBISECT_WRITE:+if(argc!=4&&argc!=5)+die(_("--bisect-write requires either 4 or 5 arguments"));+nolog=(argc==5)&&!strcmp(argv[4],"nolog");+strbuf_addstr(&terms.term_good,argv[2]);+strbuf_addstr(&terms.term_bad,argv[3]);+res=bisect_write(argv[0],argv[1],&terms,nolog);+break;default:die("BUG: unknown subcommand '%d'",cmdmode);}-return0;+bisect_terms_release(&terms);+returnres;}
Reimplement `bisect_reset` shell function in C and add a `--bisect-reset`
subcommand to `git bisect--helper` to call it from git-bisect.sh .
Using `bisect_reset` subcommand is a temporary measure to port shell
functions to C so as to use the existing test suite. As more functions
are ported, this subcommand would be retired and will be called by some
other method.
Note: --bisect-clean-state subcommand has not been retired as there are
still a function namely `bisect_start()` which still uses this
subcommand.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 28 ++--------------------------
2 files changed, 48 insertions(+), 27 deletions(-)
@@ -124,12 +128,47 @@ static int bisect_clean_state(void)returnresult;}+staticintbisect_reset(constchar*commit)+{+structstrbufbranch=STRBUF_INIT;++if(!commit){+if(strbuf_read_file(&branch,git_path_bisect_start(),0)<1){+printf("We are not bisecting.\n");+return0;+}+strbuf_rtrim(&branch);+}else{+structobject_idoid;+if(get_oid(commit,&oid))+returnerror(_("'%s' is not a valid commit"),commit);+strbuf_addstr(&branch,commit);+}++if(!file_exists(git_path_bisect_head())){+structargv_arrayargv=ARGV_ARRAY_INIT;+argv_array_pushl(&argv,"checkout",branch.buf,"--",NULL);+if(run_command_v_opt(argv.argv,RUN_GIT_CMD)){+error(_("Could not check out original HEAD '%s'. Try"+"'git bisect reset <commit>'."),branch.buf);+strbuf_release(&branch);+argv_array_clear(&argv);+return-1;+}+argv_array_clear(&argv);+}++strbuf_release(&branch);+returnbisect_clean_state();+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,-BISECT_CLEAN_STATE+BISECT_CLEAN_STATE,+BISECT_RESET}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -139,6 +178,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,N_("cleanup the bisection state"),BISECT_CLEAN_STATE),+OPT_CMDMODE(0,"bisect-reset",&cmdmode,+N_("reset the bisection state"),BISECT_RESET),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -161,6 +202,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=0)die(_("--bisect-clean-state requires no arguments"));returnbisect_clean_state();+caseBISECT_RESET:+if(argc>1)+die(_("--bisect-reset requires either zero or one arguments"));+returnbisect_reset(argc?argv[0]:NULL);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -409,35 +409,11 @@ bisect_visualize() {eval'"$@"'--bisect--$(cat"$GIT_DIR/BISECT_NAMES")}-bisect_reset(){-test-s"$GIT_DIR/BISECT_START"||{-gettextln"We are not bisecting."-return-}-case"$#"in-0)branch=$(cat"$GIT_DIR/BISECT_START");;-1)gitrev-parse--quiet--verify"$1^{commit}">/dev/null||{-invalid="$1"-die"$(eval_gettext"'\$invalid' is not a valid commit")"-}-branch="$1";;-*)-usage;;-esac--if!test-f"$GIT_DIR/BISECT_HEAD"&&!gitcheckout"$branch"---then-die"$(eval_gettext"Could not check out original HEAD '\$branch'.-Try'git bisect reset <commit>'.")"-fi-gitbisect--helper--bisect-clean-state||exit-}- bisect_replay(){file="$1"test"$#"-eq1||die"$(gettext"No logfile given")"test-r"$file"||die"$(eval_gettext"cannot read \$file for replaying")"-bisect_reset+gitbisect--helper--bisect-reset||exitwhilereadgitbisectcommandrevdotest"$git$bisect"="git bisect"||test"$git"="git-bisect"||continue
@@ -627,7 +603,7 @@ case "$#" invisualize|view)bisect_visualize"$@";;reset)-bisect_reset"$@";;+gitbisect--helper--bisect-reset"$@";;replay)bisect_replay"$@";;log)
Reimplement `is_expected_rev` & `check_expected_revs` shell function in
C and add a `--check-expected-revs` subcommand to `git bisect--helper` to
call it from git-bisect.sh .
Using `--check-expected-revs` subcommand is a temporary measure to port
shell functions to C so as to use the existing test suite. As more
functions are ported, this subcommand would be retired and will be
called by some other method.
Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 33 ++++++++++++++++++++++++++++++++-
git-bisect.sh | 20 ++------------------
2 files changed, 34 insertions(+), 19 deletions(-)
@@ -162,13 +162,40 @@ static int bisect_reset(const char *commit)returnbisect_clean_state();}+staticintis_expected_rev(constchar*expected_hex)+{+structstrbufactual_hex=STRBUF_INIT;+intres=0;+if(strbuf_read_file(&actual_hex,git_path_bisect_expected_rev(),0)>=0){+strbuf_trim(&actual_hex);+res=!strcmp(actual_hex.buf,expected_hex);+}+strbuf_release(&actual_hex);+returnres;+}++staticintcheck_expected_revs(constchar**revs,intrev_nr)+{+inti;++for(i=0;i<rev_nr;i++){+if(!is_expected_rev(revs[i])){+remove_path(git_path_bisect_ancestors_ok());+remove_path(git_path_bisect_expected_rev());+return0;+}+}+return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,BISECT_CLEAN_STATE,-BISECT_RESET+BISECT_RESET,+CHECK_EXPECTED_REVS}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -180,6 +207,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_CMDMODE(0,"bisect-reset",&cmdmode,N_("reset the bisection state"),BISECT_RESET),+OPT_CMDMODE(0,"check-expected-revs",&cmdmode,+N_("check for expected revs"),CHECK_EXPECTED_REVS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -206,6 +235,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc>1)die(_("--bisect-reset requires either zero or one arguments"));returnbisect_reset(argc?argv[0]:NULL);+caseCHECK_EXPECTED_REVS:+returncheck_expected_revs(argv,argc);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -294,7 +278,7 @@ bisect_state() {dobisect_write"$state""$rev"done-check_expected_revs$hash_list;;+gitbisect--helper--check-expected-revs$hash_list;;*,"$TERM_BAD")die"$(eval_gettext"'git bisect \$TERM_BAD' can take only one argument.")";;*)
From: Christian Couder <hidden> Date: 2016-07-13 07:48:01
Hi Pranit,
On Wed, Jul 13, 2016 at 12:35 AM, Pranit Bauva [off-list ref] wrote:
Hey Junio,
A small mistake got unnoticed by me which Lars recently pointed out.
The naming convention is "git_path_<name_of_file>" and underscore
instead of spaces.
It's a good thing to resend when you find mistakes, but please use a
version number for your patch series (like "PATCH v3" or something).
Thanks,
Christian.
On Wed, Jul 13, 2016 at 4:05 AM, Pranit Bauva [off-list ref] wrote:
quoted hunk
Hey Junio,
A small mistake got unnoticed by me which Lars recently pointed out.
The naming convention is "git_path_<name_of_file>" and underscore
instead of spaces.
Thanks!
The interdiff is:
@@ -100,7 +100,7 @@ static int write_terms(const char *bad, const char *good)if(check_term_format(bad,"bad")||check_term_format(good,"good"))return-1;-fp=fopen(git_path_bisect_write_terms(),"w");+fp=fopen(git_path_bisect_terms(),"w");if(!fp)returnerror_errno(_("could not open the file BISECT_TERMS"));
@@ -134,7 +134,7 @@ static int bisect_clean_state(void)remove_path(git_path_bisect_log());remove_path(git_path_bisect_names());remove_path(git_path_bisect_run());-remove_path(git_path_bisect_write_terms());+remove_path(git_path_bisect_terms());/* Cleanup head-name if it got left by an old version of git-bisect */remove_path(git_path_head_name());/*
Pranit Bauva (9):
bisect--helper: use OPT_CMDMODE instead of OPT_BOOL
bisect: rewrite `check_term_format` shell function in C
bisect--helper: `write_terms` shell function in C
bisect--helper: `bisect_clean_state` shell function in C
t6030: explicitly test for bisection cleanup
wrapper: move is_empty_file() and rename it as
is_empty_or_missing_file()
bisect--helper: `bisect_reset` shell function in C
bisect--helper: `is_expected_rev` & `check_expected_revs` shell
function in C
bisect--helper: `bisect_write` shell function in C
builtin/am.c | 20 +--
builtin/bisect--helper.c | 310 +++++++++++++++++++++++++++++++++++++++++++-
cache.h | 3 +
git-bisect.sh | 146 +++------------------
t/t6030-bisect-porcelain.sh | 17 +++
wrapper.c | 13 ++
6 files changed, 355 insertions(+), 154 deletions(-)
Could someone please look into this series and review so that Junio
can merge this into next which is a vital part of my GSoC project?
Regards,
Pranit Bauva
`--next-all` is meant to be used as a subcommand to support multiple
"operation mode" though the current implementation does not contain any
other subcommand along side with `--next-all` but further commits will
include some more subcommands.
Helped-by: Johannes Schindelin [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
is_empty_file() can help to refactor a lot of code. This will be very
helpful in porting "git bisect" to C.
Suggested-by: Torsten Bögershausen <redacted>
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/am.c | 20 ++------------------
cache.h | 3 +++
wrapper.c | 13 +++++++++++++
3 files changed, 18 insertions(+), 18 deletions(-)
@@ -30,22 +30,6 @@#include"mailinfo.h"/**-*Returns1ifthefileisemptyordoesnotexist,0otherwise.-*/-staticintis_empty_file(constchar*filename)-{-structstatst;--if(stat(filename,&st)<0){-if(errno==ENOENT)-return1;-die_errno(_("could not stat %s"),filename);-}--return!st.st_size;-}--/***Returnsthelengthofthefirstlineofmsg.*/staticintlinelen(constchar*msg)
@@ -1323,7 +1307,7 @@ static int parse_mail(struct am_state *state, const char *mail)gotofinish;}-if(is_empty_file(am_path(state,"patch"))){+if(is_empty_or_missing_file(am_path(state,"patch"))){printf_ln(_("Patch is empty. Was it split wrong?"));die_user_resolve(state);}
@@ -1870,4 +1870,7 @@ void sleep_millisec(int millisec);*/voidsafe_create_dir(constchar*dir,intshare);+/* Return 1 if the file is empty or does not exists, 0 otherwise. */+externintis_empty_or_missing_file(constchar*filename);+#endif /* CACHE_H */
@@ -696,3 +696,16 @@ void sleep_millisec(int millisec){poll(NULL,0,millisec);}++intis_empty_or_missing_file(constchar*filename)+{+structstatst;++if(stat(filename,&st)<0){+if(errno==ENOENT)+return1;+die_errno(_("could not stat %s"),filename);+}++return!st.st_size;+}--
Reimplement the `get_terms` and `bisect_terms` shell function in C and
add `bisect-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
In the shell version, the terms were identified by strings but in C
version its done by bit manipulation and passing the integer value to
the function.
Using `--bisect-terms` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 35 ++---------------------
2 files changed, 75 insertions(+), 34 deletions(-)
@@ -359,6 +367,43 @@ static int bisect_next_check(const struct bisect_terms *terms,return0;}+staticintget_terms(structbisect_terms*terms)+{+FILE*fp;+intres;+fp=fopen(git_path_bisect_terms(),"r");+if(!fp)+return-1;++bisect_terms_reset(terms);+res=strbuf_getline(&terms->term_bad,fp)==EOF||+strbuf_getline(&terms->term_good,fp)==EOF;++fclose(fp);+returnres?-1:0;+}++staticintbisect_terms(structbisect_terms*terms,intterm_defined)+{+if(get_terms(terms)){+fprintf(stderr,"no terms defined\n");+return-1;+}+if(!term_defined){+printf("Your current terms are %s for the old state\nand "+"%s for the new state.\n",terms->term_good.buf,+terms->term_bad.buf);+return0;+}++if(term_defined==TERM_GOOD||term_defined==TERM_OLD)+printf("%s\n",terms->term_good.buf);+if(term_defined==TERM_BAD||term_defined==TERM_NEW)+printf("%s\n",terms->term_bad.buf);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -389,6 +436,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),OPT_CMDMODE(0,"bisect-next-check",&cmdmode,N_("check whether bad or good terms exist"),BISECT_NEXT_CHECK),+OPT_CMDMODE(0,"bisect-terms",&cmdmode,+N_("print out the bisect terms"),BISECT_TERMS),+OPT_BIT(0,"term-bad",&term_defined,+N_("show the bad term"),TERM_BAD),+OPT_BIT(0,"term-good",&term_defined,+N_("show the good term"),TERM_GOOD),+OPT_BIT(0,"term-new",&term_defined,+N_("show the new term"),TERM_NEW),+OPT_BIT(0,"term-old",&term_defined,+N_("show the old term"),TERM_OLD),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -399,6 +456,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)argc=parse_options(argc,argv,prefix,options,git_bisect_helper_usage,0);+if(cmdmode!=BISECT_TERMS&&term_defined)+die(_("--term-bad, --term-good, --term-new and --term-old "+"can be used only with --bisect-terms"));++if(term_defined!=0&&term_defined!=TERM_BAD&&+term_defined!=TERM_GOOD&&term_defined!=TERM_NEW&&+term_defined!=TERM_OLD)+die(_("only one option among --term-bad, --term-good, "+"--term-new and --term-old can be used."));+if(!cmdmode)usage_with_options(git_bisect_helper_usage,options);
@@ -355,7 +355,7 @@ bisect_replay () {"$TERM_GOOD"|"$TERM_BAD"|skip)gitbisect--helper--bisect-write"$command""$rev""$TERM_GOOD""$TERM_BAD"||exit;;terms)-bisect_terms$rev;;+gitbisect--helper--bisect-terms$rev||exit;;*)die"$(gettext"?? what are you talking about?")";;esac
@@ -437,37 +437,6 @@ get_terms () {fi}-bisect_terms(){-get_terms-if!test-s"$GIT_DIR/BISECT_TERMS"-then-die"$(gettext"no terms defined")"-fi-case"$#"in-0)-gettextln"Your current terms are $TERM_GOOD for the old state-and$TERM_BADforthenewstate."-;;-1)-arg=$1-case"$arg"in---term-good|--term-old)-printf'%s\n'"$TERM_GOOD"-;;---term-bad|--term-new)-printf'%s\n'"$TERM_BAD"-;;-*)-die"$(eval_gettext"invalid argument \$arg for 'git bisect terms'.-Supportedoptionsare:--term-good|--term-oldand--term-bad|--term-new.")"-;;-esac-;;-*)-usage;;-esac-}-case"$#"in0)usage;;
@@ -498,7 +467,7 @@ case "$#" inrun)bisect_run"$@";;terms)-bisect_terms"$@";;+gitbisect--helper--bisect-terms"$@"||exit;;*)usage;;esac--
Reimplement the `get_terms` and `bisect_terms` shell function in C and
add `bisect-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
In the shell version, the terms were identified by strings but in C
version its done by bit manipulation and passing the integer value to
the function.
Using `--bisect-terms` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 35 ++---------------------
2 files changed, 75 insertions(+), 34 deletions(-)
What does TERM stand for ?
It could be TERMinal, TERMinator or just TERM.
Something like BIS_TERM_DEF_BAD .. may be more intuitive,
and may avoid name clashes in the long run.
And why are the defines 1,2,4,8 ?
It looks as if a #define bitmap may be a better choice here ?
How do we do these kind of bit-wise opions otherwise ?
@@ -389,6 +436,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS), OPT_CMDMODE(0, "bisect-next-check", &cmdmode, N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),+ OPT_CMDMODE(0, "bisect-terms", &cmdmode,+ N_("print out the bisect terms"), BISECT_TERMS),+ OPT_BIT(0, "term-bad", &term_defined,+ N_("show the bad term"), TERM_BAD),+ OPT_BIT(0, "term-good", &term_defined,+ N_("show the good term"), TERM_GOOD),+ OPT_BIT(0, "term-new", &term_defined,+ N_("show the new term"), TERM_NEW),+ OPT_BIT(0, "term-old", &term_defined,+ N_("show the old term"), TERM_OLD), OPT_BOOL(0, "no-checkout", &no_checkout, N_("update BISECT_HEAD instead of checking out the current commit")), OPT_END()
@@ -399,6 +456,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, options, git_bisect_helper_usage, 0);+ if (cmdmode != BISECT_TERMS && term_defined)+ die(_("--term-bad, --term-good, --term-new and --term-old "+ "can be used only with --bisect-terms"));++ if (term_defined != 0 && term_defined != TERM_BAD &&+ term_defined != TERM_GOOD && term_defined != TERM_NEW &&+ term_defined != TERM_OLD)+ die(_("only one option among --term-bad, --term-good, "+ "--term-new and --term-old can be used."));+
Hey Torsten,
On Fri, Jul 22, 2016 at 7:59 AM, Torsten Bögershausen [off-list ref] wrote:
On 07/20/2016 11:47 PM, Pranit Bauva wrote:
quoted
Reimplement the `get_terms` and `bisect_terms` shell function in C and
add `bisect-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
In the shell version, the terms were identified by strings but in C
version its done by bit manipulation and passing the integer value to
the function.
Using `--bisect-terms` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 74
+++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 35 ++---------------------
2 files changed, 75 insertions(+), 34 deletions(-)
What does TERM stand for ?
It could be TERMinal, TERMinator or just TERM.
Something like BIS_TERM_DEF_BAD .. may be more intuitive,
and may avoid name clashes in the long run.
And why are the defines 1,2,4,8 ?
It looks as if a #define bitmap may be a better choice here ?
How do we do these kind of bit-wise opions otherwise ?
I am not sure as why bitmaps would be a better choice except for git's
source code. I saw the source code (especially config.c) and it uses
"#defines" bitmap style. I haven't been able to find this method
before. Also it uses "(1<<2)" instead of "4".
@@ -389,6 +436,16 @@ int cmd_bisect__helper(int argc, const char **argv,
const char *prefix)
N_("check and set terms in a bisection state"),
CHECK_AND_SET_TERMS),
OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
N_("check whether bad or good terms exist"),
BISECT_NEXT_CHECK),
+ OPT_CMDMODE(0, "bisect-terms", &cmdmode,
+ N_("print out the bisect terms"), BISECT_TERMS),
+ OPT_BIT(0, "term-bad", &term_defined,
+ N_("show the bad term"), TERM_BAD),
+ OPT_BIT(0, "term-good", &term_defined,
+ N_("show the good term"), TERM_GOOD),
+ OPT_BIT(0, "term-new", &term_defined,
+ N_("show the new term"), TERM_NEW),
+ OPT_BIT(0, "term-old", &term_defined,
+ N_("show the old term"), TERM_OLD),
OPT_BOOL(0, "no-checkout", &no_checkout,
N_("update BISECT_HEAD instead of checking out
the current commit")),
OPT_END()
@@ -399,6 +456,16 @@ int cmd_bisect__helper(int argc, const char **argv,
const char *prefix)
argc = parse_options(argc, argv, prefix, options,
git_bisect_helper_usage, 0);
+ if (cmdmode != BISECT_TERMS && term_defined)
+ die(_("--term-bad, --term-good, --term-new and --term-old
"
+ "can be used only with --bisect-terms"));
+
+ if (term_defined != 0 && term_defined != TERM_BAD &&
+ term_defined != TERM_GOOD && term_defined != TERM_NEW &&
+ term_defined != TERM_OLD)
+ die(_("only one option among --term-bad, --term-good, "
+ "--term-new and --term-old can be used."));
+
[]
However I suspect handling "--term-good/--term-bad" is creating
problems in bisect_start(). I am finding a way around. If not then I
will have to get back to using "OPT_ARGUMENT" and handling it in the
individual function.
Regards,
Pranit Bauva
Reimplement the `check_and_set_terms` shell function in C and add
`check-and-set-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh
Using `--check-and-set-terms` subcommand is a temporary measure to port
shell function in C so as to use the existing test suite. As more
functions are ported, this subcommand will be retired and will be called
by some other methods.
check_and_set_terms() sets and receives two global variables namely
TERM_GOOD and TERM_BAD in the shell script. Luckily the file BISECT_TERMS
also contains the value of those variables so its appropriate to evoke the
method get_terms() after calling the subcommand so that it retrieves the
value of TERM_GOOD and TERM_BAD from the file BISECT_TERMS. The two
global variables are passed as arguments to the subcommand.
Also introduce bisect_terms_reset() to empty the contents of `term_good`
and `term_bad` of `struct bisect_terms`.
Also introduce set_terms() to copy the `term_good` and `term_bad` into
`struct bisect_terms` and write it out to the file BISECT_TERMS.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 36 ++++-----------------------------
2 files changed, 55 insertions(+), 33 deletions(-)
@@ -252,6 +259,39 @@ static int bisect_write(const char *state, const char *rev,return0;}+staticintset_terms(structbisect_terms*terms,constchar*bad,+constchar*good)+{+bisect_terms_reset(terms);+strbuf_addstr(&terms->term_good,good);+strbuf_addstr(&terms->term_bad,bad);+returnwrite_terms(terms->term_bad.buf,terms->term_good.buf);+}++staticintcheck_and_set_terms(structbisect_terms*terms,constchar*cmd)+{+intno_term_file=is_empty_or_missing_file(git_path_bisect_terms());++if(one_of(cmd,"skip","start","terms",NULL))+return0;++if(!no_term_file&&+strcmp(cmd,terms->term_bad.buf)&&+strcmp(cmd,terms->term_good.buf))+returnerror(_("Invalid command: you're currently in a "+"'%s' '%s' bisect"),terms->term_bad.buf,+terms->term_good.buf);++if(no_term_file){+if(one_of(cmd,"bad","good",NULL))+returnset_terms(terms,"bad","good");+if(one_of(cmd,"new","old",NULL))+returnset_terms(terms,"new","old");+}++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -276,6 +317,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("check for expected revs"),CHECK_EXPECTED_REVS),OPT_CMDMODE(0,"bisect-write",&cmdmode,N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),+OPT_CMDMODE(0,"check-and-set-terms",&cmdmode,+N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -239,7 +239,8 @@ bisect_skip() { bisect_state(){bisect_autostartstate=$1-check_and_set_terms$state+gitbisect--helper--check-and-set-terms$state$TERM_GOOD$TERM_BAD||exit+get_termscase"$#,$state"in0,*)die"$(gettext"Please call 'bisect_state' with at least one argument.")";;
@@ -480,36 +482,6 @@ get_terms () {fi}-check_and_set_terms(){-cmd="$1"-case"$cmd"in-skip|start|terms);;-*)-iftest-s"$GIT_DIR/BISECT_TERMS"&&test"$cmd"!="$TERM_BAD"&&test"$cmd"!="$TERM_GOOD"-then-die"$(eval_gettext"Invalid command: you're currently in a \$TERM_BAD/\$TERM_GOOD bisect.")"-fi-case"$cmd"in-bad|good)-if!test-s"$GIT_DIR/BISECT_TERMS"-then-TERM_BAD=bad-TERM_GOOD=good-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"||exit-fi-;;-new|old)-if!test-s"$GIT_DIR/BISECT_TERMS"-then-TERM_BAD=new-TERM_GOOD=old-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"||exit-fi-;;-esac;;-esac-}- bisect_voc(){case"$1"inbad)echo"bad|new";;--
Reimplement `bisect_next_check` shell function in C and add
`bisect-next-check` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
Using `--bisect-next-check` is a temporary measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
bisect_voc() is removed as it is redundant and does not serve any useful
purpose. We are better off specifying "bad|new" "good|old" as and when
we require in bisect_next_check().
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 60 +++---------------------------------
2 files changed, 82 insertions(+), 57 deletions(-)
@@ -292,6 +294,71 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)return0;}+staticintmark_good(constchar*refname,conststructobject_id*oid,+intflag,void*cb_data)+{+int*m_good=(int*)cb_data;+*m_good=0;+return0;+}++staticintbisect_next_check(conststructbisect_terms*terms,+constchar*current_term)+{+intmissing_good=1,missing_bad=1;+char*bad_ref=xstrfmt("refs/bisect/%s",terms->term_bad.buf);+char*good_glob=xstrfmt("%s*",terms->term_good.buf);++if(ref_exists(bad_ref))+missing_bad=0;+free(bad_ref);++for_each_glob_ref_in(mark_good,good_glob,"refs/bisect/",+(void*)&missing_good);+free(good_glob);++if(!missing_good&&!missing_bad)+return0;++if(!current_term)+return-1;++if(missing_good&&!missing_bad&¤t_term&&+!strcmp(current_term,terms->term_good.buf)){+char*yesno;+/*+*havebad(ornew)butnotgood(orold).Wecouldbisect+*althoughthisislessoptimum.+*/+fprintf(stderr,"Warning: bisecting only with a %s commit\n",+terms->term_bad.buf);+if(!isatty(0))+return0;+/*+*TRANSLATORS:Makesuretoinclude[Y]and[n]inyour+*translation.TheprogramwillonlyacceptEnglishinput+*atthispoint.+*/+yesno=git_prompt(_("Are you sure [Y/n]? "),PROMPT_ECHO);+if(starts_with(yesno,"N")||starts_with(yesno,"n"))+return-1;+return0;+}+if(!is_empty_or_missing_file(git_path_bisect_start()))+returnerror(_("You need to give me at least one good|old and "+"bad|new revision. You can use \"git bisect "+"bad|new\" and \"git bisect good|old\" for "+"that. \n"));+else+returnerror(_("You need to start by \"git bisect start\". "+"You then need to give me at least one good|"+"old and bad|new revision. You can use \"git "+"bisect bad|new\" and \"git bisect good|old\" "+" for that.\n"));++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -319,6 +387,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),OPT_CMDMODE(0,"check-and-set-terms",&cmdmode,N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),+OPT_CMDMODE(0,"bisect-next-check",&cmdmode,+N_("check whether bad or good terms exist"),BISECT_NEXT_CHECK),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -271,59 +271,14 @@ bisect_state() {bisect_auto_next}-bisect_next_check(){-missing_good=missing_bad=-gitshow-ref-q--verifyrefs/bisect/$TERM_BAD||missing_bad=t-test-n"$(gitfor-each-ref"refs/bisect/$TERM_GOOD-*")"||missing_good=t--case"$missing_good,$missing_bad,$1"in-,,*)-:haveboth$TERM_GOODand$TERM_BAD-ok-;;-*,)-# do not have both but not asked to fail - just report.-false-;;-t,,"$TERM_GOOD")-# have bad (or new) but not good (or old). we could bisect although-# this is less optimum.-eval_gettextln"Warning: bisecting only with a \$TERM_BAD commit.">&2-iftest-t0-then-# TRANSLATORS: Make sure to include [Y] and [n] in your-# translation. The program will only accept English input-# at this point.-gettext"Are you sure [Y/n]? ">&2-readyesno-case"$yesno"in[Nn]*)exit1;;esac-fi-:bisectwithout$TERM_GOOD...-;;-*)-bad_syn=$(bisect_vocbad)-good_syn=$(bisect_vocgood)-iftest-s"$GIT_DIR/BISECT_START"-then--eval_gettextln"You need to give me at least one \$bad_syn and one \$good_syn revision.-(Youcanuse\"gitbisect\$bad_syn\"and\"gitbisect\$good_syn\"forthat.)" >&2-else-eval_gettextln"You need to start by \"git bisect start\".-Youthenneedtogivemeatleastone\$good_synandone\$bad_synrevision.-(Youcanuse\"gitbisect\$bad_syn\"and\"gitbisect\$good_syn\"forthat.)" >&2-fi-exit1;;-esac-}- bisect_auto_next(){-bisect_next_check&&bisect_next||:+gitbisect--helper--bisect-next-check$TERM_GOOD$TERM_BAD&&bisect_next||:} bisect_next(){case"$#"in0);;*)usage;;esacbisect_autostart-bisect_next_check$TERM_GOOD+gitbisect--helper--bisect-next-check$TERM_GOOD$TERM_BAD$TERM_GOOD||exit# Perform all bisection computation, display and checkoutgitbisect--helper--next-all$(test-f"$GIT_DIR/BISECT_HEAD"&&echo--no-checkout)
Reimplement `bisect_clean_state` shell function in C and add a
`bisect-clean-state` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
Using `--bisect-clean-state` subcommand is a measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by
bisect_reset() and bisect_start().
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 26 +++--------------------
2 files changed, 57 insertions(+), 24 deletions(-)
@@ -78,11 +87,49 @@ static int write_terms(const char *bad, const char *good)return(res<0)?-1:0;}+staticintmark_for_removal(constchar*refname,conststructobject_id*oid,+intflag,void*cb_data)+{+structstring_list*refs=cb_data;+char*ref=xstrfmt("refs/bisect/%s",refname);+string_list_append(refs,ref);+return0;+}++staticintbisect_clean_state(void)+{+intresult=0;++/* There may be some refs packed during bisection */+structstring_listrefs_for_removal=STRING_LIST_INIT_NODUP;+for_each_ref_in("refs/bisect/",mark_for_removal,(void*)&refs_for_removal);+string_list_append(&refs_for_removal,xstrdup("BISECT_HEAD"));+result=delete_refs(&refs_for_removal);+refs_for_removal.strdup_strings=1;+string_list_clear(&refs_for_removal,0);+remove_path(git_path_bisect_expected_rev());+remove_path(git_path_bisect_ancestors_ok());+remove_path(git_path_bisect_log());+remove_path(git_path_bisect_names());+remove_path(git_path_bisect_run());+remove_path(git_path_bisect_terms());+/* Cleanup head-name if it got left by an old version of git-bisect */+remove_path(git_path_head_name());+/*+*CleanupBISECT_STARTlasttosupportthe--no-checkoutoption+*introducedinthecommit4796e823a.+*/+remove_path(git_path_bisect_start());++returnresult;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-WRITE_TERMS+WRITE_TERMS,+BISECT_CLEAN_STATE}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -90,6 +137,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("perform 'git bisect next'"),NEXT_ALL),OPT_CMDMODE(0,"write-terms",&cmdmode,N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),+OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,+N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -108,6 +157,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=2)die(_("--write-terms requires two arguments"));returnwrite_terms(argv[0],argv[1]);+caseBISECT_CLEAN_STATE:+if(argc!=0)+die(_("--bisect-clean-state requires no arguments"));+returnbisect_clean_state();default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -187,7 +187,7 @@ bisect_start() {## Get rid of any old bisect state.#-bisect_clean_state||exit+gitbisect--helper--bisect-clean-state||exit## Change state.
@@ -196,7 +196,7 @@ bisect_start() {# We have to trap this to be able to clean up using# "bisect_clean_state".#-trap'bisect_clean_state'0+trap'git bisect--helper --bisect-clean-state'0trap'exit 255'12315#
@@ -430,27 +430,7 @@ bisect_reset() {die"$(eval_gettext"Could not check out original HEAD '\$branch'. Try'git bisect reset <commit>'.")"fi-bisect_clean_state-}--bisect_clean_state(){-# There may be some refs packed during bisection.-gitfor-each-ref--format='%(refname) %(objectname)'refs/bisect/\*|-whilereadrefhash-do-gitupdate-ref-d$ref$hash||exit-done-rm-f"$GIT_DIR/BISECT_EXPECTED_REV"&&-rm-f"$GIT_DIR/BISECT_ANCESTORS_OK"&&-rm-f"$GIT_DIR/BISECT_LOG"&&-rm-f"$GIT_DIR/BISECT_NAMES"&&-rm-f"$GIT_DIR/BISECT_RUN"&&-rm-f"$GIT_DIR/BISECT_TERMS"&&-# Cleanup head-name if it got left by an old version of git-bisect-rm-f"$GIT_DIR/head-name"&&-gitupdate-ref-d--no-derefBISECT_HEAD&&-# clean up BISECT_START last-rm-f"$GIT_DIR/BISECT_START"+gitbisect--helper--bisect-clean-state||exit} bisect_replay(){--
Add test to explicitly check that 'git bisect reset' is working as
expected. This is already covered implicitly by the test suite.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
I faced this problem while converting `bisect_clean_state` and the tests
where showing breakages but it wasn't clear as to where exactly are they
breaking. This will patch will help in that. Also I tested the test
coverage of the test suite before this patch and it covers this (I did
this by purposely changing names of files in git-bisect.sh and running
the test suite).
---
t/t6030-bisect-porcelain.sh | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
Reimplement the `check_term_format` shell function in C and add
a `--check-term-format` subcommand to `git bisect--helper` to call it
from git-bisect.sh
Using `--check-term-format` subcommand is a temporary measure to port
shell function to C so as to use the existing test suite. As more
functions are ported, this subcommand will be retired and will
be called by some other method/subcommand. For eg. In conversion of
write_terms() of git-bisect.sh, the subcommand will be removed and
instead check_term_format() will be called in its C implementation while
a new subcommand will be introduced for write_terms().
Helped-by: Johannes Schindelein [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 31 ++-----------------------
2 files changed, 60 insertions(+), 30 deletions(-)
@@ -2,19 +2,72 @@#include"cache.h"#include"parse-options.h"#include"bisect.h"+#include"refs.h"staticconstchar*constgit_bisect_helper_usage[]={N_("git bisect--helper --next-all [--no-checkout]"),+N_("git bisect--helper --check-term-format <term> <orig_term>"),NULL};+/*+*Checkwhetherthestring`term`belongstothesetofstrings+*includedinthevariablearguments.+*/+staticintone_of(constchar*term,...)+{+intres=0;+va_listmatches;+constchar*match;++va_start(matches,term);+while(!res&&(match=va_arg(matches,constchar*)))+res=!strcmp(term,match);+va_end(matches);++returnres;+}++staticintcheck_term_format(constchar*term,constchar*orig_term)+{+intres;+char*new_term=xstrfmt("refs/bisect/%s",term);++res=check_refname_format(new_term,0);+free(new_term);++if(res)+returnerror(_("'%s' is not a valid term"),term);++if(one_of(term,"help","start","skip","next","reset",+"visualize","replay","log","run",NULL))+returnerror(_("can't use the builtin command '%s' as a term"),term);++/*+*Intheory,nothingpreventsswappingcompletelygoodandbad,+*butthissituationcouldbeconfusingandhasn'tbeentested+*enough.Forbiditfornow.+*/++if((strcmp(orig_term,"bad")&&one_of(term,"bad","new",NULL))||+(strcmp(orig_term,"good")&&one_of(term,"good","old",NULL)))+returnerror(_("can't change the meaning of the term '%s'"),term);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){-enum{NEXT_ALL=1}cmdmode=0;+enum{+NEXT_ALL=1,+CHECK_TERM_FMT+}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),+OPT_CMDMODE(0,"check-term-format",&cmdmode,+N_("check format of the term"),CHECK_TERM_FMT),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -29,6 +82,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);+caseCHECK_TERM_FMT:+if(argc!=2)+die(_("--check-term-format requires two arguments"));+returncheck_term_format(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -564,38 +564,11 @@ write_terms () {thendie"$(gettext"please use two different terms")"fi-check_term_format"$TERM_BAD"bad-check_term_format"$TERM_GOOD"good+gitbisect--helper--check-term-format"$TERM_BAD"bad||exit+gitbisect--helper--check-term-format"$TERM_GOOD"good||exitprintf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"}-check_term_format(){-term=$1-gitcheck-ref-formatrefs/bisect/"$term"||-die"$(eval_gettext"'\$term' is not a valid term")"-case"$term"in-help|start|terms|skip|next|reset|visualize|replay|log|run)-die"$(eval_gettext"can't use the builtin command '\$term' as a term")"-;;-bad|new)-iftest"$2"!=bad-then-# In theory, nothing prevents swapping-# completely good and bad, but this situation-# could be confusing and hasn't been tested-# enough. Forbid it for now.-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-good|old)-iftest"$2"!=good-then-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-esac-}- check_and_set_terms(){cmd="$1"case"$cmd"in--
Reimplement the `write_terms` shell function in C and add a `write-terms`
subcommand to `git bisect--helper` to call it from git-bisect.sh . Also
remove the subcommand `--check-term-format` as it can now be called from
inside the function write_terms() C implementation.
Also `|| exit` is added when calling write-terms subcommand from
git-bisect.sh so as to exit whenever there is an error.
Using `--write-terms` subcommand is a temporary measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other method.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 36 +++++++++++++++++++++++++++++-------
git-bisect.sh | 22 +++++++---------------
2 files changed, 36 insertions(+), 22 deletions(-)
@@ -56,18 +58,38 @@ static int check_term_format(const char *term, const char *orig_term)return0;}+staticintwrite_terms(constchar*bad,constchar*good)+{+FILE*fp;+intres;++if(!strcmp(bad,good))+returnerror(_("please use two different terms"));++if(check_term_format(bad,"bad")||check_term_format(good,"good"))+return-1;++fp=fopen(git_path_bisect_terms(),"w");+if(!fp)+returnerror_errno(_("could not open the file BISECT_TERMS"));++res=fprintf(fp,"%s\n%s\n",bad,good);+fclose(fp);+return(res<0)?-1:0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-CHECK_TERM_FMT+WRITE_TERMS}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),-OPT_CMDMODE(0,"check-term-format",&cmdmode,-N_("check format of the term"),CHECK_TERM_FMT),+OPT_CMDMODE(0,"write-terms",&cmdmode,+N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -82,10 +104,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);-caseCHECK_TERM_FMT:+caseWRITE_TERMS:if(argc!=2)-die(_("--check-term-format requires two arguments"));-returncheck_term_format(argv[0],argv[1]);+die(_("--write-terms requires two arguments"));+returnwrite_terms(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -557,18 +557,6 @@ get_terms () {fi}-write_terms(){-TERM_BAD=$1-TERM_GOOD=$2-iftest"$TERM_BAD"="$TERM_GOOD"-then-die"$(gettext"please use two different terms")"-fi-gitbisect--helper--check-term-format"$TERM_BAD"bad||exit-gitbisect--helper--check-term-format"$TERM_GOOD"good||exit-printf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"-}- check_and_set_terms(){cmd="$1"case"$cmd"in
Reimplement `bisect_reset` shell function in C and add a `--bisect-reset`
subcommand to `git bisect--helper` to call it from git-bisect.sh .
Using `bisect_reset` subcommand is a temporary measure to port shell
functions to C so as to use the existing test suite. As more functions
are ported, this subcommand would be retired and will be called by some
other method.
Note: --bisect-clean-state subcommand has not been retired as there are
still a function namely `bisect_start()` which still uses this
subcommand.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 28 ++--------------------------
2 files changed, 48 insertions(+), 27 deletions(-)
@@ -124,12 +128,47 @@ static int bisect_clean_state(void)returnresult;}+staticintbisect_reset(constchar*commit)+{+structstrbufbranch=STRBUF_INIT;++if(!commit){+if(strbuf_read_file(&branch,git_path_bisect_start(),0)<1){+printf("We are not bisecting.\n");+return0;+}+strbuf_rtrim(&branch);+}else{+structobject_idoid;+if(get_oid(commit,&oid))+returnerror(_("'%s' is not a valid commit"),commit);+strbuf_addstr(&branch,commit);+}++if(!file_exists(git_path_bisect_head())){+structargv_arrayargv=ARGV_ARRAY_INIT;+argv_array_pushl(&argv,"checkout",branch.buf,"--",NULL);+if(run_command_v_opt(argv.argv,RUN_GIT_CMD)){+error(_("Could not check out original HEAD '%s'. Try"+"'git bisect reset <commit>'."),branch.buf);+strbuf_release(&branch);+argv_array_clear(&argv);+return-1;+}+argv_array_clear(&argv);+}++strbuf_release(&branch);+returnbisect_clean_state();+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,-BISECT_CLEAN_STATE+BISECT_CLEAN_STATE,+BISECT_RESET}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -139,6 +178,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,N_("cleanup the bisection state"),BISECT_CLEAN_STATE),+OPT_CMDMODE(0,"bisect-reset",&cmdmode,+N_("reset the bisection state"),BISECT_RESET),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -161,6 +202,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=0)die(_("--bisect-clean-state requires no arguments"));returnbisect_clean_state();+caseBISECT_RESET:+if(argc>1)+die(_("--bisect-reset requires either zero or one arguments"));+returnbisect_reset(argc?argv[0]:NULL);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -409,35 +409,11 @@ bisect_visualize() {eval'"$@"'--bisect--$(cat"$GIT_DIR/BISECT_NAMES")}-bisect_reset(){-test-s"$GIT_DIR/BISECT_START"||{-gettextln"We are not bisecting."-return-}-case"$#"in-0)branch=$(cat"$GIT_DIR/BISECT_START");;-1)gitrev-parse--quiet--verify"$1^{commit}">/dev/null||{-invalid="$1"-die"$(eval_gettext"'\$invalid' is not a valid commit")"-}-branch="$1";;-*)-usage;;-esac--if!test-f"$GIT_DIR/BISECT_HEAD"&&!gitcheckout"$branch"---then-die"$(eval_gettext"Could not check out original HEAD '\$branch'.-Try'git bisect reset <commit>'.")"-fi-gitbisect--helper--bisect-clean-state||exit-}- bisect_replay(){file="$1"test"$#"-eq1||die"$(gettext"No logfile given")"test-r"$file"||die"$(eval_gettext"cannot read \$file for replaying")"-bisect_reset+gitbisect--helper--bisect-reset||exitwhilereadgitbisectcommandrevdotest"$git$bisect"="git bisect"||test"$git"="git-bisect"||continue
@@ -627,7 +603,7 @@ case "$#" invisualize|view)bisect_visualize"$@";;reset)-bisect_reset"$@";;+gitbisect--helper--bisect-reset"$@";;replay)bisect_replay"$@";;log)--
Reimplement the `bisect_write` shell function in C and add a
`bisect-write` subcommand to `git bisect--helper` to call it from
git-bisect.sh
Using `--bisect-write` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Note: bisect_write() uses two variables namely TERM_GOOD and TERM_BAD
from the global shell script thus we need to pass it to the subcommand
using the arguments. We then store them in a struct bisect_terms and
pass the memory address around functions.
This patch also introduces new methods namely bisect_state_init() and
bisect_terms_release() for easy memory management for the struct
bisect_terms.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 97 ++++++++++++++++++++++++++++++++++++++++++++----
git-bisect.sh | 25 ++-----------
2 files changed, 94 insertions(+), 28 deletions(-)
@@ -188,6 +206,52 @@ static int check_expected_revs(const char **revs, int rev_nr)return0;}+staticintbisect_write(constchar*state,constchar*rev,+conststructbisect_terms*terms,intnolog)+{+structstrbuftag=STRBUF_INIT;+structstrbufcommit_name=STRBUF_INIT;+structobject_idoid;+structcommit*commit;+structpretty_print_contextpp={0};+FILE*fp;++if(!strcmp(state,terms->term_bad.buf))+strbuf_addf(&tag,"refs/bisect/%s",state);+elseif(one_of(state,terms->term_good.buf,"skip",NULL))+strbuf_addf(&tag,"refs/bisect/%s-%s",state,rev);+else+returnerror(_("Bad bisect_write argument: %s"),state);++if(get_oid(rev,&oid)){+strbuf_release(&tag);+returnerror(_("couldn't get the oid of the rev '%s'"),rev);+}++if(update_ref(NULL,tag.buf,oid.hash,NULL,0,+UPDATE_REFS_MSG_ON_ERR)){+strbuf_release(&tag);+return-1;+}+strbuf_release(&tag);++fp=fopen(git_path_bisect_log(),"a");+if(!fp)+returnerror_errno(_("couldn't open the file '%s'"),git_path_bisect_log());++commit=lookup_commit_reference(oid.hash);+format_commit_message(commit,"%s",&commit_name,&pp);+fprintf(fp,"# %s: [%s] %s\n",state,sha1_to_hex(oid.hash),+commit_name.buf);+strbuf_release(&commit_name);++if(!nolog)+fprintf(fp,"git bisect %s %s\n",state,rev);++fclose(fp);+return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -209,10 +274,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("reset the bisection state"),BISECT_RESET),OPT_CMDMODE(0,"check-expected-revs",&cmdmode,N_("check for expected revs"),CHECK_EXPECTED_REVS),+OPT_CMDMODE(0,"bisect-write",&cmdmode,+N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()};+structbisect_termsterms;+bisect_terms_init(&terms);argc=parse_options(argc,argv,prefix,options,git_bisect_helper_usage,0);
@@ -221,24 +290,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)usage_with_options(git_bisect_helper_usage,options);switch(cmdmode){+intnolog;caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);caseWRITE_TERMS:if(argc!=2)die(_("--write-terms requires two arguments"));-returnwrite_terms(argv[0],argv[1]);+res=write_terms(argv[0],argv[1]);+break;caseBISECT_CLEAN_STATE:if(argc!=0)die(_("--bisect-clean-state requires no arguments"));-returnbisect_clean_state();+res=bisect_clean_state();+break;caseBISECT_RESET:if(argc>1)die(_("--bisect-reset requires either zero or one arguments"));-returnbisect_reset(argc?argv[0]:NULL);+res=bisect_reset(argc?argv[0]:NULL);+break;caseCHECK_EXPECTED_REVS:-returncheck_expected_revs(argv,argc);+res=check_expected_revs(argv,argc);+break;+caseBISECT_WRITE:+if(argc!=4&&argc!=5)+die(_("--bisect-write requires either 4 or 5 arguments"));+nolog=(argc==5)&&!strcmp(argv[4],"nolog");+strbuf_addstr(&terms.term_good,argv[2]);+strbuf_addstr(&terms.term_bad,argv[3]);+res=bisect_write(argv[0],argv[1],&terms,nolog);+break;default:die("BUG: unknown subcommand '%d'",cmdmode);}-return0;+bisect_terms_release(&terms);+returnres;}
Reimplement `is_expected_rev` & `check_expected_revs` shell function in
C and add a `--check-expected-revs` subcommand to `git bisect--helper` to
call it from git-bisect.sh .
Using `--check-expected-revs` subcommand is a temporary measure to port
shell functions to C so as to use the existing test suite. As more
functions are ported, this subcommand would be retired and will be
called by some other method.
Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 33 ++++++++++++++++++++++++++++++++-
git-bisect.sh | 20 ++------------------
2 files changed, 34 insertions(+), 19 deletions(-)
@@ -162,13 +162,40 @@ static int bisect_reset(const char *commit)returnbisect_clean_state();}+staticintis_expected_rev(constchar*expected_hex)+{+structstrbufactual_hex=STRBUF_INIT;+intres=0;+if(strbuf_read_file(&actual_hex,git_path_bisect_expected_rev(),0)>=0){+strbuf_trim(&actual_hex);+res=!strcmp(actual_hex.buf,expected_hex);+}+strbuf_release(&actual_hex);+returnres;+}++staticintcheck_expected_revs(constchar**revs,intrev_nr)+{+inti;++for(i=0;i<rev_nr;i++){+if(!is_expected_rev(revs[i])){+remove_path(git_path_bisect_ancestors_ok());+remove_path(git_path_bisect_expected_rev());+return0;+}+}+return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,BISECT_CLEAN_STATE,-BISECT_RESET+BISECT_RESET,+CHECK_EXPECTED_REVS}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -180,6 +207,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_CMDMODE(0,"bisect-reset",&cmdmode,N_("reset the bisection state"),BISECT_RESET),+OPT_CMDMODE(0,"check-expected-revs",&cmdmode,+N_("check for expected revs"),CHECK_EXPECTED_REVS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -206,6 +235,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc>1)die(_("--bisect-reset requires either zero or one arguments"));returnbisect_reset(argc?argv[0]:NULL);+caseCHECK_EXPECTED_REVS:+returncheck_expected_revs(argv,argc);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -294,7 +278,7 @@ bisect_state() {dobisect_write"$state""$rev"done-check_expected_revs$hash_list;;+gitbisect--helper--check-expected-revs$hash_list;;*,"$TERM_BAD")die"$(eval_gettext"'git bisect \$TERM_BAD' can take only one argument.")";;*)--
`--next-all` is meant to be used as a subcommand to support multiple
"operation mode" though the current implementation does not contain any
other subcommand along side with `--next-all` but further commits will
include some more subcommands.
Helped-by: Johannes Schindelin [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
is_empty_file() can help to refactor a lot of code. This will be very
helpful in porting "git bisect" to C.
Suggested-by: Torsten Bögershausen <redacted>
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/am.c | 20 ++------------------
cache.h | 3 +++
wrapper.c | 13 +++++++++++++
3 files changed, 18 insertions(+), 18 deletions(-)
@@ -30,22 +30,6 @@#include"mailinfo.h"/**-*Returns1ifthefileisemptyordoesnotexist,0otherwise.-*/-staticintis_empty_file(constchar*filename)-{-structstatst;--if(stat(filename,&st)<0){-if(errno==ENOENT)-return1;-die_errno(_("could not stat %s"),filename);-}--return!st.st_size;-}--/***Returnsthelengthofthefirstlineofmsg.*/staticintlinelen(constchar*msg)
@@ -1323,7 +1307,7 @@ static int parse_mail(struct am_state *state, const char *mail)gotofinish;}-if(is_empty_file(am_path(state,"patch"))){+if(is_empty_or_missing_file(am_path(state,"patch"))){printf_ln(_("Patch is empty. Was it split wrong?"));die_user_resolve(state);}
@@ -1870,4 +1870,7 @@ void sleep_millisec(int millisec);*/voidsafe_create_dir(constchar*dir,intshare);+/* Return 1 if the file is empty or does not exists, 0 otherwise. */+externintis_empty_or_missing_file(constchar*filename);+#endif /* CACHE_H */
@@ -696,3 +696,16 @@ void sleep_millisec(int millisec){poll(NULL,0,millisec);}++intis_empty_or_missing_file(constchar*filename)+{+structstatst;++if(stat(filename,&st)<0){+if(errno==ENOENT)+return1;+die_errno(_("could not stat %s"),filename);+}++return!st.st_size;+}--
Add test to explicitly check that 'git bisect reset' is working as
expected. This is already covered implicitly by the test suite.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
I faced this problem while converting `bisect_clean_state` and the tests
where showing breakages but it wasn't clear as to where exactly are they
breaking. This will patch will help in that. Also I tested the test
coverage of the test suite before this patch and it covers this (I did
this by purposely changing names of files in git-bisect.sh and running
the test suite).
---
t/t6030-bisect-porcelain.sh | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
Reimplement the `write_terms` shell function in C and add a `write-terms`
subcommand to `git bisect--helper` to call it from git-bisect.sh . Also
remove the subcommand `--check-term-format` as it can now be called from
inside the function write_terms() C implementation.
Also `|| exit` is added when calling write-terms subcommand from
git-bisect.sh so as to exit whenever there is an error.
Using `--write-terms` subcommand is a temporary measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other method.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 36 +++++++++++++++++++++++++++++-------
git-bisect.sh | 22 +++++++---------------
2 files changed, 36 insertions(+), 22 deletions(-)
@@ -56,18 +58,38 @@ static int check_term_format(const char *term, const char *orig_term)return0;}+staticintwrite_terms(constchar*bad,constchar*good)+{+FILE*fp;+intres;++if(!strcmp(bad,good))+returnerror(_("please use two different terms"));++if(check_term_format(bad,"bad")||check_term_format(good,"good"))+return-1;++fp=fopen(git_path_bisect_terms(),"w");+if(!fp)+returnerror_errno(_("could not open the file BISECT_TERMS"));++res=fprintf(fp,"%s\n%s\n",bad,good);+res|=fclose(fp);+return(res<0)?-1:0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-CHECK_TERM_FMT+WRITE_TERMS}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),-OPT_CMDMODE(0,"check-term-format",&cmdmode,-N_("check format of the term"),CHECK_TERM_FMT),+OPT_CMDMODE(0,"write-terms",&cmdmode,+N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -82,10 +104,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);-caseCHECK_TERM_FMT:+caseWRITE_TERMS:if(argc!=2)-die(_("--check-term-format requires two arguments"));-returncheck_term_format(argv[0],argv[1]);+die(_("--write-terms requires two arguments"));+returnwrite_terms(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -557,18 +557,6 @@ get_terms () {fi}-write_terms(){-TERM_BAD=$1-TERM_GOOD=$2-iftest"$TERM_BAD"="$TERM_GOOD"-then-die"$(gettext"please use two different terms")"-fi-gitbisect--helper--check-term-format"$TERM_BAD"bad||exit-gitbisect--helper--check-term-format"$TERM_GOOD"good||exit-printf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"-}- check_and_set_terms(){cmd="$1"case"$cmd"in
Reimplement `bisect_reset` shell function in C and add a `--bisect-reset`
subcommand to `git bisect--helper` to call it from git-bisect.sh .
Using `bisect_reset` subcommand is a temporary measure to port shell
functions to C so as to use the existing test suite. As more functions
are ported, this subcommand would be retired and will be called by some
other method.
Note: --bisect-clean-state subcommand has not been retired as there are
still a function namely `bisect_start()` which still uses this
subcommand.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 28 ++--------------------------
2 files changed, 48 insertions(+), 27 deletions(-)
@@ -124,12 +128,47 @@ static int bisect_clean_state(void)returnresult;}+staticintbisect_reset(constchar*commit)+{+structstrbufbranch=STRBUF_INIT;++if(!commit){+if(strbuf_read_file(&branch,git_path_bisect_start(),0)<1){+printf("We are not bisecting.\n");+return0;+}+strbuf_rtrim(&branch);+}else{+structobject_idoid;+if(get_oid(commit,&oid))+returnerror(_("'%s' is not a valid commit"),commit);+strbuf_addstr(&branch,commit);+}++if(!file_exists(git_path_bisect_head())){+structargv_arrayargv=ARGV_ARRAY_INIT;+argv_array_pushl(&argv,"checkout",branch.buf,"--",NULL);+if(run_command_v_opt(argv.argv,RUN_GIT_CMD)){+error(_("Could not check out original HEAD '%s'. Try "+"'git bisect reset <commit>'."),branch.buf);+strbuf_release(&branch);+argv_array_clear(&argv);+return-1;+}+argv_array_clear(&argv);+}++strbuf_release(&branch);+returnbisect_clean_state();+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,-BISECT_CLEAN_STATE+BISECT_CLEAN_STATE,+BISECT_RESET}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -139,6 +178,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,N_("cleanup the bisection state"),BISECT_CLEAN_STATE),+OPT_CMDMODE(0,"bisect-reset",&cmdmode,+N_("reset the bisection state"),BISECT_RESET),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -161,6 +202,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=0)die(_("--bisect-clean-state requires no arguments"));returnbisect_clean_state();+caseBISECT_RESET:+if(argc>1)+die(_("--bisect-reset requires either zero or one arguments"));+returnbisect_reset(argc?argv[0]:NULL);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -409,35 +409,11 @@ bisect_visualize() {eval'"$@"'--bisect--$(cat"$GIT_DIR/BISECT_NAMES")}-bisect_reset(){-test-s"$GIT_DIR/BISECT_START"||{-gettextln"We are not bisecting."-return-}-case"$#"in-0)branch=$(cat"$GIT_DIR/BISECT_START");;-1)gitrev-parse--quiet--verify"$1^{commit}">/dev/null||{-invalid="$1"-die"$(eval_gettext"'\$invalid' is not a valid commit")"-}-branch="$1";;-*)-usage;;-esac--if!test-f"$GIT_DIR/BISECT_HEAD"&&!gitcheckout"$branch"---then-die"$(eval_gettext"Could not check out original HEAD '\$branch'.-Try'git bisect reset <commit>'.")"-fi-gitbisect--helper--bisect-clean-state||exit-}- bisect_replay(){file="$1"test"$#"-eq1||die"$(gettext"No logfile given")"test-r"$file"||die"$(eval_gettext"cannot read \$file for replaying")"-bisect_reset+gitbisect--helper--bisect-reset||exitwhilereadgitbisectcommandrevdotest"$git$bisect"="git bisect"||test"$git"="git-bisect"||continue
@@ -627,7 +603,7 @@ case "$#" invisualize|view)bisect_visualize"$@";;reset)-bisect_reset"$@";;+gitbisect--helper--bisect-reset"$@";;replay)bisect_replay"$@";;log)--
Reimplement `bisect_next_check` shell function in C and add
`bisect-next-check` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
Using `--bisect-next-check` is a temporary measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
bisect_voc() is removed as it is redundant and does not serve any useful
purpose. We are better off specifying "bad|new" "good|old" as and when
we require in bisect_next_check().
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 60 +++---------------------------------
2 files changed, 82 insertions(+), 57 deletions(-)
@@ -292,6 +294,71 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)return0;}+staticintmark_good(constchar*refname,conststructobject_id*oid,+intflag,void*cb_data)+{+int*m_good=(int*)cb_data;+*m_good=0;+return0;+}++staticintbisect_next_check(conststructbisect_terms*terms,+constchar*current_term)+{+intmissing_good=1,missing_bad=1;+char*bad_ref=xstrfmt("refs/bisect/%s",terms->term_bad.buf);+char*good_glob=xstrfmt("%s*",terms->term_good.buf);++if(ref_exists(bad_ref))+missing_bad=0;+free(bad_ref);++for_each_glob_ref_in(mark_good,good_glob,"refs/bisect/",+(void*)&missing_good);+free(good_glob);++if(!missing_good&&!missing_bad)+return0;++if(!current_term)+return-1;++if(missing_good&&!missing_bad&¤t_term&&+!strcmp(current_term,terms->term_good.buf)){+char*yesno;+/*+*havebad(ornew)butnotgood(orold).Wecouldbisect+*althoughthisislessoptimum.+*/+fprintf(stderr,"Warning: bisecting only with a %s commit\n",+terms->term_bad.buf);+if(!isatty(0))+return0;+/*+*TRANSLATORS:Makesuretoinclude[Y]and[n]inyour+*translation.TheprogramwillonlyacceptEnglishinput+*atthispoint.+*/+yesno=git_prompt(_("Are you sure [Y/n]? "),PROMPT_ECHO);+if(starts_with(yesno,"N")||starts_with(yesno,"n"))+return-1;+return0;+}+if(!is_empty_or_missing_file(git_path_bisect_start()))+returnerror(_("You need to give me at least one good|old and "+"bad|new revision. You can use \"git bisect "+"bad|new\" and \"git bisect good|old\" for "+"that. \n"));+else+returnerror(_("You need to start by \"git bisect start\". "+"You then need to give me at least one good|"+"old and bad|new revision. You can use \"git "+"bisect bad|new\" and \"git bisect good|old\" "+" for that.\n"));++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -319,6 +387,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),OPT_CMDMODE(0,"check-and-set-terms",&cmdmode,N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),+OPT_CMDMODE(0,"bisect-next-check",&cmdmode,+N_("check whether bad or good terms exist"),BISECT_NEXT_CHECK),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -271,59 +271,14 @@ bisect_state() {bisect_auto_next}-bisect_next_check(){-missing_good=missing_bad=-gitshow-ref-q--verifyrefs/bisect/$TERM_BAD||missing_bad=t-test-n"$(gitfor-each-ref"refs/bisect/$TERM_GOOD-*")"||missing_good=t--case"$missing_good,$missing_bad,$1"in-,,*)-:haveboth$TERM_GOODand$TERM_BAD-ok-;;-*,)-# do not have both but not asked to fail - just report.-false-;;-t,,"$TERM_GOOD")-# have bad (or new) but not good (or old). we could bisect although-# this is less optimum.-eval_gettextln"Warning: bisecting only with a \$TERM_BAD commit.">&2-iftest-t0-then-# TRANSLATORS: Make sure to include [Y] and [n] in your-# translation. The program will only accept English input-# at this point.-gettext"Are you sure [Y/n]? ">&2-readyesno-case"$yesno"in[Nn]*)exit1;;esac-fi-:bisectwithout$TERM_GOOD...-;;-*)-bad_syn=$(bisect_vocbad)-good_syn=$(bisect_vocgood)-iftest-s"$GIT_DIR/BISECT_START"-then--eval_gettextln"You need to give me at least one \$bad_syn and one \$good_syn revision.-(Youcanuse\"gitbisect\$bad_syn\"and\"gitbisect\$good_syn\"forthat.)" >&2-else-eval_gettextln"You need to start by \"git bisect start\".-Youthenneedtogivemeatleastone\$good_synandone\$bad_synrevision.-(Youcanuse\"gitbisect\$bad_syn\"and\"gitbisect\$good_syn\"forthat.)" >&2-fi-exit1;;-esac-}- bisect_auto_next(){-bisect_next_check&&bisect_next||:+gitbisect--helper--bisect-next-check$TERM_GOOD$TERM_BAD&&bisect_next||:} bisect_next(){case"$#"in0);;*)usage;;esacbisect_autostart-bisect_next_check$TERM_GOOD+gitbisect--helper--bisect-next-check$TERM_GOOD$TERM_BAD$TERM_GOOD||exit# Perform all bisection computation, display and checkoutgitbisect--helper--next-all$(test-f"$GIT_DIR/BISECT_HEAD"&&echo--no-checkout)
Reimplement the `get_terms` and `bisect_terms` shell function in C and
add `bisect-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
In the shell version, the terms were identified by strings but in C
version its done by bit manipulation and passing the integer value to
the function.
Using `--bisect-terms` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 35 ++---------------------
2 files changed, 75 insertions(+), 34 deletions(-)
@@ -359,6 +367,43 @@ static int bisect_next_check(const struct bisect_terms *terms,return0;}+staticintget_terms(structbisect_terms*terms)+{+FILE*fp;+intres;+fp=fopen(git_path_bisect_terms(),"r");+if(!fp)+return-1;++bisect_terms_reset(terms);+res=strbuf_getline(&terms->term_bad,fp)==EOF||+strbuf_getline(&terms->term_good,fp)==EOF;++fclose(fp);+returnres?-1:0;+}++staticintbisect_terms(structbisect_terms*terms,intterm_defined)+{+if(get_terms(terms)){+fprintf(stderr,"no terms defined\n");+return-1;+}+if(!term_defined){+printf("Your current terms are %s for the old state\nand "+"%s for the new state.\n",terms->term_good.buf,+terms->term_bad.buf);+return0;+}++if(term_defined==TERM_GOOD||term_defined==TERM_OLD)+printf("%s\n",terms->term_good.buf);+if(term_defined==TERM_BAD||term_defined==TERM_NEW)+printf("%s\n",terms->term_bad.buf);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -389,6 +436,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),OPT_CMDMODE(0,"bisect-next-check",&cmdmode,N_("check whether bad or good terms exist"),BISECT_NEXT_CHECK),+OPT_CMDMODE(0,"bisect-terms",&cmdmode,+N_("print out the bisect terms"),BISECT_TERMS),+OPT_BIT(0,"term-bad",&term_defined,+N_("show the bad term"),TERM_BAD),+OPT_BIT(0,"term-good",&term_defined,+N_("show the good term"),TERM_GOOD),+OPT_BIT(0,"term-new",&term_defined,+N_("show the new term"),TERM_NEW),+OPT_BIT(0,"term-old",&term_defined,+N_("show the old term"),TERM_OLD),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -399,6 +456,16 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)argc=parse_options(argc,argv,prefix,options,git_bisect_helper_usage,0);+if(cmdmode!=BISECT_TERMS&&term_defined)+die(_("--term-bad, --term-good, --term-new and --term-old "+"can be used only with --bisect-terms"));++if(term_defined!=0&&term_defined!=TERM_BAD&&+term_defined!=TERM_GOOD&&term_defined!=TERM_NEW&&+term_defined!=TERM_OLD)+die(_("only one option among --term-bad, --term-good, "+"--term-new and --term-old can be used."));+if(!cmdmode)usage_with_options(git_bisect_helper_usage,options);
@@ -355,7 +355,7 @@ bisect_replay () {"$TERM_GOOD"|"$TERM_BAD"|skip)gitbisect--helper--bisect-write"$command""$rev""$TERM_GOOD""$TERM_BAD"||exit;;terms)-bisect_terms$rev;;+gitbisect--helper--bisect-terms$rev||exit;;*)die"$(gettext"?? what are you talking about?")";;esac
@@ -437,37 +437,6 @@ get_terms () {fi}-bisect_terms(){-get_terms-if!test-s"$GIT_DIR/BISECT_TERMS"-then-die"$(gettext"no terms defined")"-fi-case"$#"in-0)-gettextln"Your current terms are $TERM_GOOD for the old state-and$TERM_BADforthenewstate."-;;-1)-arg=$1-case"$arg"in---term-good|--term-old)-printf'%s\n'"$TERM_GOOD"-;;---term-bad|--term-new)-printf'%s\n'"$TERM_BAD"-;;-*)-die"$(eval_gettext"invalid argument \$arg for 'git bisect terms'.-Supportedoptionsare:--term-good|--term-oldand--term-bad|--term-new.")"-;;-esac-;;-*)-usage;;-esac-}-case"$#"in0)usage;;
@@ -498,7 +467,7 @@ case "$#" inrun)bisect_run"$@";;terms)-bisect_terms"$@";;+gitbisect--helper--bisect-terms"$@"||exit;;*)usage;;esac--
Reimplement `is_expected_rev` & `check_expected_revs` shell function in
C and add a `--check-expected-revs` subcommand to `git bisect--helper` to
call it from git-bisect.sh .
Using `--check-expected-revs` subcommand is a temporary measure to port
shell functions to C so as to use the existing test suite. As more
functions are ported, this subcommand would be retired and will be
called by some other method.
Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 33 ++++++++++++++++++++++++++++++++-
git-bisect.sh | 20 ++------------------
2 files changed, 34 insertions(+), 19 deletions(-)
@@ -162,13 +162,40 @@ static int bisect_reset(const char *commit)returnbisect_clean_state();}+staticintis_expected_rev(constchar*expected_hex)+{+structstrbufactual_hex=STRBUF_INIT;+intres=0;+if(strbuf_read_file(&actual_hex,git_path_bisect_expected_rev(),0)>=0){+strbuf_trim(&actual_hex);+res=!strcmp(actual_hex.buf,expected_hex);+}+strbuf_release(&actual_hex);+returnres;+}++staticintcheck_expected_revs(constchar**revs,intrev_nr)+{+inti;++for(i=0;i<rev_nr;i++){+if(!is_expected_rev(revs[i])){+remove_path(git_path_bisect_ancestors_ok());+remove_path(git_path_bisect_expected_rev());+return0;+}+}+return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,BISECT_CLEAN_STATE,-BISECT_RESET+BISECT_RESET,+CHECK_EXPECTED_REVS}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -180,6 +207,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_CMDMODE(0,"bisect-reset",&cmdmode,N_("reset the bisection state"),BISECT_RESET),+OPT_CMDMODE(0,"check-expected-revs",&cmdmode,+N_("check for expected revs"),CHECK_EXPECTED_REVS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -206,6 +235,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc>1)die(_("--bisect-reset requires either zero or one arguments"));returnbisect_reset(argc?argv[0]:NULL);+caseCHECK_EXPECTED_REVS:+returncheck_expected_revs(argv,argc);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -294,7 +278,7 @@ bisect_state() {dobisect_write"$state""$rev"done-check_expected_revs$hash_list;;+gitbisect--helper--check-expected-revs$hash_list;;*,"$TERM_BAD")die"$(eval_gettext"'git bisect \$TERM_BAD' can take only one argument.")";;*)--
Reimplement the `bisect_write` shell function in C and add a
`bisect-write` subcommand to `git bisect--helper` to call it from
git-bisect.sh
Using `--bisect-write` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Note: bisect_write() uses two variables namely TERM_GOOD and TERM_BAD
from the global shell script thus we need to pass it to the subcommand
using the arguments. We then store them in a struct bisect_terms and
pass the memory address around functions.
This patch also introduces new methods namely bisect_state_init() and
bisect_terms_release() for easy memory management for the struct
bisect_terms.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 97 ++++++++++++++++++++++++++++++++++++++++++++----
git-bisect.sh | 25 ++-----------
2 files changed, 94 insertions(+), 28 deletions(-)
@@ -188,6 +206,52 @@ static int check_expected_revs(const char **revs, int rev_nr)return0;}+staticintbisect_write(constchar*state,constchar*rev,+conststructbisect_terms*terms,intnolog)+{+structstrbuftag=STRBUF_INIT;+structstrbufcommit_name=STRBUF_INIT;+structobject_idoid;+structcommit*commit;+structpretty_print_contextpp={0};+FILE*fp;++if(!strcmp(state,terms->term_bad.buf))+strbuf_addf(&tag,"refs/bisect/%s",state);+elseif(one_of(state,terms->term_good.buf,"skip",NULL))+strbuf_addf(&tag,"refs/bisect/%s-%s",state,rev);+else+returnerror(_("Bad bisect_write argument: %s"),state);++if(get_oid(rev,&oid)){+strbuf_release(&tag);+returnerror(_("couldn't get the oid of the rev '%s'"),rev);+}++if(update_ref(NULL,tag.buf,oid.hash,NULL,0,+UPDATE_REFS_MSG_ON_ERR)){+strbuf_release(&tag);+return-1;+}+strbuf_release(&tag);++fp=fopen(git_path_bisect_log(),"a");+if(!fp)+returnerror_errno(_("couldn't open the file '%s'"),git_path_bisect_log());++commit=lookup_commit_reference(oid.hash);+format_commit_message(commit,"%s",&commit_name,&pp);+fprintf(fp,"# %s: [%s] %s\n",state,sha1_to_hex(oid.hash),+commit_name.buf);+strbuf_release(&commit_name);++if(!nolog)+fprintf(fp,"git bisect %s %s\n",state,rev);++fclose(fp);+return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -209,10 +274,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("reset the bisection state"),BISECT_RESET),OPT_CMDMODE(0,"check-expected-revs",&cmdmode,N_("check for expected revs"),CHECK_EXPECTED_REVS),+OPT_CMDMODE(0,"bisect-write",&cmdmode,+N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()};+structbisect_termsterms;+bisect_terms_init(&terms);argc=parse_options(argc,argv,prefix,options,git_bisect_helper_usage,0);
@@ -221,24 +290,38 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)usage_with_options(git_bisect_helper_usage,options);switch(cmdmode){+intnolog;caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);caseWRITE_TERMS:if(argc!=2)die(_("--write-terms requires two arguments"));-returnwrite_terms(argv[0],argv[1]);+res=write_terms(argv[0],argv[1]);+break;caseBISECT_CLEAN_STATE:if(argc!=0)die(_("--bisect-clean-state requires no arguments"));-returnbisect_clean_state();+res=bisect_clean_state();+break;caseBISECT_RESET:if(argc>1)die(_("--bisect-reset requires either zero or one arguments"));-returnbisect_reset(argc?argv[0]:NULL);+res=bisect_reset(argc?argv[0]:NULL);+break;caseCHECK_EXPECTED_REVS:-returncheck_expected_revs(argv,argc);+res=check_expected_revs(argv,argc);+break;+caseBISECT_WRITE:+if(argc!=4&&argc!=5)+die(_("--bisect-write requires either 4 or 5 arguments"));+nolog=(argc==5)&&!strcmp(argv[4],"nolog");+strbuf_addstr(&terms.term_good,argv[2]);+strbuf_addstr(&terms.term_bad,argv[3]);+res=bisect_write(argv[0],argv[1],&terms,nolog);+break;default:die("BUG: unknown subcommand '%d'",cmdmode);}-return0;+bisect_terms_release(&terms);+returnres;}
Reimplement the `check_term_format` shell function in C and add
a `--check-term-format` subcommand to `git bisect--helper` to call it
from git-bisect.sh
Using `--check-term-format` subcommand is a temporary measure to port
shell function to C so as to use the existing test suite. As more
functions are ported, this subcommand will be retired and will
be called by some other method/subcommand. For eg. In conversion of
write_terms() of git-bisect.sh, the subcommand will be removed and
instead check_term_format() will be called in its C implementation while
a new subcommand will be introduced for write_terms().
Helped-by: Johannes Schindelein [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 31 ++-----------------------
2 files changed, 60 insertions(+), 30 deletions(-)
@@ -2,19 +2,72 @@#include"cache.h"#include"parse-options.h"#include"bisect.h"+#include"refs.h"staticconstchar*constgit_bisect_helper_usage[]={N_("git bisect--helper --next-all [--no-checkout]"),+N_("git bisect--helper --check-term-format <term> <orig_term>"),NULL};+/*+*Checkwhetherthestring`term`belongstothesetofstrings+*includedinthevariablearguments.+*/+staticintone_of(constchar*term,...)+{+intres=0;+va_listmatches;+constchar*match;++va_start(matches,term);+while(!res&&(match=va_arg(matches,constchar*)))+res=!strcmp(term,match);+va_end(matches);++returnres;+}++staticintcheck_term_format(constchar*term,constchar*orig_term)+{+intres;+char*new_term=xstrfmt("refs/bisect/%s",term);++res=check_refname_format(new_term,0);+free(new_term);++if(res)+returnerror(_("'%s' is not a valid term"),term);++if(one_of(term,"help","start","skip","next","reset",+"visualize","replay","log","run",NULL))+returnerror(_("can't use the builtin command '%s' as a term"),term);++/*+*Intheory,nothingpreventsswappingcompletelygoodandbad,+*butthissituationcouldbeconfusingandhasn'tbeentested+*enough.Forbiditfornow.+*/++if((strcmp(orig_term,"bad")&&one_of(term,"bad","new",NULL))||+(strcmp(orig_term,"good")&&one_of(term,"good","old",NULL)))+returnerror(_("can't change the meaning of the term '%s'"),term);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){-enum{NEXT_ALL=1}cmdmode=0;+enum{+NEXT_ALL=1,+CHECK_TERM_FMT+}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),+OPT_CMDMODE(0,"check-term-format",&cmdmode,+N_("check format of the term"),CHECK_TERM_FMT),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -29,6 +82,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);+caseCHECK_TERM_FMT:+if(argc!=2)+die(_("--check-term-format requires two arguments"));+returncheck_term_format(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -564,38 +564,11 @@ write_terms () {thendie"$(gettext"please use two different terms")"fi-check_term_format"$TERM_BAD"bad-check_term_format"$TERM_GOOD"good+gitbisect--helper--check-term-format"$TERM_BAD"bad||exit+gitbisect--helper--check-term-format"$TERM_GOOD"good||exitprintf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"}-check_term_format(){-term=$1-gitcheck-ref-formatrefs/bisect/"$term"||-die"$(eval_gettext"'\$term' is not a valid term")"-case"$term"in-help|start|terms|skip|next|reset|visualize|replay|log|run)-die"$(eval_gettext"can't use the builtin command '\$term' as a term")"-;;-bad|new)-iftest"$2"!=bad-then-# In theory, nothing prevents swapping-# completely good and bad, but this situation-# could be confusing and hasn't been tested-# enough. Forbid it for now.-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-good|old)-iftest"$2"!=good-then-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-esac-}- check_and_set_terms(){cmd="$1"case"$cmd"in--
Reimplement the `check_and_set_terms` shell function in C and add
`check-and-set-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh
Using `--check-and-set-terms` subcommand is a temporary measure to port
shell function in C so as to use the existing test suite. As more
functions are ported, this subcommand will be retired and will be called
by some other methods.
check_and_set_terms() sets and receives two global variables namely
TERM_GOOD and TERM_BAD in the shell script. Luckily the file BISECT_TERMS
also contains the value of those variables so its appropriate to evoke the
method get_terms() after calling the subcommand so that it retrieves the
value of TERM_GOOD and TERM_BAD from the file BISECT_TERMS. The two
global variables are passed as arguments to the subcommand.
Also introduce bisect_terms_reset() to empty the contents of `term_good`
and `term_bad` of `struct bisect_terms`.
Also introduce set_terms() to copy the `term_good` and `term_bad` into
`struct bisect_terms` and write it out to the file BISECT_TERMS.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 36 ++++-----------------------------
2 files changed, 55 insertions(+), 33 deletions(-)
@@ -252,6 +259,39 @@ static int bisect_write(const char *state, const char *rev,return0;}+staticintset_terms(structbisect_terms*terms,constchar*bad,+constchar*good)+{+bisect_terms_reset(terms);+strbuf_addstr(&terms->term_good,good);+strbuf_addstr(&terms->term_bad,bad);+returnwrite_terms(terms->term_bad.buf,terms->term_good.buf);+}++staticintcheck_and_set_terms(structbisect_terms*terms,constchar*cmd)+{+intno_term_file=is_empty_or_missing_file(git_path_bisect_terms());++if(one_of(cmd,"skip","start","terms",NULL))+return0;++if(!no_term_file&&+strcmp(cmd,terms->term_bad.buf)&&+strcmp(cmd,terms->term_good.buf))+returnerror(_("Invalid command: you're currently in a "+"'%s' '%s' bisect"),terms->term_bad.buf,+terms->term_good.buf);++if(no_term_file){+if(one_of(cmd,"bad","good",NULL))+returnset_terms(terms,"bad","good");+if(one_of(cmd,"new","old",NULL))+returnset_terms(terms,"new","old");+}++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -276,6 +317,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("check for expected revs"),CHECK_EXPECTED_REVS),OPT_CMDMODE(0,"bisect-write",&cmdmode,N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),+OPT_CMDMODE(0,"check-and-set-terms",&cmdmode,+N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -239,7 +239,8 @@ bisect_skip() { bisect_state(){bisect_autostartstate=$1-check_and_set_terms$state+gitbisect--helper--check-and-set-terms$state$TERM_GOOD$TERM_BAD||exit+get_termscase"$#,$state"in0,*)die"$(gettext"Please call 'bisect_state' with at least one argument.")";;
@@ -480,36 +482,6 @@ get_terms () {fi}-check_and_set_terms(){-cmd="$1"-case"$cmd"in-skip|start|terms);;-*)-iftest-s"$GIT_DIR/BISECT_TERMS"&&test"$cmd"!="$TERM_BAD"&&test"$cmd"!="$TERM_GOOD"-then-die"$(eval_gettext"Invalid command: you're currently in a \$TERM_BAD/\$TERM_GOOD bisect.")"-fi-case"$cmd"in-bad|good)-if!test-s"$GIT_DIR/BISECT_TERMS"-then-TERM_BAD=bad-TERM_GOOD=good-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"||exit-fi-;;-new|old)-if!test-s"$GIT_DIR/BISECT_TERMS"-then-TERM_BAD=new-TERM_GOOD=old-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"||exit-fi-;;-esac;;-esac-}- bisect_voc(){case"$1"inbad)echo"bad|new";;--
Reimplement the `bisect_start` shell function partially in C and add
`bisect-start` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
The last part is not converted because it calls another shell function.
`bisect_start` shell function will be completed after the `bisect_next`
shell function is ported in C.
Using `--bisect-start` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
This patch contains a small bug. The option handling for `--term-good`
and `--term-bad` needs to be decided as it is now shared between
`--bisect-terms` and `--bisect-start` and the later one also requires
string support. Can comments on which approach would seem the most
feasible? Here[1] is a normal output of t6030 and here[2] is a verbose
output of [2].
[1]: http://paste.ubuntu.com/21252069/
[2]: http://paste.ubuntu.com/21252140/
---
builtin/bisect--helper.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 132 +--------------------------
2 files changed, 232 insertions(+), 132 deletions(-)
@@ -404,6 +404,228 @@ static int bisect_terms(struct bisect_terms *terms, int term_defined)return0;}+staticintbisect_start(structbisect_terms*terms,intno_checkout,+constchar**argv,intargc)+{+inti,j,has_double_dash=0,must_write_terms=0,bad_seen=0;+intflag;+structstring_listrevs=STRING_LIST_INIT_DUP;+structstring_liststates=STRING_LIST_INIT_DUP;+structstrbufstart_head=STRBUF_INIT;+constchar*head;+unsignedcharsha1[20];+FILE*fp;+structobject_idoid;++if(is_bare_repository())+no_checkout=1;++for(i=0;i<argc;i++){+if(!strcmp(argv[i],"--")){+has_double_dash=1;+break;+}+if(!strcmp(argv[i],"--term-good")){+must_write_terms=1;+strbuf_reset(&terms->term_good);+strbuf_addstr(&terms->term_good,argv[++i]);+break;+}+if(!strcmp(argv[i],"--term-bad")){+must_write_terms=1;+strbuf_reset(&terms->term_bad);+strbuf_addstr(&terms->term_bad,argv[++i]);+break;+}+if(starts_with(argv[i],"--")&&+!one_of(argv[i],"--term-good","--term-bad",NULL)){+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("unrecognised option: '%s'"),argv[i]);+}+if(get_oid(argv[i],&oid)||has_double_dash){+string_list_clear(&revs,0);+string_list_clear(&revs,0);+die(_("'%s' does not appear to be a valid revision"),argv[i]);+}+else+string_list_append(&revs,oid_to_hex(&oid));+}++for(j=0;j<revs.nr;j++){+structstrbufstate=STRBUF_INIT;+/*+*Theuserran"git bisect start <sha1> <sha1>",hence+*didnotexplicitlyspecifytheterms,butwearealready+*startingtosetreferencesnamedwiththedefaultterms,+*andwon'tbeabletochangeafterwards.+*/+must_write_terms=1;++if(bad_seen)+strbuf_addstr(&state,terms->term_good.buf);+else{+bad_seen=1;+strbuf_addstr(&state,terms->term_bad.buf);+}+string_list_append(&states,state.buf);+strbuf_release(&state);+}++/*+*VerifyHEAD+*/+head=resolve_ref_unsafe("HEAD",0,sha1,&flag);+if(!head){+if(get_sha1("HEAD",sha1)){+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("Bad HEAD - I need a HEAD"));+}+}+if(!is_empty_or_missing_file(git_path_bisect_start())){+/* Reset to the rev from where we started */+strbuf_read_file(&start_head,git_path_bisect_start(),0);+strbuf_trim(&start_head);+if(!no_checkout){+structargv_arrayargv=ARGV_ARRAY_INIT;+argv_array_pushl(&argv,"checkout",start_head.buf,+"--",NULL);+if(run_command_v_opt(argv.argv,RUN_GIT_CMD)){+error(_("checking out '%s' failed. Try again."),+start_head.buf);+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+}+}else{+if(starts_with(head,"refs/head/")||!get_oid(head,&oid)){+/*+*Thiserrormessageshouldonlybetriggeredby+*cogitousage,andcogitousersshouldunderstand+*itrelatestocg-seek.+*/+if(!is_empty_or_missing_file(git_path_head_name())){+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("won't bisect on cg-seek'ed tree"));+}+if(starts_with(head,"refs/heads/")){+strbuf_reset(&start_head);+strbuf_addstr(&start_head,head+11);+}+else{+strbuf_reset(&start_head);+strbuf_addstr(&start_head,sha1_to_hex(sha1));+}+}else{+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("Bad HEAD - strange symbolic ref"));+}+}++/*+*Getridofanyoldbisectstate.+*/+if(bisect_clean_state()){+return-1;+}++/*+*Writenewstartstate+*/+fp=fopen(git_path_bisect_start(),"w");+if(!fp){+bisect_clean_state();+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+if(!fprintf(fp,"%s\n",start_head.buf)){+fclose(fp);+bisect_clean_state();+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+fclose(fp);++if(no_checkout){+get_oid(start_head.buf,&oid);+if(update_ref(NULL,"BISECT_HEAD",oid.hash,NULL,0,+UPDATE_REFS_MSG_ON_ERR)){+bisect_clean_state();+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+}+strbuf_release(&start_head);+fp=fopen(git_path_bisect_names(),"w");++for(;i<argc;i++){+if(!fprintf(fp,"%s ",argv[i])){+fclose(fp);+bisect_clean_state();+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+}+fclose(fp);++for(j=0;j<states.nr;j++){+if(bisect_write(states.items[j].string,+revs.items[j].string,terms,1)){+bisect_clean_state();+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+}+string_list_clear(&revs,0);+string_list_clear(&states,0);++if(must_write_terms)+if(write_terms(terms->term_bad.buf,terms->term_good.buf)){+bisect_clean_state();+return-1;+}++fp=fopen(git_path_bisect_log(),"a");+if(!fp){+bisect_clean_state();+return-1;+}+if(!fprintf(fp,"git bisect start")){+bisect_clean_state();+return-1;+}+for(i=0;i<argc;i++){+if(!fprintf(fp," '%s'",argv[i])){+fclose(fp);+bisect_clean_state();+return-1;+}+}+if(!fprintf(fp,"\n")){+fclose(fp);+bisect_clean_state();+return-1;+}+fclose(fp);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -446,6 +669,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("show the new term"),TERM_NEW),OPT_BIT(0,"term-old",&term_defined,N_("show the old term"),TERM_OLD),+OPT_CMDMODE(0,"bisect-start",&cmdmode,+N_("start the bisect session"),BISECT_START),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -72,122 +72,7 @@ bisect_autostart() {} bisect_start(){-#-# Check for one bad and then some good revisions.-#-has_double_dash=0-forarg;do-case"$arg"in--)has_double_dash=1;break;;esac-done-orig_args=$(gitrev-parse--sq-quote"$@")-bad_seen=0-eval=''-must_write_terms=0-revs=''-iftest"z$(gitrev-parse--is-bare-repository)"!=zfalse-then-mode=--no-checkout-else-mode=''-fi-while[$#-gt0];do-arg="$1"-case"$arg"in---)-shift-break-;;---no-checkout)-mode=--no-checkout-shift;;---term-good|--term-old)-shift-must_write_terms=1-TERM_GOOD=$1-shift;;---term-good=*|--term-old=*)-must_write_terms=1-TERM_GOOD=${1#*=}-shift;;---term-bad|--term-new)-shift-must_write_terms=1-TERM_BAD=$1-shift;;---term-bad=*|--term-new=*)-must_write_terms=1-TERM_BAD=${1#*=}-shift;;---*)-die"$(eval_gettext"unrecognised option: '\$arg'")";;-*)-rev=$(gitrev-parse-q--verify"$arg^{commit}")||{-test$has_double_dash-eq1&&-die"$(eval_gettext"'\$arg' does not appear to be a valid revision")"-break-}-revs="$revs$rev"-shift-;;-esac-done--forrevin$revs-do-# The user ran "git bisect start <sha1>-# <sha1>", hence did not explicitly specify-# the terms, but we are already starting to-# set references named with the default terms,-# and won't be able to change afterwards.-must_write_terms=1--case$bad_seenin-0)state=$TERM_BAD;bad_seen=1;;-*)state=$TERM_GOOD;;-esac-eval="$eval git bisect--helper --bisect-write '$state' '$rev' '$TERM_GOOD' '$TERM_BAD' 'nolog' &&"-done-#-# Verify HEAD.-#-head=$(GIT_DIR="$GIT_DIR"gitsymbolic-ref-qHEAD)||-head=$(GIT_DIR="$GIT_DIR"gitrev-parse--verifyHEAD)||-die"$(gettext"Bad HEAD - I need a HEAD")"--#-# Check if we are bisecting.-#-start_head=''-iftest-s"$GIT_DIR/BISECT_START"-then-# Reset to the rev from where we started.-start_head=$(cat"$GIT_DIR/BISECT_START")-iftest"z$mode"!="z--no-checkout"-then-gitcheckout"$start_head"--||-die"$(eval_gettext"Checking out '\$start_head' failed. Try 'git bisect reset <valid-branch>'.")"-fi-else-# Get rev from where we start.-case"$head"in-refs/heads/*|$_x40)-# This error message should only be triggered by-# cogito usage, and cogito users should understand-# it relates to cg-seek.-[-s"$GIT_DIR/head-name"]&&-die"$(gettext"won't bisect on cg-seek'ed tree")"-start_head="${head#refs/heads/}"-;;-*)-die"$(gettext"Bad HEAD - strange symbolic ref")"-;;-esac-fi--#-# Get rid of any old bisect state.-#-gitbisect--helper--bisect-clean-state||exit+gitbisect--helper--bisect-start$@||exit## Change state.
@@ -198,21 +83,6 @@ bisect_start() {#trap'git bisect--helper --bisect-clean-state'0trap'exit 255'12315--#-# Write new start state.-#-echo"$start_head">"$GIT_DIR/BISECT_START"&&{-test"z$mode"!="z--no-checkout"||-gitupdate-ref--no-derefBISECT_HEAD"$start_head"-}&&-gitrev-parse--sq-quote"$@">"$GIT_DIR/BISECT_NAMES"&&-eval"$eval true"&&-iftest$must_write_terms-eq1-then-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"-fi&&-echo"git bisect start$orig_args">>"$GIT_DIR/BISECT_LOG"||exit## Check if we can proceed to the next bisect state.#--
Reimplement `bisect_clean_state` shell function in C and add a
`bisect-clean-state` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
Using `--bisect-clean-state` subcommand is a measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by
bisect_reset() and bisect_start().
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 26 +++--------------------
2 files changed, 57 insertions(+), 24 deletions(-)
@@ -78,11 +87,49 @@ static int write_terms(const char *bad, const char *good)return(res<0)?-1:0;}+staticintmark_for_removal(constchar*refname,conststructobject_id*oid,+intflag,void*cb_data)+{+structstring_list*refs=cb_data;+char*ref=xstrfmt("refs/bisect/%s",refname);+string_list_append(refs,ref);+return0;+}++staticintbisect_clean_state(void)+{+intresult=0;++/* There may be some refs packed during bisection */+structstring_listrefs_for_removal=STRING_LIST_INIT_NODUP;+for_each_ref_in("refs/bisect/",mark_for_removal,(void*)&refs_for_removal);+string_list_append(&refs_for_removal,xstrdup("BISECT_HEAD"));+result=delete_refs(&refs_for_removal);+refs_for_removal.strdup_strings=1;+string_list_clear(&refs_for_removal,0);+remove_path(git_path_bisect_expected_rev());+remove_path(git_path_bisect_ancestors_ok());+remove_path(git_path_bisect_log());+remove_path(git_path_bisect_names());+remove_path(git_path_bisect_run());+remove_path(git_path_bisect_terms());+/* Cleanup head-name if it got left by an old version of git-bisect */+remove_path(git_path_head_name());+/*+*CleanupBISECT_STARTlasttosupportthe--no-checkoutoption+*introducedinthecommit4796e823a.+*/+remove_path(git_path_bisect_start());++returnresult;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-WRITE_TERMS+WRITE_TERMS,+BISECT_CLEAN_STATE}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -90,6 +137,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("perform 'git bisect next'"),NEXT_ALL),OPT_CMDMODE(0,"write-terms",&cmdmode,N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),+OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,+N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -108,6 +157,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=2)die(_("--write-terms requires two arguments"));returnwrite_terms(argv[0],argv[1]);+caseBISECT_CLEAN_STATE:+if(argc!=0)+die(_("--bisect-clean-state requires no arguments"));+returnbisect_clean_state();default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -187,7 +187,7 @@ bisect_start() {## Get rid of any old bisect state.#-bisect_clean_state||exit+gitbisect--helper--bisect-clean-state||exit## Change state.
@@ -196,7 +196,7 @@ bisect_start() {# We have to trap this to be able to clean up using# "bisect_clean_state".#-trap'bisect_clean_state'0+trap'git bisect--helper --bisect-clean-state'0trap'exit 255'12315#
@@ -430,27 +430,7 @@ bisect_reset() {die"$(eval_gettext"Could not check out original HEAD '\$branch'. Try'git bisect reset <commit>'.")"fi-bisect_clean_state-}--bisect_clean_state(){-# There may be some refs packed during bisection.-gitfor-each-ref--format='%(refname) %(objectname)'refs/bisect/\*|-whilereadrefhash-do-gitupdate-ref-d$ref$hash||exit-done-rm-f"$GIT_DIR/BISECT_EXPECTED_REV"&&-rm-f"$GIT_DIR/BISECT_ANCESTORS_OK"&&-rm-f"$GIT_DIR/BISECT_LOG"&&-rm-f"$GIT_DIR/BISECT_NAMES"&&-rm-f"$GIT_DIR/BISECT_RUN"&&-rm-f"$GIT_DIR/BISECT_TERMS"&&-# Cleanup head-name if it got left by an old version of git-bisect-rm-f"$GIT_DIR/head-name"&&-gitupdate-ref-d--no-derefBISECT_HEAD&&-# clean up BISECT_START last-rm-f"$GIT_DIR/BISECT_START"+gitbisect--helper--bisect-clean-state||exit} bisect_replay(){--
`--next-all` is meant to be used as a subcommand to support multiple
"operation mode" though the current implementation does not contain any
other subcommand along side with `--next-all` but further commits will
include some more subcommands.
Helped-by: Johannes Schindelin [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
Reimplement the `check_and_set_terms` shell function in C and add
`check-and-set-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh
Using `--check-and-set-terms` subcommand is a temporary measure to port
shell function in C so as to use the existing test suite. As more
functions are ported, this subcommand will be retired but its
implementation will be called by some other methods.
check_and_set_terms() sets and receives two global variables namely
TERM_GOOD and TERM_BAD in the shell script. Luckily the file BISECT_TERMS
also contains the value of those variables so its appropriate to evoke the
method get_terms() after calling the subcommand so that it retrieves the
value of TERM_GOOD and TERM_BAD from the file BISECT_TERMS. The two
global variables are passed as arguments to the subcommand.
Also introduce bisect_terms_reset() to empty the contents of `term_good`
and `term_bad` of `struct bisect_terms`.
Also introduce set_terms() to copy the `term_good` and `term_bad` into
`struct bisect_terms` and write it out to the file BISECT_TERMS.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 36 ++++-----------------------------
2 files changed, 55 insertions(+), 33 deletions(-)
@@ -253,6 +260,39 @@ static int bisect_write(const char *state, const char *rev,return0;}+staticintset_terms(structbisect_terms*terms,constchar*bad,+constchar*good)+{+bisect_terms_reset(terms);+strbuf_addstr(&terms->term_good,good);+strbuf_addstr(&terms->term_bad,bad);+returnwrite_terms(terms->term_bad.buf,terms->term_good.buf);+}++staticintcheck_and_set_terms(structbisect_terms*terms,constchar*cmd)+{+inthas_term_file=!is_empty_or_missing_file(git_path_bisect_terms());++if(one_of(cmd,"skip","start","terms",NULL))+return0;++if(has_term_file&&+strcmp(cmd,terms->term_bad.buf)&&+strcmp(cmd,terms->term_good.buf))+returnerror(_("Invalid command: you're currently in a "+"%s/%s bisect"),terms->term_bad.buf,+terms->term_good.buf);++if(!has_term_file){+if(one_of(cmd,"bad","good",NULL))+returnset_terms(terms,"bad","good");+if(one_of(cmd,"new","old",NULL))+returnset_terms(terms,"new","old");+}++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -277,6 +318,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("check for expected revs"),CHECK_EXPECTED_REVS),OPT_CMDMODE(0,"bisect-write",&cmdmode,N_("write out the bisection state in BISECT_LOG"),BISECT_WRITE),+OPT_CMDMODE(0,"check-and-set-terms",&cmdmode,+N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -239,7 +239,8 @@ bisect_skip() { bisect_state(){bisect_autostartstate=$1-check_and_set_terms$state+gitbisect--helper--check-and-set-terms$state$TERM_GOOD$TERM_BAD||exit+get_termscase"$#,$state"in0,*)die"$(gettext"Please call 'bisect_state' with at least one argument.")";;
@@ -480,36 +482,6 @@ get_terms () {fi}-check_and_set_terms(){-cmd="$1"-case"$cmd"in-skip|start|terms);;-*)-iftest-s"$GIT_DIR/BISECT_TERMS"&&test"$cmd"!="$TERM_BAD"&&test"$cmd"!="$TERM_GOOD"-then-die"$(eval_gettext"Invalid command: you're currently in a \$TERM_BAD/\$TERM_GOOD bisect.")"-fi-case"$cmd"in-bad|good)-if!test-s"$GIT_DIR/BISECT_TERMS"-then-TERM_BAD=bad-TERM_GOOD=good-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"||exit-fi-;;-new|old)-if!test-s"$GIT_DIR/BISECT_TERMS"-then-TERM_BAD=new-TERM_GOOD=old-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"||exit-fi-;;-esac;;-esac-}- bisect_voc(){case"$1"inbad)echo"bad|new";;--
Reimplement the `write_terms` shell function in C and add a `write-terms`
subcommand to `git bisect--helper` to call it from git-bisect.sh . Also
remove the subcommand `--check-term-format` as it can now be called from
inside the function write_terms() C implementation.
Also `|| exit` is added when calling write-terms subcommand from
git-bisect.sh so as to exit whenever there is an error.
Using `--write-terms` subcommand is a temporary measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and its implementation will
be called by some other method.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 36 +++++++++++++++++++++++++++++-------
git-bisect.sh | 22 +++++++---------------
2 files changed, 36 insertions(+), 22 deletions(-)
@@ -57,18 +59,38 @@ static int check_term_format(const char *term, const char *orig_term)return0;}+staticintwrite_terms(constchar*bad,constchar*good)+{+FILE*fp;+intres;++if(!strcmp(bad,good))+returnerror(_("please use two different terms"));++if(check_term_format(bad,"bad")||check_term_format(good,"good"))+return-1;++fp=fopen(git_path_bisect_terms(),"w");+if(!fp)+returnerror_errno(_("could not open the file BISECT_TERMS"));++res=fprintf(fp,"%s\n%s\n",bad,good);+res|=fclose(fp);+return(res<0)?-1:0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-CHECK_TERM_FMT+WRITE_TERMS}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),-OPT_CMDMODE(0,"check-term-format",&cmdmode,-N_("check format of the term"),CHECK_TERM_FMT),+OPT_CMDMODE(0,"write-terms",&cmdmode,+N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -83,10 +105,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);-caseCHECK_TERM_FMT:+caseWRITE_TERMS:if(argc!=2)-die(_("--check-term-format requires two arguments"));-returncheck_term_format(argv[0],argv[1]);+die(_("--write-terms requires two arguments"));+returnwrite_terms(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -557,18 +557,6 @@ get_terms () {fi}-write_terms(){-TERM_BAD=$1-TERM_GOOD=$2-iftest"$TERM_BAD"="$TERM_GOOD"-then-die"$(gettext"please use two different terms")"-fi-gitbisect--helper--check-term-format"$TERM_BAD"bad||exit-gitbisect--helper--check-term-format"$TERM_GOOD"good||exit-printf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"-}- check_and_set_terms(){cmd="$1"case"$cmd"in
Reimplement `bisect_reset` shell function in C and add a `--bisect-reset`
subcommand to `git bisect--helper` to call it from git-bisect.sh .
Using `bisect_reset` subcommand is a temporary measure to port shell
functions to C so as to use the existing test suite. As more functions
are ported, this subcommand would be retired but its implementation will
be called by some other method.
Note: --bisect-clean-state subcommand has not been retired as there are
still a function namely `bisect_start()` which still uses this
subcommand.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 28 ++--------------------------
2 files changed, 48 insertions(+), 27 deletions(-)
@@ -125,12 +129,47 @@ static int bisect_clean_state(void)returnresult;}+staticintbisect_reset(constchar*commit)+{+structstrbufbranch=STRBUF_INIT;++if(!commit){+if(strbuf_read_file(&branch,git_path_bisect_start(),0)<1){+printf("We are not bisecting.\n");+return0;+}+strbuf_rtrim(&branch);+}else{+structobject_idoid;+if(get_oid(commit,&oid))+returnerror(_("'%s' is not a valid commit"),commit);+strbuf_addstr(&branch,commit);+}++if(!file_exists(git_path_bisect_head())){+structargv_arrayargv=ARGV_ARRAY_INIT;+argv_array_pushl(&argv,"checkout",branch.buf,"--",NULL);+if(run_command_v_opt(argv.argv,RUN_GIT_CMD)){+error(_("Could not check out original HEAD '%s'. Try "+"'git bisect reset <commit>'."),branch.buf);+strbuf_release(&branch);+argv_array_clear(&argv);+return-1;+}+argv_array_clear(&argv);+}++strbuf_release(&branch);+returnbisect_clean_state();+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,-BISECT_CLEAN_STATE+BISECT_CLEAN_STATE,+BISECT_RESET}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -140,6 +179,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,N_("cleanup the bisection state"),BISECT_CLEAN_STATE),+OPT_CMDMODE(0,"bisect-reset",&cmdmode,+N_("reset the bisection state"),BISECT_RESET),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -162,6 +203,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=0)die(_("--bisect-clean-state requires no arguments"));returnbisect_clean_state();+caseBISECT_RESET:+if(argc>1)+die(_("--bisect-reset requires either zero or one arguments"));+returnbisect_reset(argc?argv[0]:NULL);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -409,35 +409,11 @@ bisect_visualize() {eval'"$@"'--bisect--$(cat"$GIT_DIR/BISECT_NAMES")}-bisect_reset(){-test-s"$GIT_DIR/BISECT_START"||{-gettextln"We are not bisecting."-return-}-case"$#"in-0)branch=$(cat"$GIT_DIR/BISECT_START");;-1)gitrev-parse--quiet--verify"$1^{commit}">/dev/null||{-invalid="$1"-die"$(eval_gettext"'\$invalid' is not a valid commit")"-}-branch="$1";;-*)-usage;;-esac--if!test-f"$GIT_DIR/BISECT_HEAD"&&!gitcheckout"$branch"---then-die"$(eval_gettext"Could not check out original HEAD '\$branch'.-Try'git bisect reset <commit>'.")"-fi-gitbisect--helper--bisect-clean-state||exit-}- bisect_replay(){file="$1"test"$#"-eq1||die"$(gettext"No logfile given")"test-r"$file"||die"$(eval_gettext"cannot read \$file for replaying")"-bisect_reset+gitbisect--helper--bisect-reset||exitwhilereadgitbisectcommandrevdotest"$git$bisect"="git bisect"||test"$git"="git-bisect"||continue
@@ -627,7 +603,7 @@ case "$#" invisualize|view)bisect_visualize"$@";;reset)-bisect_reset"$@";;+gitbisect--helper--bisect-reset"$@";;replay)bisect_replay"$@";;log)--
Reimplement the `check_term_format` shell function in C and add
a `--check-term-format` subcommand to `git bisect--helper` to call it
from git-bisect.sh
Using `--check-term-format` subcommand is a temporary measure to port
shell function to C so as to use the existing test suite. As more
functions are ported, this subcommand will be retired and its
implementation will be called by some other method/subcommand. For
eg. In conversion of write_terms() of git-bisect.sh, the subcommand will
be removed and instead check_term_format() will be called in its C
implementation while a new subcommand will be introduced for write_terms().
Helped-by: Johannes Schindelein [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 31 ++-----------------------
2 files changed, 61 insertions(+), 30 deletions(-)
@@ -2,19 +2,73 @@#include"cache.h"#include"parse-options.h"#include"bisect.h"+#include"refs.h"staticconstchar*constgit_bisect_helper_usage[]={N_("git bisect--helper --next-all [--no-checkout]"),+N_("git bisect--helper --check-term-format <term> <orig_term>"),NULL};+/*+*Checkwhetherthestring`term`belongstothesetofstrings+*includedinthevariablearguments.+*/+LAST_ARG_MUST_BE_NULL+staticintone_of(constchar*term,...)+{+intres=0;+va_listmatches;+constchar*match;++va_start(matches,term);+while(!res&&(match=va_arg(matches,constchar*)))+res=!strcmp(term,match);+va_end(matches);++returnres;+}++staticintcheck_term_format(constchar*term,constchar*orig_term)+{+intres;+char*new_term=xstrfmt("refs/bisect/%s",term);++res=check_refname_format(new_term,0);+free(new_term);++if(res)+returnerror(_("'%s' is not a valid term"),term);++if(one_of(term,"help","start","skip","next","reset",+"visualize","replay","log","run",NULL))+returnerror(_("can't use the builtin command '%s' as a term"),term);++/*+*Intheory,nothingpreventsswappingcompletelygoodandbad,+*butthissituationcouldbeconfusingandhasn'tbeentested+*enough.Forbiditfornow.+*/++if((strcmp(orig_term,"bad")&&one_of(term,"bad","new",NULL))||+(strcmp(orig_term,"good")&&one_of(term,"good","old",NULL)))+returnerror(_("can't change the meaning of the term '%s'"),term);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){-enum{NEXT_ALL=1}cmdmode=0;+enum{+NEXT_ALL=1,+CHECK_TERM_FMT+}cmdmode=0;intno_checkout=0;structoptionoptions[]={OPT_CMDMODE(0,"next-all",&cmdmode,N_("perform 'git bisect next'"),NEXT_ALL),+OPT_CMDMODE(0,"check-term-format",&cmdmode,+N_("check format of the term"),CHECK_TERM_FMT),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -29,6 +83,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)switch(cmdmode){caseNEXT_ALL:returnbisect_next_all(prefix,no_checkout);+caseCHECK_TERM_FMT:+if(argc!=2)+die(_("--check-term-format requires two arguments"));+returncheck_term_format(argv[0],argv[1]);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -564,38 +564,11 @@ write_terms () {thendie"$(gettext"please use two different terms")"fi-check_term_format"$TERM_BAD"bad-check_term_format"$TERM_GOOD"good+gitbisect--helper--check-term-format"$TERM_BAD"bad||exit+gitbisect--helper--check-term-format"$TERM_GOOD"good||exitprintf'%s\n%s\n'"$TERM_BAD""$TERM_GOOD">"$GIT_DIR/BISECT_TERMS"}-check_term_format(){-term=$1-gitcheck-ref-formatrefs/bisect/"$term"||-die"$(eval_gettext"'\$term' is not a valid term")"-case"$term"in-help|start|terms|skip|next|reset|visualize|replay|log|run)-die"$(eval_gettext"can't use the builtin command '\$term' as a term")"-;;-bad|new)-iftest"$2"!=bad-then-# In theory, nothing prevents swapping-# completely good and bad, but this situation-# could be confusing and hasn't been tested-# enough. Forbid it for now.-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-good|old)-iftest"$2"!=good-then-die"$(eval_gettext"can't change the meaning of term '\$term'")"-fi-;;-esac-}- check_and_set_terms(){cmd="$1"case"$cmd"in--
Reimplement the `bisect_start` shell function partially in C and add
`bisect-start` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
The last part is not converted because it calls another shell function.
`bisect_start` shell function will be completed after the `bisect_next`
shell function is ported in C.
Using `--bisect-start` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired and will be called by some
other methods.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 254 ++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 133 +------------------------
2 files changed, 254 insertions(+), 133 deletions(-)
@@ -431,6 +434,244 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc)return0;}+staticintbisect_start(structbisect_terms*terms,intno_checkout,+constchar**argv,intargc)+{+inti,has_double_dash=0,must_write_terms=0,bad_seen=0;+intflags,pathspec_pos;+structstring_listrevs=STRING_LIST_INIT_DUP;+structstring_liststates=STRING_LIST_INIT_DUP;+structstrbufstart_head=STRBUF_INIT;+structstrbufbisect_names=STRBUF_INIT;+structstrbuforig_args=STRBUF_INIT;+constchar*head;+unsignedcharsha1[20];+FILE*fp;+structobject_idoid;++if(is_bare_repository())+no_checkout=1;++for(i=0;i<argc;i++){+char*commit_id=xstrfmt("%s^{commit}",argv[i]);+if(!strcmp(argv[i],"--")){+has_double_dash=1;+break;+}+elseif(!strcmp(argv[i],"--no-checkout"))+no_checkout=1;+elseif(!strcmp(argv[i],"--term-good")||+!strcmp(argv[i],"--term-old")){+must_write_terms=1;+strbuf_reset(&terms->term_good);+strbuf_addstr(&terms->term_good,argv[++i]);+}+elseif(skip_prefix(argv[i],"--term-good=",&argv[i])){+must_write_terms=1;+strbuf_reset(&terms->term_good);+strbuf_addstr(&terms->term_good,argv[i]);+}+elseif(skip_prefix(argv[i],"--term-old=",&argv[i])){+must_write_terms=1;+strbuf_reset(&terms->term_good);+strbuf_addstr(&terms->term_good,argv[i]);+}+elseif(!strcmp(argv[i],"--term-bad")||+!strcmp(argv[i],"--term-new")){+must_write_terms=1;+strbuf_reset(&terms->term_bad);+strbuf_addstr(&terms->term_bad,argv[++i]);+}+elseif(skip_prefix(argv[i],"--term-bad=",&argv[i])){+must_write_terms=1;+strbuf_reset(&terms->term_bad);+strbuf_addstr(&terms->term_bad,argv[i]);+}+elseif(skip_prefix(argv[i],"--term-new=",&argv[i])){+must_write_terms=1;+strbuf_reset(&terms->term_good);+strbuf_addstr(&terms->term_good,argv[i]);+}+elseif(starts_with(argv[i],"--")&&+!one_of(argv[i],"--term-good","--term-bad",NULL)){+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("unrecognised option: '%s'"),argv[i]);+}+elseif(get_oid(argv[i],&oid)&&!has_double_dash){+string_list_clear(&revs,0);+string_list_clear(&states,0);+free(commit_id);+die(_("'%s' does not appear to be a valid revision"),argv[i]);+}+else{+free(commit_id);+string_list_append(&revs,oid_to_hex(&oid));+}+}+pathspec_pos=i;++/*+*Theuserran"git bisect start <sha1> <sha1>",hencedidnot+*explicitlyspecifytheterms,butwearealreadystartingto+*setreferencesnamedwiththedefaultterms,andwon'tbeable+*tochangeafterwards.+*/+must_write_terms|=!!revs.nr;+for(i=0;i<revs.nr;i++){+if(bad_seen)+string_list_append(&states,terms->term_good.buf);+else{+bad_seen=1;+string_list_append(&states,terms->term_bad.buf);+}+}++/*+*VerifyHEAD+*/+head=resolve_ref_unsafe("HEAD",0,sha1,&flags);+if(!head){+if(get_sha1("HEAD",sha1)){+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("Bad HEAD - I need a HEAD"));+}+}+if(!is_empty_or_missing_file(git_path_bisect_start())){+/* Reset to the rev from where we started */+strbuf_read_file(&start_head,git_path_bisect_start(),0);+strbuf_trim(&start_head);+if(!no_checkout){+structargv_arrayargv=ARGV_ARRAY_INIT;+argv_array_pushl(&argv,"checkout",start_head.buf,+"--",NULL);+if(run_command_v_opt(argv.argv,RUN_GIT_CMD)){+error(_("checking out '%s' failed. Try 'git "+"bisect start <valid-branch>'."),+start_head.buf);+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+}+}else{+if(starts_with(head,"refs/heads/")||+!get_oid_hex(head,&oid)||ref_exists(head)){+/*+*Thiserrormessageshouldonlybetriggeredby+*cogitousage,andcogitousersshouldunderstand+*itrelatestocg-seek.+*/+if(!is_empty_or_missing_file(git_path_head_name())){+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("won't bisect on cg-seek'ed tree"));+}+if(starts_with(head,"refs/heads/")){+strbuf_reset(&start_head);+strbuf_addstr(&start_head,head+11);+}+else{+strbuf_reset(&start_head);+strbuf_addstr(&start_head,sha1_to_hex(sha1));+}+}else{+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+die(_("Bad HEAD - strange symbolic ref"));+}+}++/*+*Getridofanyoldbisectstate.+*/+if(bisect_clean_state()){+return-1;+}+/*+*Incaseofmistakenrevsorcheckouterror,orsignalsreceived,+*"bisect_auto_next"belowmayexitormisbehave.+*Wehavetotrapthistobeabletocleanupusing+*"bisect_clean_state".+*/++/*+*Writenewstartstate+*/+if(write_file(git_path_bisect_start(),"%s\n",start_head.buf)){+bisect_clean_state();+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}++if(no_checkout){+get_oid(start_head.buf,&oid);+if(update_ref(NULL,"BISECT_HEAD",oid.hash,NULL,0,+UPDATE_REFS_MSG_ON_ERR)){+bisect_clean_state();+strbuf_release(&start_head);+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+}+strbuf_release(&start_head);++if(pathspec_pos<argc-1)+sq_quote_argv(&bisect_names,argv+pathspec_pos,0);+write_file(git_path_bisect_names(),"%s\n",bisect_names.buf);+strbuf_release(&bisect_names);++for(i=0;i<states.nr;i++){+if(bisect_write(states.items[i].string,+revs.items[i].string,terms,1)){+bisect_clean_state();+string_list_clear(&revs,0);+string_list_clear(&states,0);+return-1;+}+}+string_list_clear(&revs,0);+string_list_clear(&states,0);++if(must_write_terms)+if(write_terms(terms->term_bad.buf,terms->term_good.buf)){+bisect_clean_state();+return-1;+}++fp=fopen(git_path_bisect_log(),"a");+if(!fp){+bisect_clean_state();+return-1;+}+if(fprintf(fp,"git bisect start")<1){+bisect_clean_state();+return-1;+}+sq_quote_argv(&orig_args,argv,0);+if(fprintf(fp,"%s",orig_args.buf)<0){+bisect_clean_state();+strbuf_release(&orig_args);+return-1;+}+strbuf_release(&orig_args);+if(fprintf(fp,"\n")<1){+fclose(fp);+bisect_clean_state();+return-1;+}+fclose(fp);++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -464,6 +706,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("check whether bad or good terms exist"),BISECT_NEXT_CHECK),OPT_CMDMODE(0,"bisect-terms",&cmdmode,N_("print out the bisect terms"),BISECT_TERMS),+OPT_CMDMODE(0,"bisect-start",&cmdmode,+N_("start the bisect session"),BISECT_START),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -72,122 +72,7 @@ bisect_autostart() {} bisect_start(){-#-# Check for one bad and then some good revisions.-#-has_double_dash=0-forarg;do-case"$arg"in--)has_double_dash=1;break;;esac-done-orig_args=$(gitrev-parse--sq-quote"$@")-bad_seen=0-eval=''-must_write_terms=0-revs=''-iftest"z$(gitrev-parse--is-bare-repository)"!=zfalse-then-mode=--no-checkout-else-mode=''-fi-while[$#-gt0];do-arg="$1"-case"$arg"in---)-shift-break-;;---no-checkout)-mode=--no-checkout-shift;;---term-good|--term-old)-shift-must_write_terms=1-TERM_GOOD=$1-shift;;---term-good=*|--term-old=*)-must_write_terms=1-TERM_GOOD=${1#*=}-shift;;---term-bad|--term-new)-shift-must_write_terms=1-TERM_BAD=$1-shift;;---term-bad=*|--term-new=*)-must_write_terms=1-TERM_BAD=${1#*=}-shift;;---*)-die"$(eval_gettext"unrecognised option: '\$arg'")";;-*)-rev=$(gitrev-parse-q--verify"$arg^{commit}")||{-test$has_double_dash-eq1&&-die"$(eval_gettext"'\$arg' does not appear to be a valid revision")"-break-}-revs="$revs$rev"-shift-;;-esac-done--forrevin$revs-do-# The user ran "git bisect start <sha1>-# <sha1>", hence did not explicitly specify-# the terms, but we are already starting to-# set references named with the default terms,-# and won't be able to change afterwards.-must_write_terms=1--case$bad_seenin-0)state=$TERM_BAD;bad_seen=1;;-*)state=$TERM_GOOD;;-esac-eval="$eval git bisect--helper --bisect-write '$state' '$rev' '$TERM_GOOD' '$TERM_BAD' 'nolog' &&"-done-#-# Verify HEAD.-#-head=$(GIT_DIR="$GIT_DIR"gitsymbolic-ref-qHEAD)||-head=$(GIT_DIR="$GIT_DIR"gitrev-parse--verifyHEAD)||-die"$(gettext"Bad HEAD - I need a HEAD")"--#-# Check if we are bisecting.-#-start_head=''-iftest-s"$GIT_DIR/BISECT_START"-then-# Reset to the rev from where we started.-start_head=$(cat"$GIT_DIR/BISECT_START")-iftest"z$mode"!="z--no-checkout"-then-gitcheckout"$start_head"--||-die"$(eval_gettext"Checking out '\$start_head' failed. Try 'git bisect reset <valid-branch>'.")"-fi-else-# Get rev from where we start.-case"$head"in-refs/heads/*|$_x40)-# This error message should only be triggered by-# cogito usage, and cogito users should understand-# it relates to cg-seek.-[-s"$GIT_DIR/head-name"]&&-die"$(gettext"won't bisect on cg-seek'ed tree")"-start_head="${head#refs/heads/}"-;;-*)-die"$(gettext"Bad HEAD - strange symbolic ref")"-;;-esac-fi--#-# Get rid of any old bisect state.-#-gitbisect--helper--bisect-clean-state||exit+gitbisect--helper--bisect-start$@||exit## Change state.
@@ -198,24 +83,10 @@ bisect_start() {#trap'git bisect--helper --bisect-clean-state'0trap'exit 255'12315--#-# Write new start state.-#-echo"$start_head">"$GIT_DIR/BISECT_START"&&{-test"z$mode"!="z--no-checkout"||-gitupdate-ref--no-derefBISECT_HEAD"$start_head"-}&&-gitrev-parse--sq-quote"$@">"$GIT_DIR/BISECT_NAMES"&&-eval"$eval true"&&-iftest$must_write_terms-eq1-then-gitbisect--helper--write-terms"$TERM_BAD""$TERM_GOOD"-fi&&-echo"git bisect start$orig_args">>"$GIT_DIR/BISECT_LOG"||exit## Check if we can proceed to the next bisect state.#+get_termsbisect_auto_nexttrap'-'0--
From: Christian Couder <hidden> Date: 2016-08-13 07:34:09
On Wed, Aug 10, 2016 at 11:57 PM, Pranit Bauva [off-list ref] wrote:
quoted hunk
@@ -431,6 +434,244 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc) return 0; }+static int bisect_start(struct bisect_terms *terms, int no_checkout,+ const char **argv, int argc)+{+ int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;+ int flags, pathspec_pos;+ struct string_list revs = STRING_LIST_INIT_DUP;+ struct string_list states = STRING_LIST_INIT_DUP;+ struct strbuf start_head = STRBUF_INIT;+ struct strbuf bisect_names = STRBUF_INIT;+ struct strbuf orig_args = STRBUF_INIT;+ const char *head;+ unsigned char sha1[20];+ FILE *fp;+ struct object_id oid;++ if (is_bare_repository())+ no_checkout = 1;++ for (i = 0; i < argc; i++) {+ char *commit_id = xstrfmt("%s^{commit}", argv[i]);+ if (!strcmp(argv[i], "--")) {+ has_double_dash = 1;+ break;+ }
In the shell code there is a loop dedicated to checking if there is a
double dash in the arguments before the real argument parsing loop.
There is a reason for that.
If you do it in the same loop, has_double_dash will not be set when
the arguments that are before the double dash will be parsed.
And here checking "!has_double_dash" has no meaning if you check for a
double dash in the same loop, because there is a "break" after
has_double_dash is set above.
+ string_list_clear(&revs, 0);
+ string_list_clear(&states, 0);
+ free(commit_id);
+ die(_("'%s' does not appear to be a valid revision"), argv[i]);
+ }
+ else {
+ free(commit_id);
+ string_list_append(&revs, oid_to_hex(&oid));
+ }
+ }
+ pathspec_pos = i;
+
Hey Christian,
On Sat, Aug 13, 2016 at 1:04 PM, Christian Couder
[off-list ref] wrote:
On Wed, Aug 10, 2016 at 11:57 PM, Pranit Bauva [off-list ref] wrote:
quoted
@@ -431,6 +434,244 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc) return 0; }+static int bisect_start(struct bisect_terms *terms, int no_checkout,+ const char **argv, int argc)+{+ int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;+ int flags, pathspec_pos;+ struct string_list revs = STRING_LIST_INIT_DUP;+ struct string_list states = STRING_LIST_INIT_DUP;+ struct strbuf start_head = STRBUF_INIT;+ struct strbuf bisect_names = STRBUF_INIT;+ struct strbuf orig_args = STRBUF_INIT;+ const char *head;+ unsigned char sha1[20];+ FILE *fp;+ struct object_id oid;++ if (is_bare_repository())+ no_checkout = 1;++ for (i = 0; i < argc; i++) {+ char *commit_id = xstrfmt("%s^{commit}", argv[i]);+ if (!strcmp(argv[i], "--")) {+ has_double_dash = 1;+ break;+ }
In the shell code there is a loop dedicated to checking if there is a
double dash in the arguments before the real argument parsing loop.
There is a reason for that.
If you do it in the same loop, has_double_dash will not be set when
the arguments that are before the double dash will be parsed.
I had tried that before. But somehow I couldn't get it to run so I
reverted back. I have now successfully tried it and its working. You
can checkout the PR[1].
And here checking "!has_double_dash" has no meaning if you check for a
double dash in the same loop, because there is a "break" after
has_double_dash is set above.
I think this is the situation in the shell script too.
quoted
+ string_list_clear(&revs, 0);
+ string_list_clear(&states, 0);
+ free(commit_id);
+ die(_("'%s' does not appear to be a valid revision"), argv[i]);
+ }
+ else {
+ free(commit_id);
+ string_list_append(&revs, oid_to_hex(&oid));
+ }
+ }
+ pathspec_pos = i;
+
Reimplement the `get_terms` and `bisect_terms` shell function in C and
add `bisect-terms` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
Using `--bisect-terms` subcommand is a temporary measure to port shell
function in C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired but its implementation will
be called by some other methods.
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++--
git-bisect.sh | 35 ++--------------------------
2 files changed, 59 insertions(+), 35 deletions(-)
@@ -384,6 +385,52 @@ static int bisect_next_check(const struct bisect_terms *terms,return0;}+staticintget_terms(structbisect_terms*terms)+{+FILE*fp;+intres;+fp=fopen(git_path_bisect_terms(),"r");+if(!fp)+return-1;++bisect_terms_reset(terms);+res=strbuf_getline(&terms->term_bad,fp)==EOF||+strbuf_getline(&terms->term_good,fp)==EOF;++fclose(fp);+returnres?-1:0;+}++staticintbisect_terms(structbisect_terms*terms,constchar**argv,intargc)+{+inti;++if(get_terms(terms)){+fprintf(stderr,N_("no terms defined\n"));+return-1;+}+if(argc==0){+printf(N_("Your current terms are %s for the old state\nand "+"%s for the new state.\n"),terms->term_good.buf,+terms->term_bad.buf);+return0;+}++for(i=0;i<argc;i++){+if(!strcmp(argv[i],"--term-good"))+printf(N_("%s\n"),terms->term_good.buf);+elseif(!strcmp(argv[i],"--term-bad"))+printf(N_("%s\n"),terms->term_bad.buf);+else+printf(N_("invalid argument %s for 'git bisect "+"terms'.\nSupported options are: "+"--term-good|--term-old and "+"--term-bad|--term-new."),argv[i]);+}++return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{
@@ -414,6 +462,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("check and set terms in a bisection state"),CHECK_AND_SET_TERMS),OPT_CMDMODE(0,"bisect-next-check",&cmdmode,N_("check whether bad or good terms exist"),BISECT_NEXT_CHECK),+OPT_CMDMODE(0,"bisect-terms",&cmdmode,+N_("print out the bisect terms"),BISECT_TERMS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -355,7 +355,7 @@ bisect_replay () {"$TERM_GOOD"|"$TERM_BAD"|skip)gitbisect--helper--bisect-write"$command""$rev""$TERM_GOOD""$TERM_BAD"||exit;;terms)-bisect_terms$rev;;+gitbisect--helper--bisect-terms$rev||exit;;*)die"$(gettext"?? what are you talking about?")";;esac
@@ -437,37 +437,6 @@ get_terms () {fi}-bisect_terms(){-get_terms-if!test-s"$GIT_DIR/BISECT_TERMS"-then-die"$(gettext"no terms defined")"-fi-case"$#"in-0)-gettextln"Your current terms are $TERM_GOOD for the old state-and$TERM_BADforthenewstate."-;;-1)-arg=$1-case"$arg"in---term-good|--term-old)-printf'%s\n'"$TERM_GOOD"-;;---term-bad|--term-new)-printf'%s\n'"$TERM_BAD"-;;-*)-die"$(eval_gettext"invalid argument \$arg for 'git bisect terms'.-Supportedoptionsare:--term-good|--term-oldand--term-bad|--term-new.")"-;;-esac-;;-*)-usage;;-esac-}-case"$#"in0)usage;;
@@ -498,7 +467,7 @@ case "$#" inrun)bisect_run"$@";;terms)-bisect_terms"$@";;+gitbisect--helper--bisect-terms"$@"||exit;;*)usage;;esac--
Reimplement `bisect_clean_state` shell function in C and add a
`bisect-clean-state` subcommand to `git bisect--helper` to call it from
git-bisect.sh .
Using `--bisect-clean-state` subcommand is a measure to port shell
function to C so as to use the existing test suite. As more functions
are ported, this subcommand will be retired but its implementation will
be called by bisect_reset() and bisect_start().
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++-
git-bisect.sh | 26 +++--------------------
2 files changed, 57 insertions(+), 24 deletions(-)
@@ -79,11 +88,49 @@ static int write_terms(const char *bad, const char *good)return(res<0)?-1:0;}+staticintmark_for_removal(constchar*refname,conststructobject_id*oid,+intflag,void*cb_data)+{+structstring_list*refs=cb_data;+char*ref=xstrfmt("refs/bisect/%s",refname);+string_list_append(refs,ref);+return0;+}++staticintbisect_clean_state(void)+{+intresult=0;++/* There may be some refs packed during bisection */+structstring_listrefs_for_removal=STRING_LIST_INIT_NODUP;+for_each_ref_in("refs/bisect/",mark_for_removal,(void*)&refs_for_removal);+string_list_append(&refs_for_removal,xstrdup("BISECT_HEAD"));+result=delete_refs(&refs_for_removal);+refs_for_removal.strdup_strings=1;+string_list_clear(&refs_for_removal,0);+unlink_or_warn(git_path_bisect_expected_rev());+unlink_or_warn(git_path_bisect_ancestors_ok());+unlink_or_warn(git_path_bisect_log());+unlink_or_warn(git_path_bisect_names());+unlink_or_warn(git_path_bisect_run());+unlink_or_warn(git_path_bisect_terms());+/* Cleanup head-name if it got left by an old version of git-bisect */+unlink_or_warn(git_path_head_name());+/*+*CleanupBISECT_STARTlasttosupportthe--no-checkoutoption+*introducedinthecommit4796e823a.+*/+unlink_or_warn(git_path_bisect_start());++returnresult;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,-WRITE_TERMS+WRITE_TERMS,+BISECT_CLEAN_STATE}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -91,6 +138,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("perform 'git bisect next'"),NEXT_ALL),OPT_CMDMODE(0,"write-terms",&cmdmode,N_("write the terms to .git/BISECT_TERMS"),WRITE_TERMS),+OPT_CMDMODE(0,"bisect-clean-state",&cmdmode,+N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -109,6 +158,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc!=2)die(_("--write-terms requires two arguments"));returnwrite_terms(argv[0],argv[1]);+caseBISECT_CLEAN_STATE:+if(argc!=0)+die(_("--bisect-clean-state requires no arguments"));+returnbisect_clean_state();default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -187,7 +187,7 @@ bisect_start() {## Get rid of any old bisect state.#-bisect_clean_state||exit+gitbisect--helper--bisect-clean-state||exit## Change state.
@@ -196,7 +196,7 @@ bisect_start() {# We have to trap this to be able to clean up using# "bisect_clean_state".#-trap'bisect_clean_state'0+trap'git bisect--helper --bisect-clean-state'0trap'exit 255'12315#
@@ -430,27 +430,7 @@ bisect_reset() {die"$(eval_gettext"Could not check out original HEAD '\$branch'. Try'git bisect reset <commit>'.")"fi-bisect_clean_state-}--bisect_clean_state(){-# There may be some refs packed during bisection.-gitfor-each-ref--format='%(refname) %(objectname)'refs/bisect/\*|-whilereadrefhash-do-gitupdate-ref-d$ref$hash||exit-done-rm-f"$GIT_DIR/BISECT_EXPECTED_REV"&&-rm-f"$GIT_DIR/BISECT_ANCESTORS_OK"&&-rm-f"$GIT_DIR/BISECT_LOG"&&-rm-f"$GIT_DIR/BISECT_NAMES"&&-rm-f"$GIT_DIR/BISECT_RUN"&&-rm-f"$GIT_DIR/BISECT_TERMS"&&-# Cleanup head-name if it got left by an old version of git-bisect-rm-f"$GIT_DIR/head-name"&&-gitupdate-ref-d--no-derefBISECT_HEAD&&-# clean up BISECT_START last-rm-f"$GIT_DIR/BISECT_START"+gitbisect--helper--bisect-clean-state||exit} bisect_replay(){--
Reimplement `is_expected_rev` & `check_expected_revs` shell function in
C and add a `--check-expected-revs` subcommand to `git bisect--helper` to
call it from git-bisect.sh .
Using `--check-expected-revs` subcommand is a temporary measure to port
shell functions to C so as to use the existing test suite. As more
functions are ported, this subcommand would be retired but its
implementation will be called by some other method.
Helped-by: Eric Sunshine [off-list ref]
Mentored-by: Lars Schneider [off-list ref]
Mentored-by: Christian Couder [off-list ref]
Signed-off-by: Pranit Bauva <redacted>
---
builtin/bisect--helper.c | 33 ++++++++++++++++++++++++++++++++-
git-bisect.sh | 20 ++------------------
2 files changed, 34 insertions(+), 19 deletions(-)
@@ -163,13 +163,40 @@ static int bisect_reset(const char *commit)returnbisect_clean_state();}+staticintis_expected_rev(constchar*expected_hex)+{+structstrbufactual_hex=STRBUF_INIT;+intres=0;+if(strbuf_read_file(&actual_hex,git_path_bisect_expected_rev(),0)>=0){+strbuf_trim(&actual_hex);+res=!strcmp(actual_hex.buf,expected_hex);+}+strbuf_release(&actual_hex);+returnres;+}++staticintcheck_expected_revs(constchar**revs,intrev_nr)+{+inti;++for(i=0;i<rev_nr;i++){+if(!is_expected_rev(revs[i])){+unlink_or_warn(git_path_bisect_ancestors_ok());+unlink_or_warn(git_path_bisect_expected_rev());+return0;+}+}+return0;+}+intcmd_bisect__helper(intargc,constchar**argv,constchar*prefix){enum{NEXT_ALL=1,WRITE_TERMS,BISECT_CLEAN_STATE,-BISECT_RESET+BISECT_RESET,+CHECK_EXPECTED_REVS}cmdmode=0;intno_checkout=0;structoptionoptions[]={
@@ -181,6 +208,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)N_("cleanup the bisection state"),BISECT_CLEAN_STATE),OPT_CMDMODE(0,"bisect-reset",&cmdmode,N_("reset the bisection state"),BISECT_RESET),+OPT_CMDMODE(0,"check-expected-revs",&cmdmode,+N_("check for expected revs"),CHECK_EXPECTED_REVS),OPT_BOOL(0,"no-checkout",&no_checkout,N_("update BISECT_HEAD instead of checking out the current commit")),OPT_END()
@@ -207,6 +236,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)if(argc>1)die(_("--bisect-reset requires either zero or one arguments"));returnbisect_reset(argc?argv[0]:NULL);+caseCHECK_EXPECTED_REVS:+returncheck_expected_revs(argv,argc);default:die("BUG: unknown subcommand '%d'",cmdmode);}
@@ -294,7 +278,7 @@ bisect_state() {dobisect_write"$state""$rev"done-check_expected_revs$hash_list;;+gitbisect--helper--check-expected-revs$hash_list;;*,"$TERM_BAD")die"$(eval_gettext"'git bisect \$TERM_BAD' can take only one argument.")";;*)--