Repository navigation
A gitlink with no .gitmodules entry aborts the whole fetch, even outside src #1380
Description
Summary
If an upstream repository contains a gitlink (mode 160000) that is not registered in .gitmodules, dfetch update fails outright with
fatal: No url found for submodule path '<path>' in .gitmodules
The project is not fetched at all. This happens even when the offending path lies entirely outside the project's src, and even when the upstream has no .gitmodules file whatsoever.
Such a repository is malformed, but it is not rare: it is what you get when someone commits a git worktree directory, or git adds a nested checkout by accident. The upstream I vendor from has done it twice in two months, in two different directories, and the consumer has no way to ask the producer to hurry. Right now the only remedies are to pin to an older revision that predates the mistake, or to shim git on PATH — both disproportionate to a probe that is incidental to the fetch being requested.
Reproduction
Fully self-contained; no network needed.
# 1. An upstream with a stray gitlink and no .gitmodules.
mkdir -p /tmp/dfetch-repro/upstream && cd /tmp/dfetch-repro/upstream
git init -q -b main
mkdir vendored && echo hello > vendored/file.txt
git add -A && git commit -qm "initial"
git update-index --add --cacheinfo 160000,"$(git rev-parse HEAD)",some/worktree
git commit -qm "commit a gitlink with no .gitmodules entry"
# 2. A consumer that vendors only `vendored/` — nowhere near the gitlink.
mkdir -p /tmp/dfetch-repro/consumer && cd /tmp/dfetch-repro/consumer
cat > dfetch.yaml <<'EOF'
manifest:
version: '0.0'
remotes:
- name: local
url-base: file:///tmp/dfetch-repro/
projects:
- name: demo
remote: local
repo-path: upstream
branch: main
src: vendored
dst: vendored
EOF
dfetch updateExpected: vendored/file.txt is fetched. The gitlink is outside src and declares no submodule, so there is nothing to do about it.
Actual:
Dfetch (0.14.0)
demo:
>>>git submodule update --init --recursive<<< returned 128:
fatal: No url found for submodule path 'some/worktree' in .gitmodules
Diagnosis
GitLocalRepo.checkout_version in dfetch/vcs/git.py runs two submodule commands unconditionally on the freshly fetched clone:
run_on_cmdline(
logger,
["git", "submodule", "update", "--init", "--recursive"],
env=_extend_env_for_non_interactive_mode(),
)
submodules = self.submodules()and submodules() runs
["git", "submodule", "foreach", "--quiet", 'printf "%s\\0%s\\0%s\\0%s\n" ...']Both consult the index for gitlinks and both look each one up in .gitmodules, so both exit 128 on a gitlink that is not declared there. run_on_cmdline raises, and the fetch dies.
Three things make this hard to work around from the consumer side:
- Sparse checkout does not help. The gitlinks are index entries;
_configure_sparse_checkoutonly marks them skip-worktree. A project withsrc: vendoredstill trips oversome/worktree. src/ignorefiltering happens too late._apply_src_and_ignore— which since fix: exclude submodules outside src folder when src is specified #1256 correctly drops submodules outsidesrc— runs aftersubmodules(), so it never gets the chance. The filter's own premise, that submodules outsidesrcare not this fetch's business, applies equally to the failure being reported here.- No git config silences both.
submodule.active=':!*'turnssubmodule updateinto a no-op, butsubmodule foreachstill aborts. And there is no.gitmodulesto point asubmodule.<name>.urlat.
Environment
| DFetch | 0.14.0. Reproduced there; main carries the identical call sequence — unconditional submodule update --init --recursive at dfetch/vcs/git.py:529, then submodules(), with _apply_src_and_ignore still running after both. |
| git | 2.43.0 |
| Python | 3.12.3 |
| OS | Linux |
Activity
refactor: consolidate git submodule handling into git_submodule.py
test: reproduce gitlink-with-no-.gitmodules abort (#1380)
fix: don't abort the fetch on a gitlink with no .gitmodules entry (#1380
refactor: consolidate git submodule handling into git_submodule.py
test: reproduce gitlink-with-no-.gitmodules abort (#1380)
fix: don't abort the fetch on a gitlink with no .gitmodules entry (#1380
refactor: consolidate git submodule handling into git_submodule.py
ben-edna commentedon Aug 28, 2026
Fixed in #1385