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

[PATCH v2 01/15] repository: require Rust support for interoperability

From
brian m. carlson <sandals@crustytoothpaste.net>
Date
Nov 17, 2025, 22:16 UTC
Message-ID
<20251117221621.2863243-2-sandals@crustytoothpaste.net>
In-Reply-To
<20251117221621.2863243-1-sandals@crustytoothpaste.net>

We'll be implementing some of our interoperability code, like the loose object map, in Rust. While the code currently compiles with the old loose object map format, which is written entirely in C, we'll soon replace that with the Rust-based implementation.

Require the use of Rust for compatibility mode and die if it is not supported. Because the repo argument is not used when Rust is missing, cast it to void to silence the compiler warning, which we do not care about.

Add a prerequisite in our tests, RUST, that checks if Rust functionality is available and use it in the tests that handle interoperability.

This is technically a regression in functionality compared to our existing state, but pack index v3 is not yet implemented and thus the functionality is mostly quite broken, which is why we've recently marked this functionality as experimental. We don't believe anyone is getting useful use out of the interoperability code in its current state, so no actual users should be negatively impacted by this change.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 repository.c                      |  8 ++-
 t/t1006-cat-file.sh               | 82 +++++++++++++++++++++----------
 t/t1016-compatObjectFormat.sh     |  6 +++
 t/t1500-rev-parse.sh              |  2 +-
 t/t9305-fast-import-signatures.sh |  4 +-
 t/t9350-fast-export.sh            |  4 +-
 t/test-lib.sh                     |  4 ++
 7 files changed, 77 insertions(+), 33 deletions(-)
diff --git a/repository.c b/repository.c
index 6faf5c7398..186d2c1028 100644
--- a/repository.c
+++ b/repository.c
@@ -3,6 +3,7 @@
 #include "repository.h"
 #include "odb.h"
 #include "config.h"
+#include "gettext.h"
 #include "object.h"
 #include "lockfile.h"
 #include "path.h"
@@ -190,13 +191,18 @@ void repo_set_hash_algo(struct repository *repo, int hash_algo)
 	repo->hash_algo = &hash_algos[hash_algo];
 }
 
-void repo_set_compat_hash_algo(struct repository *repo, int algo)
+void repo_set_compat_hash_algo(struct repository *repo MAYBE_UNUSED, int algo)
 {
+#ifdef WITH_RUST
 	if (hash_algo_by_ptr(repo->hash_algo) == algo)
 		BUG("hash_algo and compat_hash_algo match");
 	repo->compat_hash_algo = algo ? &hash_algos[algo] : NULL;
 	if (repo->compat_hash_algo)
 		repo_read_loose_object_map(repo);
+#else
+	if (algo)
+		die(_("compatibility hash algorithm support requires Rust"));
+#endif
 }
 
 void repo_set_ref_storage_format(struct repository *repo,
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index 1f61b666a7..29a9503523 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -241,10 +241,16 @@ hello_content="Hello World"
 hello_size=$(strlen "$hello_content")
 hello_oid=$(echo_without_newline "$hello_content" | git hash-object --stdin)
 
-test_expect_success "setup" '
+test_expect_success "setup part 1" '
 	git config core.repositoryformatversion 1 &&
-	git config extensions.objectformat $test_hash_algo &&
-	git config extensions.compatobjectformat $test_compat_hash_algo &&
+	git config extensions.objectformat $test_hash_algo
+'
+
+test_expect_success RUST 'compat setup' '
+	git config extensions.compatobjectformat $test_compat_hash_algo
+'
+
+test_expect_success 'setup part 2' '
 	echo_without_newline "$hello_content" > hello &&
 	git update-index --add hello &&
 	echo_without_newline "$hello_content" > "path with spaces" &&
@@ -273,9 +279,13 @@ run_blob_tests () {
     '
 }
 
-hello_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $hello_oid)
 run_blob_tests $hello_oid
-run_blob_tests $hello_compat_oid
+
+if test_have_prereq RUST
+then
+	hello_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $hello_oid)
+	run_blob_tests $hello_compat_oid
+fi
 
 test_expect_success '--batch-check without %(rest) considers whole line' '
 	echo "$hello_oid blob $hello_size" >expect &&
@@ -286,62 +296,76 @@ test_expect_success '--batch-check without %(rest) considers whole line' '
 '
 
 tree_oid=$(git write-tree)
-tree_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tree_oid)
 tree_size=$((2 * $(test_oid rawsz) + 13 + 24))
-tree_compat_size=$((2 * $(test_oid --hash=compat rawsz) + 13 + 24))
 tree_pretty_content="100644 blob $hello_oid	hello${LF}100755 blob $hello_oid	path with spaces${LF}"
-tree_compat_pretty_content="100644 blob $hello_compat_oid	hello${LF}100755 blob $hello_compat_oid	path with spaces${LF}"
 
 run_tests 'tree' $tree_oid "" $tree_size "" "$tree_pretty_content"
-run_tests 'tree' $tree_compat_oid "" $tree_compat_size "" "$tree_compat_pretty_content"
 run_tests 'blob' "$tree_oid:hello" "100644" $hello_size "" "$hello_content" $hello_oid
-run_tests 'blob' "$tree_compat_oid:hello" "100644" $hello_size "" "$hello_content" $hello_compat_oid
 run_tests 'blob' "$tree_oid:path with spaces" "100755" $hello_size "" "$hello_content" $hello_oid
-run_tests 'blob' "$tree_compat_oid:path with spaces" "100755" $hello_size "" "$hello_content" $hello_compat_oid
+
+if test_have_prereq RUST
+then
+	tree_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tree_oid)
+	tree_compat_size=$((2 * $(test_oid --hash=compat rawsz) + 13 + 24))
+	tree_compat_pretty_content="100644 blob $hello_compat_oid	hello${LF}100755 blob $hello_compat_oid	path with spaces${LF}"
+
+	run_tests 'tree' $tree_compat_oid "" $tree_compat_size "" "$tree_compat_pretty_content"
+	run_tests 'blob' "$tree_compat_oid:hello" "100644" $hello_size "" "$hello_content" $hello_compat_oid
+	run_tests 'blob' "$tree_compat_oid:path with spaces" "100755" $hello_size "" "$hello_content" $hello_compat_oid
+fi
 
 commit_message="Initial commit"
 commit_oid=$(echo_without_newline "$commit_message" | git commit-tree $tree_oid)
-commit_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $commit_oid)
 commit_size=$(($(test_oid hexsz) + 137))
-commit_compat_size=$(($(test_oid --hash=compat hexsz) + 137))
 commit_content="tree $tree_oid
 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 
 $commit_message"
 
-commit_compat_content="tree $tree_compat_oid
+run_tests 'commit' $commit_oid "" $commit_size "$commit_content" "$commit_content"
+
+if test_have_prereq RUST
+then
+	commit_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $commit_oid)
+	commit_compat_size=$(($(test_oid --hash=compat hexsz) + 137))
+	commit_compat_content="tree $tree_compat_oid
 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 
 $commit_message"
 
-run_tests 'commit' $commit_oid "" $commit_size "$commit_content" "$commit_content"
-run_tests 'commit' $commit_compat_oid "" $commit_compat_size "$commit_compat_content" "$commit_compat_content"
+	run_tests 'commit' $commit_compat_oid "" $commit_compat_size "$commit_compat_content" "$commit_compat_content"
+fi
 
 tag_header_without_oid="type blob
 tag hellotag
 tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
 tag_header_without_timestamp="object $hello_oid
 $tag_header_without_oid"
-tag_compat_header_without_timestamp="object $hello_compat_oid
-$tag_header_without_oid"
 tag_description="This is a tag"
 tag_content="$tag_header_without_timestamp 0 +0000
 
-$tag_description"
-tag_compat_content="$tag_compat_header_without_timestamp 0 +0000
-
 $tag_description"
 
 tag_oid=$(echo_without_newline "$tag_content" | git hash-object -t tag --stdin -w)
 tag_size=$(strlen "$tag_content")
 
-tag_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tag_oid)
-tag_compat_size=$(strlen "$tag_compat_content")
-
 run_tests 'tag' $tag_oid "" $tag_size "$tag_content" "$tag_content"
-run_tests 'tag' $tag_compat_oid "" $tag_compat_size "$tag_compat_content" "$tag_compat_content"
+
+if test_have_prereq RUST
+then
+	tag_compat_header_without_timestamp="object $hello_compat_oid
+$tag_header_without_oid"
+	tag_compat_content="$tag_compat_header_without_timestamp 0 +0000
+
+$tag_description"
+
+	tag_compat_oid=$(git rev-parse --output-object-format=$test_compat_hash_algo $tag_oid)
+	tag_compat_size=$(strlen "$tag_compat_content")
+
+	run_tests 'tag' $tag_compat_oid "" $tag_compat_size "$tag_compat_content" "$tag_compat_content"
+fi
 
 test_expect_success "Reach a blob from a tag pointing to it" '
 	echo_without_newline "$hello_content" >expect &&
@@ -590,7 +614,8 @@ flush"
 }
 
 batch_tests $hello_oid $tree_oid $tree_size $commit_oid $commit_size "$commit_content" $tag_oid $tag_size "$tag_content"
-batch_tests $hello_compat_oid $tree_compat_oid $tree_compat_size $commit_compat_oid $commit_compat_size "$commit_compat_content" $tag_compat_oid $tag_compat_size "$tag_compat_content"
+
+test_have_prereq RUST && batch_tests $hello_compat_oid $tree_compat_oid $tree_compat_size $commit_compat_oid $commit_compat_size "$commit_compat_content" $tag_compat_oid $tag_compat_size "$tag_compat_content"
 
 
 test_expect_success FUNNYNAMES 'setup with newline in input' '
@@ -1226,7 +1251,10 @@ test_expect_success 'batch-check with a submodule' '
 	test_unconfig extensions.compatobjectformat &&
 	printf "160000 commit $(test_oid deadbeef)\tsub\n" >tree-with-sub &&
 	tree=$(git mktree <tree-with-sub) &&
-	test_config extensions.compatobjectformat $test_compat_hash_algo &&
+	if test_have_prereq RUST
+	then
+		test_config extensions.compatobjectformat $test_compat_hash_algo
+	fi &&
 
 	git cat-file --batch-check >actual <<-EOF &&
 	$tree:sub
diff --git a/t/t1016-compatObjectFormat.sh b/t/t1016-compatObjectFormat.sh
index 0efce53f3a..92d48b96a1 100755
--- a/t/t1016-compatObjectFormat.sh
+++ b/t/t1016-compatObjectFormat.sh
@@ -8,6 +8,12 @@ test_description='Test how well compatObjectFormat works'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-gpg.sh
 
+if ! test_have_prereq RUST
+then
+	skip_all='interoperability requires a Git built with Rust'
+	test_done
+fi
+
 # All of the follow variables must be defined in the environment:
 # GIT_AUTHOR_NAME
 # GIT_AUTHOR_EMAIL
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 7739ab611b..98c5a772bd 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -208,7 +208,7 @@ test_expect_success 'rev-parse --show-object-format in repo' '
 '
 
 
