[BUG] submodule merge tries to read B's commit from A
From: Guillaume CHAUVEL <hidden>
Date: 2026-09-23 20:20:37
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 (local) 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.