Skip to content

A gitlink with no .gitmodules entry aborts the whole fetch, even outside src #1380

Description

@sawachikaminoru

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 update

Expected: 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:

  1. Sparse checkout does not help. The gitlinks are index entries; _configure_sparse_checkout only marks them skip-worktree. A project with src: vendored still trips over some/worktree.
  2. src/ignore filtering happens too late. _apply_src_and_ignore — which since fix: exclude submodules outside src folder when src is specified #1256 correctly drops submodules outside src — runs after submodules(), so it never gets the chance. The filter's own premise, that submodules outside src are not this fetch's business, applies equally to the failure being reported here.
  3. No git config silences both. submodule.active=':!*' turns submodule update into a no-op, but submodule foreach still aborts. And there is no .gitmodules to point a submodule.<name>.url at.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions