viv.lock

viv.lock is the record-per-package lock format behind merging composer.lock without conflicts; this page covers using it on its own, with or without a committed composer.lock beside it.

Converting and exporting

viv lock convert          # translate an existing composer.lock into viv.lock
viv lock export --check   # composer.lock from viv.lock; --check only compares
viv update --lock native  # resolves normally, also writes viv.lock beside composer.lock (implied once viv.lock exists)

viv lock export writes composer.lock from viv.lock through the same writer a solve feeds, byte-equal on every pinned compatibility project. --check reports whether the committed composer.lock matches without writing anything. A project that isolates plugins (see Two plugins, one library) gets that list in composer.lock too, under a top-level extra.viv.isolate key that Composer ignores.

Installing from viv.lock alone

viv install in a project with viv.lock and no composer.lock generates composer.lock first and says so, one line, before installing proceeds. With both files present, install writes nothing and refuses a divergence between them with a hint naming viv lock export and viv lock convert as the fix — it never rewrites a composer.lock that's already on disk, on any evidence, since git checkout doesn't preserve mtimes and a present-but-differing file might be one a developer, or Composer itself, legitimately changed.

A project can therefore commit viv.lock alone and let viv install generate composer.lock from it, or keep committing both and let install catch the two files disagreeing.

Marking composer.lock as generated

viv init --lock native and viv lock convert mark composer.lock linguist-generated in .gitattributes, so GitHub's diff view and language statistics treat it the way a build artefact deserves: collapsed in pull requests and excluded from the repository's language breakdown.

Where the format comes from

Each viv.lock record holds a package's name, version, dist and source references, its dev/root-requirement/time fields, and (since the export above needed it) its own composer.lock block verbatim. The reasoning behind that shape, and the merge behaviour it earns, is chapter 1 of the research programme.