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

Re: "git bisect run" strips "--log" from the list of arguments

From
Đoàn Trần Công Danh <congdanhqx@gmail.com>
Date
Nov 4, 2022, 11:10 UTC
Message-ID
<Y2Ty6KZT8iACqHf+@danh.dev>
In-Reply-To
<Y2TfUFkLUa2tHdS7@coredump.intra.peff.net>
On 2022-11-04 05:45:52-0400, Jeff King <peff@peff.net> wrote:
Show 41 quoted lines
> On Fri, Nov 04, 2022 at 07:31:26AM +0100, Lukáš Doktor wrote:
> 
> > Steps to Reproduce:
> > 
> > 1. git bisect start BAD GOOD
> > 2. git bisect run ./myscript arg1 --log arg2 --log -- arg3 --log arg4
> > 
> > Results with 2.34.1:
> > 
> >     running  './myscript' 'arg1' 'arg2' '--' 'arg3' '--log' 'arg4'
> > 
> > Results with 2.33.0:
> > 
> >     running ./myscript arg1 --log arg2 --log -- arg3 --log arg4
> 
> Thanks for an easy reproduction recipe. I used this as an easy-to-see
> test case, which works in any repo:
> 
>   git bisect start HEAD HEAD~2 >/dev/null 2>&1
>   git bisect bisect run echo --log 2>&1 | grep running
> 
> > Is this expected? In https://bugzilla.redhat.com/show_bug.cgi?id=2139883 Todd suggested it might be related to
> > 
> >     d1bbbe45df (bisect--helper: reimplement `bisect_run` shell function in C, 2021-09-13) 
> > 
> > but I haven't tried it myself.
> 
> Yes, it bisects to that commit. +cc Christian, who mentored this gsoc
> project.
> 
> I think the problem is that we are now feeding the arguments to
> parse_options() in git bisect--helper, and it doesn't realize that it
> needs to stop after seeing that we are in "run" mode.  And because
> "--log" is an option to git-bisect--helper (it is the opposite of
> "--no-log"), it is consumed there.
> 
> As you noticed, the "--" stops parsing, so the one between "arg3" and
> "arg4" is preserved.
> 
> It feels like the invocation of bisect--helper ought to be passing "--"
> itself to indicate the end of options, like:

I think we should use OPT_SUBCOMMAND to parse bisect--helper subcommand instead, which would pave ways for easier converting to built-int git-bisect. This huge patch, which could be splited into 2 patches can fix the problem: ---- 8< ----

diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c
index 1d2ce8a0e1..fe8aea7240 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect--helper.c
@@ -1279,115 +1279,119 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
 	return res;
 }
 
