Skip to content

Config cannot request partial clones (git clone --filter) #576

Description

@tony

Summary

A vcspull config cannot ask for a partial clone, so syncing a workspace of large repositories downloads every version of every file in their history. The git-only shallow and depth settings also sit in the VCS-neutral options: block, and editors have no schema to complete or check config files. Depends on partial clone support in libvcs, libvcs#553. Sized for one evening once that lands.

Problem

Prompt

Let a repo entry request a partial clone, give git-only settings their own block, and publish a JSON Schema for config files.

These must hold; everything after them is open:

  • A repo entry can request a partial clone, and vcspull sync produces one: remote.origin.partialclonefilter is set and history blobs are missing.
  • A malformed filter, or an unknown key in the git-only block, fails when the config loads and names the file, workspace root, repository, and key; it never fails mid-sync.
  • Existing configs keep loading. Older locations of shallow and depth still work with a deprecation warning, and vcspull migrate rewrites them.
  • vcspull add and vcspull discover write the current layout.
  • The vcspull runtime never imports pydantic, so CLI startup does not get slower.
  • The published schema and the config loader accept and reject the same entries, enforced by a test.

Direction, non-binding:

  • Add a top-level git_options: {shallow, depth, filter} block on repo entries; rev stays in options:. filter takes git's spec string, a {kind: ..., <fields>} mapping, or a list of either, converted with libvcs coerce_filter and passed to GitSync as git_filter. git_options wins over options, which wins over top-level keys.
  • Validate git_options at load, reporting errors as '<workspace>' -> '<repo>' -> git_options.filter[<i>].
  • Warn on shallow/depth under options: and teach vcspull migrate both moves in one pass: top-level rev into options:, and shallow/depth from the top level or options: into git_options:. Also fix the existing deprecation warning, which joins the workspace key and repo name with no separator (~/codeflask).
  • Make build_repo_entry write git_options.
  • Add pydantic and jsonschema to the dev dependency group only. Add scripts/generate_schema.py to build the schema from the config TypedDicts, and commit its output under docs/_static/schemas/ so the docs site publishes it. Give the filter spec string a hint class that pydantic reads by method name, so no runtime import is needed, and have it validate with libvcs parse_filter. Test that the committed schema is current, and that shared fixtures give the same verdict through jsonschema against the schema file and through load_configs.
  • Document git_options, partial clones, and the # yaml-language-server: $schema=... comment; add a MIGRATION note; give the CHANGES entries YAML examples.

Target shape:

# yaml-language-server: $schema=https://vcspull.git-pull.com/_static/schemas/vcspull.schema.json
~/code/:
  git:
    repo: git+https://github.com/git/git.git
    options:
      rev: v2.55.0
    git_options:
      filter: blob:none
  monorepo:
    repo: git+https://github.com/example/monorepo.git
    git_options:
      depth: 50
      filter:
        - blob:limit=1m
        - kind: tree
          depth: 3

Details that cost time to rediscover:

  • pydantic (repo, v2.13.5 release notes, PyPI) rejects typing.TypedDict before Python 3.12, including TypedDicts imported from libvcs, so schema generator tests skip there. vcspull CI currently tests only Python 3.14.
  • Validating at runtime with a pydantic TypeAdapter built at import was tried and dropped: import vcspull.cli took about 220 ms instead of 120 to 133 ms (Python 3.14 free-threaded, best of 12 to 18 runs), and one bad filter produced several stacked errors naming pydantic internals, with no file path.
  • In JSON Schema, pattern and enum constrain strings only. Without "type": "string" on the string branch, a mapping such as {kind: nope} passes the filter union.
  • The schema has to accept what vcspull writes: url: in place of repo:, metadata from vcspull import --sync, and remotes as URL strings or {fetch_url, push_url} mappings, where the loader requires both keys.
  • pydantic's use_attribute_docstrings gives no descriptions for fields on TypedDicts split into Required and Optional bases, or on functional-syntax TypedDicts such as RepoPinDict.
  • Validate the schema document itself with jsonschema (repo, v4.26.0 release notes, PyPI); asking pydantic again would miss every constraint the generator adds by hand.
  • Differences the agreement test cannot cover yet: combine containing auto passes the schema but fails at load; an empty filter list fails the schema but loads; a misspelled repo-entry key fails the schema but is ignored at load.

Not doing:

  • Changing an existing checkout's filter on sync.
  • Detecting an existing checkout's filter in vcspull discover.
  • Validating the whole config with pydantic at runtime.

Alternatives

Weighed and set aside:

  • options.filter next to shallow and depth: no migration, but git-only settings stay mixed into the VCS-neutral block.
  • A nested options.git: block migrated by vcspull fmt --write: splits migration across two commands, and fmt skips pinned entries, so those warn forever.
  • Runtime pydantic validation: slower startup, broken on Python 3.10 and 3.11, and harder-to-read errors, as measured above.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions