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

[PATCH v2 1/3] builtin/grep: read submodule trees via their repository

From
Patrick Steinhardt <ps@pks.im>
Date
Nov 3, 2026, 12:43 UTC
Message-ID
<20261103-pks-grep-recurse-submodule-v2-1-b00e3b3dc865@pks.im>
In-Reply-To
<20261103-pks-grep-recurse-submodule-v2-0-b00e3b3dc865@pks.im>

The function `grep_tree()` searches for a specific string recursively in a tree. It can recurse in two different ways:

  - It may either see a subtree, in which case it recurses into itself.
  - Or it may see a submodule, and in that case it recurses via
    `grep_submodule()` which then again calls `grep_tree()`.

In the latter case we continue grepping in the submodule repository's object graph. Historically this used to work by linking that submodule's object directory into the main object database. But in 93cd344e34f (builtin/grep: stop registering submodule ODB as source, 2026-09-11), which was released as part of Git 2.56, we stopped doing that and instead expect to read submodule objects via the submodule repository.

This logic is broken though: while we indeed know to read blobs via the submodule's object database, we didn't adapt trees in the same way. The result is that Git fails to read the object:

    $ git grep --recurse-submodules -e hello HEAD
    fatal: unable to read tree (935cff11a11f8734cf4e0d40955d1e0e5c12038e)

This went unnoticed because our tests only cover submodules that contain files at the top level.

Fix this by reading nested trees via `opt->repo`, which is set to the submodule's repository via `grep_submodule()`.

Reported-by: Root <rootminus0x1@gmail.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/grep.c                     |  2 +-
 t/t7814-grep-recurse-submodules.sh | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index b045f8a488d..22fb365eeac 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -653,7 +653,7 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 			void *data;
 			size_t size;
 
-			data = odb_read_object(the_repository->objects,
+			data = odb_read_object(repo->objects,
 					       &entry.oid, &type, &size);
 			if (!data)
 				die(_("unable to read tree (%s)"),
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index 3d149d34c15..f51c5181805 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -631,4 +631,27 @@ test_expect_success 'check scope of core.useReplaceRefs' '
 	git -C base grep --cached --recurse-submodules C
 '
 
+test_expect_success 'grep --recurse-submodules with tree-ish and nested directory' '
+	rm -rf sub super &&
+
+	git init sub &&
+	mkdir sub/dir &&
+	echo hello >sub/top &&
+	echo hello >sub/dir/nested &&
+	git -C sub add top dir/nested &&
+	git -C sub commit --message "sub" &&
+
+	test_config_global protocol.file.allow always &&
+	git init super &&
+	git -C super submodule add "$(pwd)/sub" sub &&
+	git -C super commit --message "super" &&
+
+	cat >expect <<-\EOF &&
+	HEAD:sub/dir/nested:hello
+	HEAD:sub/top:hello
+	EOF
+	git -C super grep --recurse-submodules -e hello HEAD >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.56.0.500.g5d06dc02cd.dirty
Previous: Patrick SteinhardtNext: Patrick Steinhardt
Message 8 of 10 in “builtin/grep: fix reading objects from wrong repository”
  1. 0/3 builtin/grep: fix reading objects from wrong repositoryPatrick Steinhardt, Oct 30, 2026
  2. 1/3 builtin/grep: read submodule trees via their repositoryPatrick Steinhardt, Oct 30, 2026
  3. Toon ClaesOct 30, 2026
  4. Patrick SteinhardtNov 3, 2026
  5. 2/3 builtin/grep: read sparse directory trees via passed-in repositoryPatrick Steinhardt, Oct 30, 2026
  6. 3/3 builtin/grep: read ".gitmodules" via passed-in repositoryPatrick Steinhardt, Oct 30, 2026
  7. 0/3 builtin/grep: fix reading objects from wrong repositoryPatrick Steinhardt, Nov 3, 2026
  8. 1/3 builtin/grep: read submodule trees via their repositoryPatrick Steinhardt, Nov 3, 2026
  9. 2/3 builtin/grep: read sparse directory trees via passed-in repositoryPatrick Steinhardt, Nov 3, 2026
  10. 3/3 builtin/grep: read ".gitmodules" via passed-in repositoryPatrick Steinhardt, Nov 3, 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.