+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
+{
+	if (argc > 1)
+		return error(_("--bisect-reset requires either no argument or a commit"));
+	return bisect_reset(argc ? argv[0] : NULL);
+}
+
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc > 1)
+		return error(_("--bisect-terms requires 0 or 1 argument"));
+	return bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+}
+
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	return bisect_start(&terms, argv, argc);
+}
+
+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc)
+		return error(_("--bisect-next requires 0 arguments"));
+	get_terms(&terms);
+	return bisect_next(&terms, prefix);
+}
+
+static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	return bisect_state(&terms, argv, argc);
+}
+
+static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+{
+	if (argc)
+		return error(_("--bisect-log requires 0 arguments"));
+	return bisect_log();
+}
+
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (argc != 1)
+		return error(_("no logfile given"));
+	set_terms(&terms, "bad", "good");
+	return bisect_replay(&terms, argv[0]);
+}
+
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	return bisect_skip(&terms, argv, argc);
+}
+
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	get_terms(&terms);
+	return bisect_visualize(&terms, argv, argc);
+}
+
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED)
+{
+	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
+
+	if (!argc)
+		return error(_("bisect run failed: no command provided."));
+	get_terms(&terms);
+	return bisect_run(&terms, argv, argc);
+}
+
 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
 {
-	enum {
-		BISECT_RESET = 1,
-		BISECT_NEXT_CHECK,
-		BISECT_TERMS,
-		BISECT_START,
-		BISECT_AUTOSTART,
-		BISECT_NEXT,
-		BISECT_STATE,
-		BISECT_LOG,
-		BISECT_REPLAY,
-		BISECT_SKIP,
-		BISECT_VISUALIZE,
-		BISECT_RUN,
-	} cmdmode = 0;
-	int res = 0, nolog = 0;
+	int res = 0;
+	parse_opt_subcommand_fn *fn = NULL;
 	struct option options[] = {
-		OPT_CMDMODE(0, "bisect-reset", &cmdmode,
-			 N_("reset the bisection state"), BISECT_RESET),
-		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_CMDMODE(0, "bisect-start", &cmdmode,
-			 N_("start the bisect session"), BISECT_START),
-		OPT_CMDMODE(0, "bisect-next", &cmdmode,
-			 N_("find the next bisection commit"), BISECT_NEXT),
-		OPT_CMDMODE(0, "bisect-state", &cmdmode,
-			 N_("mark the state of ref (or refs)"), BISECT_STATE),
-		OPT_CMDMODE(0, "bisect-log", &cmdmode,
-			 N_("list the bisection steps so far"), BISECT_LOG),
-		OPT_CMDMODE(0, "bisect-replay", &cmdmode,
-			 N_("replay the bisection process from the given file"), BISECT_REPLAY),
-		OPT_CMDMODE(0, "bisect-skip", &cmdmode,
-			 N_("skip some commits for checkout"), BISECT_SKIP),
-		OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
-			 N_("visualize the bisection"), BISECT_VISUALIZE),
-		OPT_CMDMODE(0, "bisect-run", &cmdmode,
-			 N_("use <cmd>... to automatically bisect"), BISECT_RUN),
-		OPT_BOOL(0, "no-log", &nolog,
-			 N_("no log for BISECT_WRITE")),
+		OPT_SUBCOMMAND("bisect-reset", &fn, cmd_bisect__reset),
+		OPT_SUBCOMMAND("bisect-terms", &fn, cmd_bisect__terms),
+		OPT_SUBCOMMAND("bisect-start", &fn, cmd_bisect__start),
+		OPT_SUBCOMMAND("bisect-next", &fn, cmd_bisect__next),
+		OPT_SUBCOMMAND("bisect-state", &fn, cmd_bisect__state),
+		OPT_SUBCOMMAND("bisect-log", &fn, cmd_bisect__log),
+		OPT_SUBCOMMAND("bisect-replay", &fn, cmd_bisect__replay),
+		OPT_SUBCOMMAND("bisect-skip", &fn, cmd_bisect__skip),
+		OPT_SUBCOMMAND("bisect-visualize", &fn, cmd_bisect__visualize),
+		OPT_SUBCOMMAND("bisect-run", &fn, cmd_bisect__run),
 		OPT_END()
 	};
-	struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
-
 	argc = parse_options(argc, argv, prefix, options,
-			     git_bisect_helper_usage,
-			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN_OPT);
+			     git_bisect_helper_usage, 0);
 
-	if (!cmdmode)
+	if (!fn)
 		usage_with_options(git_bisect_helper_usage, options);
+	argc--;
+	argv++;
 
