Related:
unity-path-rules(shared Unity importer predicates) ·unity-assetdb::register(.metasynthesis primitives) ·meow-tower/lefthook.yml(consumer).
Pre-commit hook that auto-fixes Unity .meta pairing in a staged commit:
synthesizes missing metas, prunes orphaned ones, and reports anything that
can't be safely auto-fixed. Run with no arguments inside a Unity project's git
working tree.
cargo install --path . # → ~/.cargo/bin/unity-meta-cop
# Wire from a lefthook.yml pre-commit step:
# meta-pairing:
# run: unity-meta-copFor every staged add/delete under Assets/ or Packages/<pkg>/ (depth ≥ 2):
Auto-fixed silently (no commit blocked):
- Added asset without
.meta→ synthesize a fresh.meta(random 128-bit guid + extension-derived importer kind viaunity-assetdb::register) andgit addit. - Added asset in a new folder → also synthesize
<folder>.meta(folderAsset: yes) for each ancestor dir that doesn't already have one in the index. Walks top-down so nested new dirs all get covered in one pass. - Deleted asset with leftover
.meta→git rm --quietthe orphan. - Deleted last file in a folder → if
<folder>.metais now an orphan,git rmit too.
Reported as manual fixes (exit 1):
- Added
.metawhose target doesn't exist — can't conjure the asset. - Deleted
.metawhose target is still tracked — the original guid is lost; user must restore the meta manually or also delete the asset.
Renames flatten to delete-of-src + add-of-dst so both ends get the auto-fix treatment. Modify / type-change are skipped — meta pairing isn't affected by content edits.
Synthesis uses only the pure primitives from unity-assetdb::register
(generate_guid, importer_for_path, render_meta) — no asset-db touch, no
lock, no DB round-trip. Per missing meta: one file write + one entry to a
batched git add. Even 100 missing metas finish well under 100ms.
Sourced from unity-path-rules so
the rules match what Unity's importer itself skips:
- Hidden segments anywhere in the path —
.foo/foo~. - Contents of opaque plugin folders —
*.androidlib/*.androidpack/*.aar. The folder itself (and its.meta) are still tracked; only its contents are skipped (Unity hands them to Gradle untouched).
Tool-specific exclusions stay out of scope — e.g. unity-assetdb drops
.asmdef / .md from its name pool, but those do carry Unity .meta
files, so the pairing check (and the synth) honors them.
0— no issues, or every issue was auto-fixed.1— manual-fix issues remain (reported on stderr).2— internal error (git invocation failed, non-UTF-8 path in index, fs write failed, …).
- Staged diff:
git diff --cached --name-status -z. - Post-staging snapshot (for "is the sibling in this commit?"):
git ls-files --cached -z. - Repo root for relative path resolution:
git rev-parse --show-toplevel.