You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(pm): make mcpp.lock authoritative for git deps (2026.8.1.2)
The lock was read for the first time in the previous commits of this PR, but
only as a hint the local clone had to confirm: a recorded commit counted while
`~/.mcpp/git/<hash>` existed, and otherwise the branch was re-resolved over the
network and the lock rewritten. That hands "which commit do we build" to the
survival of a cache directory. `mcpp new` does not gitignore `mcpp.lock` — it is
meant to be committed — so the failure is ordinary: clone the project on a second
machine, get a different commit, and see the lock quietly change under you.
Measured on the new e2e assertion, with the branch moved and the cache evicted:
the previous head built v2, this builds the v1 the lock recorded. `cargo build` /
`cargo update` split it the same way.
Making the lock authoritative also collapses the block into two independent
questions, each with at most one network operation and therefore exactly one
--offline gate: which commit (tag/rev name one; a branch is answered by the lock,
else by ls-remote), and is it on disk (the commit picks the cache directory; a
miss is a clone). The separate tag/rev leg goes with it, taking its per-build
"from cache" noise line and its "is locked but its local cache is missing"
message — which was emitted for deps that were never in the lock.
Four defects fixed along the way:
- --offline refused git remotes that are local directories. docs/05-mcpp-toml.md
defines --offline as "never touch the network ... anything already installed
still builds", and prepare.cppm's dependency-download gate draws the same line
in a comment; ls-remote/clone against a local path are filesystem reads, so
refusing them buys no isolation. Remotes are now classified by shape, which
keeps a Windows drive letter (C:\repo — colon, no @) on the local side.
- A clone killed between `git clone` and `git checkout` served the wrong commit
forever: the directory is named after the commit but was only checked for
existence. Branch deps now compare `git rev-parse HEAD` and re-clone on
mismatch (tag/rev keep the ref name as identity, so there is nothing to
compare).
- The clone depended on `cd` changing drive on Windows. cmd.exe needs `cd /d`,
and MCPP_HOME routinely sits on a different drive than the project; every
other cross-drive site in the repo (process.cppm, msvc.cppm) writes /d, this
one did not. `git -C <dir>` needs no shell at all.
- An unreadable mcpp.lock was a plain warning, invisible to --strict. Per
src/diag.cppm that is the degraded channel: the engine silently does less than
asked — every git branch dep falls back to the network.
Also: parse_git_source no longer splits a tag/rev whose name contains '@' (only
branch entries carry @<commit>, which is what the writer emits), the cmd_update
comment now records the right causality, and docs/CHANGELOG cover the new
semantics in both languages.
Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
@@ -356,6 +357,25 @@ package declares `[features]` but does not include the requested feature (includ
356
357
the result of backend desugaring), a warning is issued by default, and an error
357
358
under `mcpp build --strict`.
358
359
360
+
**Git dependencies and `mcpp.lock`**: a `tag` or `rev` already names a fixed point
361
+
in history, but a `branch` moves. The first build resolves the branch to a commit
362
+
and records it in `mcpp.lock`, and every later build rebuilds **that** commit — the
363
+
lock is authoritative, not a cache hint, so deleting `~/.mcpp/git` or moving to
364
+
another machine cannot quietly put you on a newer tip. Ask for the newer tip
365
+
explicitly:
366
+
367
+
```bash
368
+
mcpp update mylib # drop the recorded commit; the next build re-resolves it
369
+
mcpp update # same, for every dependency
370
+
```
371
+
372
+
Because the recorded commit is enough to decide what to build, a rebuild with the
373
+
clone already in `~/.mcpp/git` makes no network request at all and works under
374
+
`--offline`. Only two things need the network: resolving a branch that has no
375
+
commit in the lock, and cloning a commit that is not cached yet. A `git =` value
376
+
that names a local directory (or a `file://` URL) needs neither, so it is never
377
+
refused offline.
378
+
359
379
**SemVer constraints**:
360
380
361
381
```toml
@@ -454,7 +474,7 @@ Controls, in order of precedence:
454
474
455
475
| Control | Effect |
456
476
|---|---|
457
-
|`--offline` (any command) | Never touch the network — no index refresh, no downloads, no toolchain auto-install. Anything already installed still builds |
477
+
|`--offline` (any command) | Never touch the network — no index refresh, no downloads, no toolchain auto-install, no `git ls-remote`/`clone`. Anything already installed still builds, including git deps whose commit is in `mcpp.lock` and whose clone is cached|
458
478
|`MCPP_OFFLINE=1`| Same, for a whole shell session or CI job |
459
479
|`[index] auto_refresh = false` in `~/.mcpp/config.toml`| Never refresh the index automatically; downloads still work |
0 commit comments