-	switch (cmdmode) {
-	case BISECT_RESET:
-		if (argc > 1)
-			return error(_("--bisect-reset requires either no argument or a commit"));
-		res = bisect_reset(argc ? argv[0] : NULL);
-		break;
-	case BISECT_TERMS:
-		if (argc > 1)
-			return error(_("--bisect-terms requires 0 or 1 argument"));
-		res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
-		break;
-	case BISECT_START:
-		set_terms(&terms, "bad", "good");
-		res = bisect_start(&terms, argv, argc);
-		break;
-	case BISECT_NEXT:
-		if (argc)
-			return error(_("--bisect-next requires 0 arguments"));
-		get_terms(&terms);
-		res = bisect_next(&terms, prefix);
-		break;
-	case BISECT_STATE:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_state(&terms, argv, argc);
-		break;
-	case BISECT_LOG:
-		if (argc)
-			return error(_("--bisect-log requires 0 arguments"));
-		res = bisect_log();
-		break;
-	case BISECT_REPLAY:
-		if (argc != 1)
-			return error(_("no logfile given"));
-		set_terms(&terms, "bad", "good");
-		res = bisect_replay(&terms, argv[0]);
-		break;
-	case BISECT_SKIP:
-		set_terms(&terms, "bad", "good");
-		get_terms(&terms);
-		res = bisect_skip(&terms, argv, argc);
-		break;
-	case BISECT_VISUALIZE:
-		get_terms(&terms);
-		res = bisect_visualize(&terms, argv, argc);
-		break;
-	case BISECT_RUN:
-		if (!argc)
-			return error(_("bisect run failed: no command provided."));
-		get_terms(&terms);
-		res = bisect_run(&terms, argv, argc);
-		break;
-	default:
-		BUG("unknown subcommand %d", cmdmode);
-	}
-	free_terms(&terms);
+	res = fn(argc, argv, prefix);
 
 	/*
 	 * Handle early success
diff --git a/git-bisect.sh b/git-bisect.sh
index 405cf76f2a..07a7257be4 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -58,26 +58,26 @@ case "$#" in
 	help)
 		git bisect -h ;;
 	start)
-		git bisect--helper --bisect-start "$@" ;;
+		git bisect--helper bisect-start "$@" ;;
 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
-		git bisect--helper --bisect-state "$cmd" "$@" ;;
+		git bisect--helper bisect-state "$cmd" "$@" ;;
 	skip)
-		git bisect--helper --bisect-skip "$@" || exit;;
+		git bisect--helper bisect-skip "$@" || exit;;
 	next)
 		# Not sure we want "next" at the UI level anymore.
-		git bisect--helper --bisect-next "$@" || exit ;;
+		git bisect--helper bisect-next "$@" || exit ;;
 	visualize|view)
-		git bisect--helper --bisect-visualize "$@" || exit;;
+		git bisect--helper bisect-visualize "$@" || exit;;
 	reset)
-		git bisect--helper --bisect-reset "$@" ;;
+		git bisect--helper bisect-reset "$@" ;;
 	replay)
-		git bisect--helper --bisect-replay "$@" || exit;;
+		git bisect--helper bisect-replay "$@" || exit;;
 	log)
-		git bisect--helper --bisect-log || exit ;;
+		git bisect--helper bisect-log || exit ;;
 	run)
-		git bisect--helper --bisect-run "$@" || exit;;
+		git bisect--helper bisect-run "$@" || exit;;
 	terms)
-		git bisect--helper --bisect-terms "$@" || exit;;
+		git bisect--helper bisect-terms "$@" || exit;;
 	*)
 		usage ;;
 	esac
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 83931d482f..e957772b05 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -266,6 +266,17 @@ test_expect_success '"git bisect run" simple case' '
 	git bisect reset
 '
 
+# We want to automatically find the commit that
+# added "Another" into hello. We also want to make sure --log is not eaten
+test_expect_success '"git bisect run" simple case' '
+	git bisect start &&
+	git bisect good $HASH1 &&
+	git bisect bad $HASH4 &&
+	git bisect run printf "%s\n" --log >my_bisect_log.txt &&
+	grep -e --log my_bisect_log.txt &&
+	git bisect reset
+'
+
 # We want to automatically find the commit that
 # added "Ciao" into hello.
 test_expect_success '"git bisect run" with more complex "git bisect start"' '
----- >8 -----

I can turn this into 2 patches series if you thinks this is the right
direction.
-- 
Danh
Previous: Jeff KingNext: Jeff King
Message 3 of 106 in “"git bisect run" strips "--log" from the list of arguments”
  1. Lukáš DoktorNov 4, 2022
  2. Jeff KingNov 4, 2022
  3. Đoàn Trần Công DanhNov 4, 2022
  4. Jeff KingNov 4, 2022
  5. Ævar Arnfjörð BjarmasonNov 4, 2022
  6. Jeff KingNov 4, 2022
  7. Ævar Arnfjörð BjarmasonNov 4, 2022
  8. SZEDER GáborNov 4, 2022
  9. Jeff KingNov 4, 2022
  10. 0/3 Convert git-bisect--helper to OPT_SUBCOMMANDĐoàn Trần Công Danh, Nov 4, 2022
  11. 1/3 bisect--helper: remove unused optionsĐoàn Trần Công Danh, Nov 4, 2022
  12. Jeff KingNov 4, 2022
  13. 2/3 bisect--helper: move all subcommands into their own functionsĐoàn Trần Công Danh, Nov 4, 2022
  14. Jeff KingNov 4, 2022
  15. Ævar Arnfjörð BjarmasonNov 4, 2022
  16. Đoàn Trần Công DanhNov 4, 2022
  17. 3/3 bisect--helper: parse subcommand with OPT_SUBCOMMANDĐoàn Trần Công Danh, Nov 4, 2022
  18. Jeff KingNov 4, 2022
  19. Ævar Arnfjörð BjarmasonNov 4, 2022
  20. Đoàn Trần Công DanhNov 4, 2022
  21. Ævar Arnfjörð BjarmasonNov 4, 2022
  22. 0/3 Convert git-bisect--helper to OPT_SUBCOMMANDĐoàn Trần Công Danh, Nov 5, 2022
  23. 1/3 bisect--helper: remove unused optionsĐoàn Trần Công Danh, Nov 5, 2022
  24. 3/3 bisect--helper: parse subcommand with OPT_SUBCOMMANDĐoàn Trần Công Danh, Nov 5, 2022
  25. 2/3 bisect--helper: move all subcommands into their own functionsĐoàn Trần Công Danh, Nov 5, 2022
  26. Đoàn Trần Công DanhNov 5, 2022
  27. 00/13 Turn git-bisect to be builtinĐoàn Trần Công Danh, Nov 5, 2022
  28. 01/13 bisect tests: test for v2.30.0 "bisect run" regressionsĐoàn Trần Công Danh, Nov 5, 2022
  29. Ævar Arnfjörð BjarmasonNov 7, 2022
  30. Đoàn Trần Công DanhNov 8, 2022
  31. 02/13 bisect: refactor bisect_run() to match CodingGuidelinesĐoàn Trần Công Danh, Nov 5, 2022
  32. 03/13 bisect--helper: pass arg[cv] down to do_bisect_runĐoàn Trần Công Danh, Nov 5, 2022
  33. 04/13 bisect: fix output regressions in v2.30.0Đoàn Trần Công Danh, Nov 5, 2022
  34. 05/13 bisect run: keep some of the post-v2.30.0 outputĐoàn Trần Công Danh, Nov 5, 2022
  35. Ævar Arnfjörð BjarmasonNov 7, 2022
  36. Đoàn Trần Công DanhNov 8, 2022
  37. Ævar Arnfjörð BjarmasonNov 8, 2022
  38. 06/13 bisect--helper: remove unused arguments from do_bisect_runĐoàn Trần Công Danh, Nov 5, 2022
  39. 07/13 bisect--helper: pretend we're real bisect when report errorĐoàn Trần Công Danh, Nov 5, 2022
  40. Ævar Arnfjörð BjarmasonNov 7, 2022
  41. 08/13 bisect test: test exit codes on bad usageĐoàn Trần Công Danh, Nov 5, 2022
  42. 09/13 bisect--helper: emit usage for "git bisect"Đoàn Trần Công Danh, Nov 5, 2022
  43. 10/13 bisect--helper: make `state` optionalĐoàn Trần Công Danh, Nov 5, 2022
  44. 11/13 bisect--helper: remove subcommand stateĐoàn Trần Công Danh, Nov 5, 2022
  45. Ævar Arnfjörð BjarmasonNov 7, 2022
  46. Đoàn Trần Công DanhNov 8, 2022
  47. 12/13 bisect--helper: log: allow arbitrary number of argumentsĐoàn Trần Công Danh, Nov 5, 2022
  48. 13/13 Turn `git bisect` into a full built-inĐoàn Trần Công Danh, Nov 5, 2022
  49. Taylor BlauNov 5, 2022
  50. 0/3 Convert git-bisect--helper to OPT_SUBCOMMANDĐoàn Trần Công Danh, Nov 10, 2022
  51. 1/3 bisect--helper: remove unused optionsĐoàn Trần Công Danh, Nov 10, 2022
  52. Ævar Arnfjörð BjarmasonNov 11, 2022
  53. 2/3 bisect--helper: move all subcommands into their own functionsĐoàn Trần Công Danh, Nov 10, 2022
  54. Ævar Arnfjörð BjarmasonNov 11, 2022
  55. 3/3 bisect--helper: parse subcommand with OPT_SUBCOMMANDĐoàn Trần Công Danh, Nov 10, 2022
  56. 00/11 Turn git-bisect to be builtinĐoàn Trần Công Danh, Nov 10, 2022
  57. 02/11 bisect: refactor bisect_run() to match CodingGuidelinesĐoàn Trần Công Danh, Nov 10, 2022
  58. 01/11 bisect tests: test for v2.30.0 "bisect run" regressionsĐoàn Trần Công Danh, Nov 10, 2022
  59. 03/11 bisect: fix output regressions in v2.30.0Đoàn Trần Công Danh, Nov 10, 2022
  60. 04/11 bisect run: keep some of the post-v2.30.0 outputĐoàn Trần Công Danh, Nov 10, 2022
  61. 05/11 bisect-run: verify_good: account for non-negative exit statusĐoàn Trần Công Danh, Nov 10, 2022
  62. 06/11 bisect--helper: identify as bisect when report errorĐoàn Trần Công Danh, Nov 10, 2022
  63. 07/11 bisect test: test exit codes on bad usageĐoàn Trần Công Danh, Nov 10, 2022
  64. 08/11 bisect--helper: emit usage for "git bisect"Đoàn Trần Công Danh, Nov 10, 2022
  65. 09/11 bisect--helper: handle states directlyĐoàn Trần Công Danh, Nov 10, 2022
  66. 10/11 bisect--helper: log: allow arbitrary number of argumentsĐoàn Trần Công Danh, Nov 10, 2022
  67. Ævar Arnfjörð BjarmasonNov 11, 2022
  68. 11/11 Turn `git bisect` into a full built-inĐoàn Trần Công Danh, Nov 10, 2022
  69. Ævar Arnfjörð BjarmasonNov 11, 2022
  70. Jeff KingNov 11, 2022
  71. Ævar Arnfjörð BjarmasonNov 11, 2022
  72. Taylor BlauNov 11, 2022
  73. Taylor BlauNov 15, 2022
  74. Jeff KingNov 15, 2022
  75. Taylor BlauNov 15, 2022
  76. Ævar Arnfjörð BjarmasonNov 11, 2022
  77. 00/13 bisect: v2.30.0 "run" regressions + make it built-inÆvar Arnfjörð Bjarmason, Nov 4, 2022
  78. 01/13 bisect tests: test for v2.30.0 "bisect run" regressionsÆvar Arnfjörð Bjarmason, Nov 4, 2022
  79. 02/13 bisect: refactor bisect_run() to match CodingGuidelinesÆvar Arnfjörð Bjarmason, Nov 4, 2022
  80. 04/13 bisect run: fix "--log" eating regression in v2.30.0Ævar Arnfjörð Bjarmason, Nov 4, 2022
  81. 03/13 bisect: fix output regressions in v2.30.0Ævar Arnfjörð Bjarmason, Nov 4, 2022
  82. 05/13 bisect run: keep some of the post-v2.30.0 outputÆvar Arnfjörð Bjarmason, Nov 4, 2022
  83. 06/13 bisect test: test exit codes on bad usageÆvar Arnfjörð Bjarmason, Nov 4, 2022
  84. 07/13 bisect--helper: emit usage for "git bisect"Ævar Arnfjörð Bjarmason, Nov 4, 2022
  85. 09/13 parse-options API: don't restrict OPT_SUBCOMMAND() to one *_fn typeÆvar Arnfjörð Bjarmason, Nov 4, 2022
  86. René ScharfeNov 5, 2022
  87. Đoàn Trần Công DanhNov 5, 2022
  88. Phillip WoodNov 5, 2022
  89. Ævar Arnfjörð BjarmasonNov 5, 2022
  90. Phillip WoodNov 5, 2022
  91. Ævar Arnfjörð BjarmasonNov 5, 2022
  92. René ScharfeNov 5, 2022
  93. Ævar Arnfjörð BjarmasonNov 5, 2022
  94. René ScharfeNov 6, 2022
  95. Ævar Arnfjörð BjarmasonNov 6, 2022
  96. René ScharfeNov 12, 2022
  97. Jeff KingNov 12, 2022
  98. Ævar Arnfjörð BjarmasonNov 12, 2022
  99. René ScharfeNov 13, 2022
  100. 08/13 bisect--helper: have all functions take state, argc, argv, prefixÆvar Arnfjörð Bjarmason, Nov 4, 2022
  101. 10/13 bisect--helper: remove dead --bisect-{next-check,autostart} codeÆvar Arnfjörð Bjarmason, Nov 4, 2022
  102. 11/13 bisect--helper: convert to OPT_SUBCOMMAND_CB()Ævar Arnfjörð Bjarmason, Nov 4, 2022
  103. 12/13 bisect--helper: make `state` optionalÆvar Arnfjörð Bjarmason, Nov 4, 2022
  104. 13/13 Turn `git bisect` into a full built-inÆvar Arnfjörð Bjarmason, Nov 4, 2022
  105. Taylor BlauNov 5, 2022
  106. Johannes SchindelinNov 10, 2022

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.