git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v17 2/7] bisect--helper: `bisect_write` shell function in C

From
Pranit Bauva via GitGitGadget <gitgitgadget@gmail.com>
Date
Jan 2, 2019, 15:38 UTC
Message-ID
<7d6291d9dda2531646b2a64941338adb98f60dee.1546443509.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.101.v17.git.gitgitgadget@gmail.com>
From: Pranit Bauva <pranit.bauva@gmail.com>

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 <ramsay@ramsayjones.plus.com>
Mentored-by: Lars Schneider <larsxschneider@gmail.com>
Mentored-by: Christian Couder <chriscool@tuxfamily.org>
Mentored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Pranit Bauva <pranit.bauva@gmail.com>
Signed-off-by: Tanushree Tumane <tanushreetumane@gmail.com>
---
 builtin/bisect--helper.c | 105 +++++++++++++++++++++++++++++++++++++--
 git-bisect.sh            |  25 ++--------
 2 files changed, 106 insertions(+), 24 deletions(-)
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index aa6495dc84..df821be4b2 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -12,15 +12,37 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
 static GIT_PATH_FUNC(git_path_bisect_head, "BISECT_HEAD")
+static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
 
 static const char * const git_bisect_helper_usage[] = {
 	N_("git bisect--helper --next-all [--no-checkout]"),
 	N_("git bisect--helper --write-terms <bad_term> <good_term>"),
 	N_("git bisect--helper --bisect-clean-state"),
 	N_("git bisect--helper --bisect-reset [<commit>]"),
+	N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
 	NULL
 };
 