-test_expect_success 'rev-parse --show-object-format in repo with compat mode' '
+test_expect_success RUST 'rev-parse --show-object-format in repo with compat mode' '
 	mkdir repo &&
 	(
 		sane_unset GIT_DEFAULT_HASH &&
diff --git a/t/t9305-fast-import-signatures.sh b/t/t9305-fast-import-signatures.sh
index c2b4271658..63c0a2b5c4 100755
--- a/t/t9305-fast-import-signatures.sh
+++ b/t/t9305-fast-import-signatures.sh
@@ -70,7 +70,7 @@ test_expect_success GPGSSH 'strip SSH signature with --signed-commits=strip' '
 	test_must_be_empty log
 '
 
-test_expect_success GPG 'setup a commit with dual OpenPGP signatures on its SHA-1 and SHA-256 formats' '
+test_expect_success RUST,GPG 'setup a commit with dual OpenPGP signatures on its SHA-1 and SHA-256 formats' '
 	# Create a signed SHA-256 commit
 	git init --object-format=sha256 explicit-sha256 &&
 	git -C explicit-sha256 config extensions.compatObjectFormat sha1 &&
@@ -91,7 +91,7 @@ test_expect_success GPG 'setup a commit with dual OpenPGP signatures on its SHA-
 	test_grep -E "^gpgsig-sha256 " out
 '
 
-test_expect_success GPG 'strip both OpenPGP signatures with --signed-commits=warn-strip' '
+test_expect_success RUST,GPG 'strip both OpenPGP signatures with --signed-commits=warn-strip' '
 	git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output &&
 	test_grep -E "^gpgsig sha1 openpgp" output &&
 	test_grep -E "^gpgsig sha256 openpgp" output &&
diff --git a/t/t9350-fast-export.sh b/t/t9350-fast-export.sh
index 3d153a4805..784d68b6e5 100755
--- a/t/t9350-fast-export.sh
+++ b/t/t9350-fast-export.sh
@@ -972,7 +972,7 @@ test_expect_success 'fast-export handles --end-of-options' '
 	test_cmp expect actual
 '
 
-test_expect_success GPG 'setup a commit with dual signatures on its SHA-1 and SHA-256 formats' '
+test_expect_success GPG,RUST 'setup a commit with dual signatures on its SHA-1 and SHA-256 formats' '
 	# Create a signed SHA-256 commit
 	git init --object-format=sha256 explicit-sha256 &&
 	git -C explicit-sha256 config extensions.compatObjectFormat sha1 &&
@@ -993,7 +993,7 @@ test_expect_success GPG 'setup a commit with dual signatures on its SHA-1 and SH
 	test_grep -E "^gpgsig-sha256 " out
 '
 
-test_expect_success GPG 'export and import of doubly signed commit' '
+test_expect_success GPG,RUST 'export and import of doubly signed commit' '
 	git -C explicit-sha256 fast-export --signed-commits=verbatim dual-signed >output &&
 	test_grep -E "^gpgsig sha1 openpgp" output &&
 	test_grep -E "^gpgsig sha256 openpgp" output &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index ef0ab7ec2d..3499a83806 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1890,6 +1890,10 @@ test_lazy_prereq LONG_IS_64BIT '
 	test 8 -le "$(build_option sizeof-long)"
 '
 
+test_lazy_prereq RUST '
+	test "$(build_option rust)" = enabled
+'
+
 test_lazy_prereq TIME_IS_64BIT 'test-tool date is64bit'
 test_lazy_prereq TIME_T_IS_64BIT 'test-tool date time_t-is64bit'
 
Previous: brian m. carlsonNext: brian m. carlson
Message 89 of 118 in “SHA-1/SHA-256 interoperability, part 2”
  1. 00/14 SHA-1/SHA-256 interoperability, part 2brian m. carlson, Oct 27, 2025
  2. 14/14 object-file-convert: always make sure object ID algo is validbrian m. carlson, Oct 27, 2025
  3. 05/14 rust: add a hash algorithm abstractionbrian m. carlson, Oct 27, 2025
  4. Patrick SteinhardtOct 28, 2025
  5. Ezekiel NewrenOct 28, 2025
  6. Junio C HamanoOct 28, 2025
  7. Ezekiel NewrenOct 28, 2025
  8. Junio C HamanoOct 29, 2025
  9. Junio C HamanoOct 29, 2025
  10. 11/14 rust: add functionality to hash an objectbrian m. carlson, Oct 27, 2025
  11. Patrick SteinhardtOct 28, 2025
  12. brian m. carlsonOct 29, 2025
  13. Patrick SteinhardtOct 29, 2025
  14. Ezekiel NewrenOct 28, 2025
  15. brian m. carlsonOct 29, 2025
  16. Ben KnobleOct 29, 2025
  17. 07/14 csum-file: define hashwrite's count as a uint32_tbrian m. carlson, Oct 27, 2025
  18. Ezekiel NewrenOct 28, 2025
  19. 09/14 hash: expose hash context functions to Rustbrian m. carlson, Oct 27, 2025
  20. Junio C HamanoOct 29, 2025
  21. brian m. carlsonOct 30, 2025
  22. Junio C HamanoOct 30, 2025
  23. 13/14 rust: add a small wrapper around the hashfile codebrian m. carlson, Oct 27, 2025
  24. Ezekiel NewrenOct 28, 2025
  25. brian m. carlsonOct 29, 2025
  26. 06/14 hash: add a function to look up hash algo structsbrian m. carlson, Oct 27, 2025
  27. Patrick SteinhardtOct 28, 2025
  28. Junio C HamanoOct 28, 2025
  29. brian m. carlsonNov 4, 2025
  30. Junio C HamanoNov 4, 2025
  31. 10/14 rust: add a build.rs script for testsbrian m. carlson, Oct 27, 2025
  32. Patrick SteinhardtOct 28, 2025
  33. Ezekiel NewrenOct 28, 2025
  34. Junio C HamanoOct 29, 2025
  35. Ezekiel NewrenOct 29, 2025
  36. Junio C HamanoOct 29, 2025
  37. Patrick SteinhardtOct 30, 2025
  38. Junio C HamanoOct 30, 2025
  39. Ezekiel NewrenOct 31, 2025
  40. Junio C HamanoNov 1, 2025
  41. 12/14 rust: add a new binary loose object map formatbrian m. carlson, Oct 27, 2025
  42. Patrick SteinhardtOct 28, 2025
  43. brian m. carlsonOct 29, 2025
  44. Patrick SteinhardtOct 29, 2025
  45. Junio C HamanoOct 29, 2025
  46. Junio C HamanoOct 29, 2025
  47. 08/14 write-or-die: add an fsync component for the loose object mapbrian m. carlson, Oct 27, 2025
  48. 02/14 conversion: don't crash when no destination algobrian m. carlson, Oct 27, 2025
  49. 03/14 hash: use uint32_t for object_id algorithmbrian m. carlson, Oct 27, 2025
  50. Patrick SteinhardtOct 28, 2025
  51. Ezekiel NewrenOct 28, 2025
  52. Junio C HamanoOct 28, 2025
  53. Ezekiel NewrenOct 28, 2025
  54. Junio C HamanoOct 28, 2025
  55. brian m. carlsonOct 30, 2025
  56. Collin FunkOct 30, 2025
  57. brian m. carlsonNov 3, 2025
  58. brian m. carlsonOct 29, 2025
  59. Patrick SteinhardtOct 29, 2025
  60. 04/14 rust: add a ObjectID structbrian m. carlson, Oct 27, 2025
  61. Patrick SteinhardtOct 28, 2025
  62. Ezekiel NewrenOct 28, 2025
  63. brian m. carlsonOct 29, 2025
  64. Junio C HamanoOct 28, 2025
  65. brian m. carlsonOct 29, 2025
  66. brian m. carlsonOct 29, 2025
  67. Patrick SteinhardtOct 29, 2025
  68. brian m. carlsonOct 30, 2025
  69. 01/14 repository: require Rust support for interoperabilitybrian m. carlson, Oct 27, 2025
  70. Patrick SteinhardtOct 28, 2025
  71. Junio C HamanoOct 29, 2025
  72. Junio C HamanoOct 29, 2025
  73. Ezekiel NewrenNov 11, 2025
  74. Junio C HamanoNov 14, 2025
  75. Junio C HamanoNov 14, 2025
  76. Junio C HamanoNov 17, 2025
  77. brian m. carlsonNov 17, 2025
  78. Junio C HamanoNov 18, 2025
  79. brian m. carlsonNov 19, 2025
  80. Junio C HamanoNov 19, 2025
  81. Ezekiel NewrenNov 19, 2025
  82. Ezekiel NewrenNov 20, 2025
  83. brian m. carlsonNov 20, 2025
  84. Ezekiel NewrenNov 20, 2025
  85. Junio C HamanoNov 20, 2025
  86. 00/15 SHA-1/SHA-256 interoperability, part 2brian m. carlson, Nov 17, 2025
  87. 02/15 conversion: don't crash when no destination algobrian m. carlson, Nov 17, 2025
  88. 03/15 hash: use uint32_t for object_id algorithmbrian m. carlson, Nov 17, 2025
  89. 01/15 repository: require Rust support for interoperabilitybrian m. carlson, Nov 17, 2025
  90. 04/15 rust: add a ObjectID structbrian m. carlson, Nov 17, 2025
  91. 06/15 hash: add a function to look up hash algo structsbrian m. carlson, Nov 17, 2025
  92. 08/15 csum-file: define hashwrite's count as a uint32_tbrian m. carlson, Nov 17, 2025
  93. 05/15 rust: add a hash algorithm abstractionbrian m. carlson, Nov 17, 2025
  94. 09/15 write-or-die: add an fsync component for the object mapbrian m. carlson, Nov 17, 2025
  95. 10/15 hash: expose hash context functions to Rustbrian m. carlson, Nov 17, 2025
  96. 07/15 rust: add additional helpers for ObjectIDbrian m. carlson, Nov 17, 2025
  97. 12/15 rust: add functionality to hash an objectbrian m. carlson, Nov 17, 2025
  98. 11/15 rust: add a build.rs script for testsbrian m. carlson, Nov 17, 2025
  99. 14/15 rust: add a small wrapper around the hashfile codebrian m. carlson, Nov 17, 2025
  100. 15/15 object-file-convert: always make sure object ID algo is validbrian m. carlson, Nov 17, 2025
  101. 13/15 rust: add a new binary object map formatbrian m. carlson, Nov 17, 2025
  102. 00/16 SHA-1/SHA-256 interoperability, part 2brian m. carlson, Feb 7, 2026
  103. 04/16 rust: add a ObjectID structbrian m. carlson, Feb 7, 2026
  104. 02/16 conversion: don't crash when no destination algobrian m. carlson, Feb 7, 2026
  105. 01/16 repository: require Rust support for interoperabilitybrian m. carlson, Feb 7, 2026
  106. 03/16 hash: use uint32_t for object_id algorithmbrian m. carlson, Feb 7, 2026
  107. 07/16 rust: add additional helpers for ObjectIDbrian m. carlson, Feb 7, 2026
  108. 14/16 rust: add a new binary object map formatbrian m. carlson, Feb 7, 2026
  109. 08/16 csum-file: define hashwrite's count as a uint32_tbrian m. carlson, Feb 7, 2026
  110. 06/16 hash: add a function to look up hash algo structsbrian m. carlson, Feb 7, 2026
  111. 11/16 rust: fix linking binaries with cargobrian m. carlson, Feb 7, 2026
  112. 12/16 rust: add a build.rs script for testsbrian m. carlson, Feb 7, 2026
  113. 10/16 hash: expose hash context functions to Rustbrian m. carlson, Feb 7, 2026
  114. 05/16 rust: add a hash algorithm abstractionbrian m. carlson, Feb 7, 2026
  115. 09/16 write-or-die: add an fsync component for the object mapbrian m. carlson, Feb 7, 2026
  116. 13/16 rust: add functionality to hash an objectbrian m. carlson, Feb 7, 2026
  117. 15/16 rust: add a small wrapper around the hashfile codebrian m. carlson, Feb 7, 2026
  118. 16/16 object-file-convert: always make sure object ID algo is validbrian m. carlson, Feb 7, 2026

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.