Skip to content

Commit 0f30233

Browse files
pranitbauva1997gitster
authored andcommitted
bisect--helper: bisect_write shell function in C
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 but its implementation 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. Add a log_commit() helper function to write the contents of the commit message header to a file which will be re-used in future parts of the code as well. Also introduce a function free_terms() to free the memory of `struct bisect_terms` and set_terms() to set the values of members in `struct bisect_terms`. Helped-by: Ramsay Jones <[email protected]> Mentored-by: Lars Schneider <[email protected]> Mentored-by: Christian Couder <[email protected]> Mentored-by: Johannes Schindelin <[email protected]> Signed-off-by: Pranit Bauva <[email protected]> Signed-off-by: Tanushree Tumane <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5e82c3d commit 0f30233

File tree

2 files changed

+106
-24
lines changed

2 files changed

+106
-24
lines changed

builtin/bisect--helper.c

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,37 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
1212
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
1313
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
1414
static GIT_PATH_FUNC(git_path_bisect_head, "BISECT_HEAD")
15+
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
1516

1617
static const char * const git_bisect_helper_usage[] = {
1718
N_("git bisect--helper --next-all [--no-checkout]"),
1819
N_("git bisect--helper --write-terms <bad_term> <good_term>"),
1920
N_("git bisect--helper --bisect-clean-state"),
2021
N_("git bisect--helper --bisect-reset [<commit>]"),
22+
N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
2123
NULL
2224
};
2325

26+
struct bisect_terms {
27+
char *term_good;
28+
char *term_bad;
29+
};
30+
31+
static void free_terms(struct bisect_terms *terms)
32+
{
33+
FREE_AND_NULL(terms->term_good);
34+
FREE_AND_NULL(terms->term_bad);
35+
}
36+
37+
static void set_terms(struct bisect_terms *terms, const char *bad,
38+
const char *good)
39+
{
40+
free((void *)terms->term_good);
41+
terms->term_good = xstrdup(good);
42+
free((void *)terms->term_bad);
43+
terms->term_bad = xstrdup(bad);
44+
}
45+
2446
/*
2547
* Check whether the string `term` belongs to the set of strings
2648
* included in the variable arguments.
@@ -148,16 +170,81 @@ static int bisect_reset(const char *commit)
148170
return bisect_clean_state();
149171
}
150172

173+
static void log_commit(FILE *fp, char *fmt, const char *state,
174+
struct commit *commit)
175+
{
176+
struct pretty_print_context pp = {0};
177+
struct strbuf commit_msg = STRBUF_INIT;
178+
char *label = xstrfmt(fmt, state);
179+
180+
format_commit_message(commit, "%s", &commit_msg, &pp);
181+
182+
fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
183+
commit_msg.buf);
184+
185+
strbuf_release(&commit_msg);
186+
free(label);
187+
}
188+
189+
static int bisect_write(const char *state, const char *rev,
190+
const struct bisect_terms *terms, int nolog)
191+
{
192+
struct strbuf tag = STRBUF_INIT;
193+
struct object_id oid;
194+
struct commit *commit;
195+
FILE *fp = NULL;
196+
int retval = 0;
197+
198+
if (!strcmp(state, terms->term_bad)) {
199+
strbuf_addf(&tag, "refs/bisect/%s", state);
200+
} else if (one_of(state, terms->term_good, "skip", NULL)) {
201+
strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
202+
} else {
203+
retval = error(_("Bad bisect_write argument: %s"), state);
204+
goto finish;
205+
}
206+
207+
if (get_oid(rev, &oid)) {
208+
retval = error(_("couldn't get the oid of the rev '%s'"), rev);
209+
goto finish;
210+
}
211+
212+
if (update_ref(NULL, tag.buf, &oid, NULL, 0,
213+
UPDATE_REFS_MSG_ON_ERR)) {
214+
retval = -1;
215+
goto finish;
216+
}
217+
218+
fp = fopen(git_path_bisect_log(), "a");
219+
if (!fp) {
220+
retval = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
221+
goto finish;
222+
}
223+
224+
commit = lookup_commit_reference(the_repository, &oid);
225+
log_commit(fp, "%s", state, commit);
226+
227+
if (!nolog)
228+
fprintf(fp, "git bisect %s %s\n", state, rev);
229+
230+
finish:
231+
if (fp)
232+
fclose(fp);
233+
strbuf_release(&tag);
234+
return retval;
235+
}
236+
151237
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
152238
{
153239
enum {
154240
NEXT_ALL = 1,
155241
WRITE_TERMS,
156242
BISECT_CLEAN_STATE,
157243
CHECK_EXPECTED_REVS,
158-
BISECT_RESET
244+
BISECT_RESET,
245+
BISECT_WRITE
159246
} cmdmode = 0;
160-
int no_checkout = 0;
247+
int no_checkout = 0, res = 0, nolog = 0;
161248
struct option options[] = {
162249
OPT_CMDMODE(0, "next-all", &cmdmode,
163250
N_("perform 'git bisect next'"), NEXT_ALL),
@@ -169,10 +256,15 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
169256
N_("check for expected revs"), CHECK_EXPECTED_REVS),
170257
OPT_CMDMODE(0, "bisect-reset", &cmdmode,
171258
N_("reset the bisection state"), BISECT_RESET),
259+
OPT_CMDMODE(0, "bisect-write", &cmdmode,
260+
N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
172261
OPT_BOOL(0, "no-checkout", &no_checkout,
173262
N_("update BISECT_HEAD instead of checking out the current commit")),
263+
OPT_BOOL(0, "no-log", &nolog,
264+
N_("no log for BISECT_WRITE ")),
174265
OPT_END()
175266
};
267+
struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
176268

177269
argc = parse_options(argc, argv, prefix, options,
178270
git_bisect_helper_usage, 0);
@@ -198,8 +290,15 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
198290
if (argc > 1)
199291
return error(_("--bisect-reset requires either no argument or a commit"));
200292
return !!bisect_reset(argc ? argv[0] : NULL);
293+
case BISECT_WRITE:
294+
if (argc != 4 && argc != 5)
295+
return error(_("--bisect-write requires either 4 or 5 arguments"));
296+
set_terms(&terms, argv[3], argv[2]);
297+
res = bisect_write(argv[0], argv[1], &terms, nolog);
298+
break;
201299
default:
202300
return error("BUG: unknown subcommand '%d'", cmdmode);
203301
}
204-
return 0;
302+
free_terms(&terms);
303+
return !!res;
205304
}

git-bisect.sh

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ bisect_start() {
144144
0) state=$TERM_BAD ; bad_seen=1 ;;
145145
*) state=$TERM_GOOD ;;
146146
esac
147-
eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
147+
eval="$eval git bisect--helper --bisect-write '$state' '$rev' '$TERM_GOOD' '$TERM_BAD' 'nolog' &&"
148148
done
149149
#
150150
# Verify HEAD.
@@ -220,23 +220,6 @@ bisect_start() {
220220
trap '-' 0
221221
}
222222

223-
bisect_write() {
224-
state="$1"
225-
rev="$2"
226-
nolog="$3"
227-
case "$state" in
228-
"$TERM_BAD")
229-
tag="$state" ;;
230-
"$TERM_GOOD"|skip)
231-
tag="$state"-"$rev" ;;
232-
*)
233-
die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
234-
esac
235-
git update-ref "refs/bisect/$tag" "$rev" || exit
236-
echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
237-
test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
238-
}
239-
240223
bisect_skip() {
241224
all=''
242225
for arg in "$@"
@@ -263,7 +246,7 @@ bisect_state() {
263246
bisected_head=$(bisect_head)
264247
rev=$(git rev-parse --verify "$bisected_head") ||
265248
die "$(eval_gettext "Bad rev input: \$bisected_head")"
266-
bisect_write "$state" "$rev"
249+
git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
267250
git bisect--helper --check-expected-revs "$rev" ;;
268251
2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
269252
shift
@@ -276,7 +259,7 @@ bisect_state() {
276259
done
277260
for rev in $hash_list
278261
do
279-
bisect_write "$state" "$rev"
262+
git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
280263
done
281264
git bisect--helper --check-expected-revs $hash_list ;;
282265
*,"$TERM_BAD")
@@ -413,7 +396,7 @@ bisect_replay () {
413396
cmd="bisect_start $rev"
414397
eval "$cmd" ;;
415398
"$TERM_GOOD"|"$TERM_BAD"|skip)
416-
bisect_write "$command" "$rev" ;;
399+
git bisect--helper --bisect-write "$command" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit;;
417400
terms)
418401
bisect_terms $rev ;;
419402
*)

0 commit comments

Comments
 (0)