+struct bisect_terms {
+	char *term_good;
+	char *term_bad;
+};
+
+static void free_terms(struct bisect_terms *terms)
+{
+	FREE_AND_NULL(terms->term_good);
+	FREE_AND_NULL(terms->term_bad);
+}
+
+static void set_terms(struct bisect_terms *terms, const char *bad,
+		      const char *good)
+{
+	free((void *)terms->term_good);
+	terms->term_good = xstrdup(good);
+	free((void *)terms->term_bad);
+	terms->term_bad = xstrdup(bad);
+}
+
 /*
  * Check whether the string `term` belongs to the set of strings
  * included in the variable arguments.
@@ -148,6 +170,70 @@ static int bisect_reset(const char *commit)
 	return bisect_clean_state();
 }
 
+static void log_commit(FILE *fp, char *fmt, const char *state,
+		       struct commit *commit)
+{
+	struct pretty_print_context pp = {0};
+	struct strbuf commit_msg = STRBUF_INIT;
+	char *label = xstrfmt(fmt, state);
+
+	format_commit_message(commit, "%s", &commit_msg, &pp);
+
+	fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
+		commit_msg.buf);
+
+	strbuf_release(&commit_msg);
+	free(label);
+}
+
+static int bisect_write(const char *state, const char *rev,
+			const struct bisect_terms *terms, int nolog)
+{
+	struct strbuf tag = STRBUF_INIT;
+	struct object_id oid;
+	struct commit *commit;
+	FILE *fp = NULL;
+	int retval = 0;
+
+	if (!strcmp(state, terms->term_bad)) {
+		strbuf_addf(&tag, "refs/bisect/%s", state);
+	} else if (one_of(state, terms->term_good, "skip", NULL)) {
+		strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
+	} else {
+		retval = error(_("Bad bisect_write argument: %s"), state);
+		goto finish;
+	}
+
+	if (get_oid(rev, &oid)) {
+		retval = error(_("couldn't get the oid of the rev '%s'"), rev);
+		goto finish;
+	}
+
+	if (update_ref(NULL, tag.buf, &oid, NULL, 0,
+		       UPDATE_REFS_MSG_ON_ERR)) {
+		retval = -1;
+		goto finish;
+	}
+
+	fp = fopen(git_path_bisect_log(), "a");
+	if (!fp) {
+		retval = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
+		goto finish;
+	}
+
+	commit = lookup_commit_reference(the_repository, &oid);
+	log_commit(fp, "%s", state, commit);
+
+	if (!nolog)
+		fprintf(fp, "git bisect %s %s\n", state, rev);
+
+finish:
+	if (fp)
+		fclose(fp);
+	strbuf_release(&tag);
+	return retval;
+}
+
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
 	enum {
@@ -155,9 +241,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		WRITE_TERMS,
 		BISECT_CLEAN_STATE,
 		CHECK_EXPECTED_REVS,
-		BISECT_RESET
+		BISECT_RESET,
+		BISECT_WRITE
 	} cmdmode = 0;
-	int no_checkout = 0;
+	int no_checkout = 0, res = 0, nolog = 0;
 	struct option options[] = {
 		OPT_CMDMODE(0, "next-all", &cmdmode,
 			 N_("perform 'git bisect next'"), NEXT_ALL),
@@ -169,10 +256,15 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 			 N_("check for expected revs"), CHECK_EXPECTED_REVS),
 		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
 			 N_("reset the bisection state"), BISECT_RESET),
+		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_BOOL(0, "no-log", &nolog,
+			 N_("no log for BISECT_WRITE ")),
 		OPT_END()
 	};
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
 
 	argc = parse_options(argc, argv, prefix, options,
 			     git_bisect_helper_usage, 0);
@@ -198,8 +290,15 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 		if (argc > 1)
 			return error(_("--bisect-reset requires either no argument or a commit"));
 		return !!bisect_reset(argc ? argv[0] : NULL);
+	case BISECT_WRITE:
+		if (argc != 4 && argc != 5)
+			return error(_("--bisect-write requires either 4 or 5 arguments"));
+		set_terms(&terms, argv[3], argv[2]);
+		res = bisect_write(argv[0], argv[1], &terms, nolog);
+		break;
 	default:
 		return error("BUG: unknown subcommand '%d'", cmdmode);
 	}
-	return 0;
+	free_terms(&terms);
+	return !!res;
 }
diff --git a/git-bisect.sh b/git-bisect.sh
index afbfbc1f8e..ebf445223c 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -144,7 +144,7 @@ bisect_start() {
 		0) state=$TERM_BAD ; bad_seen=1 ;;
 		*) state=$TERM_GOOD ;;
 		esac
-		eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
+		eval="$eval git bisect--helper --bisect-write '$state' '$rev' '$TERM_GOOD' '$TERM_BAD' 'nolog' &&"
 	done
 	#
 	# Verify HEAD.
@@ -220,23 +220,6 @@ bisect_start() {
 	trap '-' 0
 }
 
-bisect_write() {
-	state="$1"
-	rev="$2"
-	nolog="$3"
-	case "$state" in
-		"$TERM_BAD")
-			tag="$state" ;;
-		"$TERM_GOOD"|skip)
-			tag="$state"-"$rev" ;;
-		*)
-			die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
-	esac
-	git update-ref "refs/bisect/$tag" "$rev" || exit
-	echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
-	test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
-}
-
 bisect_skip() {
 	all=''
 	for arg in "$@"
@@ -263,7 +246,7 @@ bisect_state() {
 		bisected_head=$(bisect_head)
 		rev=$(git rev-parse --verify "$bisected_head") ||
 			die "$(eval_gettext "Bad rev input: \$bisected_head")"
-		bisect_write "$state" "$rev"
+		git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
 		git bisect--helper --check-expected-revs "$rev" ;;
 	2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip)
 		shift
@@ -276,7 +259,7 @@ bisect_state() {
 		done
 		for rev in $hash_list
 		do
-			bisect_write "$state" "$rev"
+			git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit
 		done
 		git bisect--helper --check-expected-revs $hash_list ;;
 	*,"$TERM_BAD")
@@ -413,7 +396,7 @@ bisect_replay () {
 			cmd="bisect_start $rev"
 			eval "$cmd" ;;
 		"$TERM_GOOD"|"$TERM_BAD"|skip)
-			bisect_write "$command" "$rev" ;;
+			git bisect--helper --bisect-write "$command" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit;;
 		terms)
 			bisect_terms $rev ;;
 		*)
-- 
gitgitgadget
Previous: Pranit Bauva via GitGitGadgetNext: Pranit Bauva via GitGitGadget
Message 43 of 50 in “bisect--helper: `bisect_reset` shell function in C”
  1. 1/8 bisect--helper: `bisect_reset` shell function in CPranit Bauva, Oct 27, 2017
  2. 7/8 bisect--helper: `bisect_start` shell function partially in CPranit Bauva, Oct 27, 2017
  3. Stephan BeyerOct 30, 2017
  4. Pranit BauvaOct 30, 2017
  5. SZEDER GáborFeb 16, 2018
  6. 2/8 bisect--helper: `bisect_write` shell function in CPranit Bauva, Oct 27, 2017
  7. Martin ÅgrenOct 27, 2017
  8. Pranit BauvaOct 30, 2017
  9. Johannes SchindelinNov 23, 2018
  10. Martin ÅgrenNov 23, 2018
  11. Johannes SchindelinNov 26, 2018
  12. Junio C HamanoOct 27, 2017
  13. Pranit BauvaOct 30, 2017
  14. Stephan BeyerOct 30, 2017
  15. Stephan BeyerOct 30, 2017
  16. Ramsay JonesNov 8, 2017
  17. 3/8 wrapper: move is_empty_file() and rename it as is_empty_or_missing_file()Pranit Bauva, Oct 27, 2017
  18. 5/8 bisect--helper: `bisect_next_check` shell function in CPranit Bauva, Oct 27, 2017
  19. Martin ÅgrenOct 27, 2017
  20. Pranit BauvaOct 30, 2017
  21. Ramsay JonesNov 8, 2017
  22. Stephan BeyerNov 12, 2017
  23. Stephan BeyerNov 12, 2017
  24. Stephan BeyerNov 12, 2017
  25. Junio C HamanoNov 13, 2017
  26. 8/8 t6030: make various test to pass GETTEXT_POISON testsPranit Bauva, Oct 27, 2017
  27. 4/8 bisect--helper: `check_and_set_terms` shell function in CPranit Bauva, Oct 27, 2017
  28. Ramsay JonesNov 8, 2017
  29. 6/8 bisect--helper: `get_terms` & `bisect_terms` shell function in CPranit Bauva, Oct 27, 2017
  30. Martin ÅgrenOct 27, 2017
  31. Pranit BauvaOct 30, 2017
  32. Stephan BeyerOct 30, 2017
  33. Pranit BauvaOct 30, 2017
  34. Ramsay JonesNov 8, 2017
  35. Pranit BauvaOct 27, 2017
  36. Junio C HamanoOct 27, 2017
  37. Pranit BauvaOct 30, 2017
  38. Stephan BeyerOct 30, 2017
  39. Pranit BauvaOct 30, 2017
  40. Ramsay JonesNov 8, 2017
  41. 0/7 git bisect: convert from shell to CTanushree Tumane via GitGitGadget, Jan 2, 2019
  42. 1/7 bisect--helper: `bisect_reset` shell function in CPranit Bauva via GitGitGadget, Jan 2, 2019
  43. 2/7 bisect--helper: `bisect_write` shell function in CPranit Bauva via GitGitGadget, Jan 2, 2019
  44. 4/7 bisect--helper: `check_and_set_terms` shell function in CPranit Bauva via GitGitGadget, Jan 2, 2019
  45. 5/7 bisect--helper: `bisect_next_check` shell function in CPranit Bauva via GitGitGadget, Jan 2, 2019
  46. 7/7 bisect--helper: `bisect_start` shell function partially in CPranit Bauva via GitGitGadget, Jan 2, 2019
  47. 3/7 wrapper: move is_empty_file() and rename it as is_empty_or_missing_file()Pranit Bauva via GitGitGadget, Jan 2, 2019
  48. 6/7 bisect--helper: `get_terms` & `bisect_terms` shell function in CPranit Bauva via GitGitGadget, Jan 2, 2019
  49. Ramsay JonesJan 3, 2019
  50. TANUSHREE TUMANEJan 7, 2019

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.