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

[BUG] submodule merge tries to read B's commit from A

From
GCGuillaume CHAUVEL <guillaume.chauvel@gmail.com>
Date
Sep 23, 2026, 20:20 UTC
Message-ID
<CAP4DsUexEmm1qo6jH+Qzy+n3dQs_OCJ8yg=ReF+aVrcTrC7NeQ@mail.gmail.com>
I ran into two problems while merging a superproject with submodules.

One problem, involving the repository used for commit-graph lookups, was reported in this thread: https://lore.kernel.org/git/d3241733-d015-4646-88e0-06e56a04e77b@nutanix.com/T/#m174067937aaf76e9fa844386961b3e9e66c1e4d9

The other problem is that during a merge, Git sometimes tries to read from submodule A a commit that exists only in submodule B. I reproduced this with Git v2.56.0-rc2, built from source in an Ubuntu 26.04 container and an Alpine container. The reproducer below triggered the issue in all 50 Ubuntu runs and in 43 out of 50 Alpine runs.

The merge should report a submodule conflict, not look for B's commit in A or report A as corrupt. The script checks the OID's presence in both submodules and prints the "BUG" line when it finds this case.

--------- #!/usr/bin/env bash

set -euo pipefail

unset $(git rev-parse --local-env-vars) export LC_ALL=C export GIT_CONFIG_NOSYSTEM=1 export GIT_CONFIG_GLOBAL=/dev/null export GIT_DEFAULT_HASH=sha1 export GIT_TEMPLATE_DIR= export GIT_AUTHOR_NAME=Reproducer export GIT_AUTHOR_EMAIL=reproducer@example.invalid export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL" export GIT_AUTHOR_DATE='2000-01-01T00:00:00 +0000' export GIT_COMMITTER_DATE='2000-01-01T00:00:00 +0000'

tmpdir=$(mktemp -d)

for name in A B; do mkdir "$tmpdir/source-$name" cd "$tmpdir/source-$name" git init -q -b main printf '%s base\n' "$name" >file git add file git commit -qm "$name base" git switch -qc branch-a git commit --allow-empty -qm "$name branch-a" git switch -qc branch-b main git commit --allow-empty -qm "$name branch-b" git switch -q main done

mkdir "$tmpdir/super" cd "$tmpdir/super" git init -q -b base git config --local protocol.file.allow always for name in A B; do # reproduces the bug git -c protocol.file.allow=always submodule add -q "file://$tmpdir/source-$name" "$name"

# does not reproduce the bug # git -c protocol.file.allow=always submodule add -q "$tmpdir/source-$name" "$name" done git add . git commit -qm base

git switch -qc branch-a for name in A B; do (cd "$name" && git switch -q -c branch-a --track origin/branch-a) done git add A B git commit -qm branch-a

git switch -qc branch-b base for name in A B; do (cd "$name" && git switch -q -c branch-b --track origin/branch-b) done git add A B git commit -qm branch-b

cd "$tmpdir" git -c protocol.file.allow=always clone -q --no-local "file://$tmpdir/super" clone cd clone git -c protocol.file.allow=always submodule update --init -q git switch -q -c branch-a --track origin/branch-a if merge_output=$(git merge branch-b 2>&1); then merge_status=0 else merge_status=$? fi printf 'git merge exit status: %s\n%s\n' "$merge_status" "$merge_output"

if [[ $merge_output =~ Could\ not\ read\ ([0-9a-f]{40}|[0-9a-f]{64}) ]]; then foreign_oid=${BASH_REMATCH[1]} if ! (cd A && git cat-file -e "$foreign_oid" 2>/dev/null) && (cd B && git cat-file -e "$foreign_oid" 2>/dev/null); then printf 'BUG: OID %s belongs to B instead of A\n' "$foreign_oid" fi fi ---------

One run produced:
git merge exit status: 2
error: Could not read 7d549ba7e9152029e66ddca8dd23ee7da32b036f
error: could not parse commit 7d549ba7e9152029e66ddca8dd23ee7da32b036f
error: failed to merge submodule A (repository corrupt)
Merge with strategy ort failed.
BUG: OID 7d549ba7e9152029e66ddca8dd23ee7da32b036f belongs to B instead of A

An AI analysis identified a likely cause: a delta-base cache entry may remain after its pack is closed. If a pack from another submodule reuses the same packed_git address and base offset, Git may return stale cached data.

Next: Philippe Blain
Message 1 of 4 in “[BUG] submodule merge tries to read B's commit from A”
  1. Guillaume CHAUVELSep 23, 2026
  2. Philippe BlainSep 30, 2026
  3. Patrick SteinhardtOct 1, 2026
  4. Patrick SteinhardtOct 2, 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.