Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .changeset/6391-lockfile-merge-driver-measurement.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
---
---

CI/doc-only: records the measurement of the last remaining "Lockfile Merge Driver" row
(objectui#6391). No mechanism is added or removed.

`changeset-release.yml` performs no local merge, so the driver it configures cannot fire in
that job. Swept the whole file with a control term on every zero-hit — no `git merge`,
`rebase`, `pull`, `cherry-pick`, `am`, `apply` or `revert`; every `git` in it is the two
`git config` lines, `git status` twice, and the `git checkout -- .` / `git clean` pair that
undoes the version step, `checkout -- .` being an index-restore rather than a merge. The
deciding fact is in the marketplace action: read at `changesets/action` v1.9.0 (`a45c4d5`),
`src/git.ts` and the shipped `dist/` agreeing, its entire git surface is `checkout`,
`reset --hard`, `add .`, `commit -m`, `push --force` and `config user.*` — the version branch
is updated by `reset --hard` plus a force-push, and a force-push resolves no merge.

⭐ The `.gitattributes` line is NOT dead, which is why the row was not removed with the other
two. `CONTRIBUTING.md` has contributors configure the same driver and then `git merge
upstream/main` — a real local merge on the attributed path. Measured in a scratch repository
with one variable changed: with the attribute the driver fires and the lockfile is
regenerated; without it the identical merge ends in `CONFLICT (content)`. The CI half is dead
and the repository-wide half is live, while `ci-cd-pipeline-doc.test.ts` binds them together,
so the removal is a decision rather than a cleanup and is escalated instead of guessed.

The row's stated reason ("version bumps rewrite the lockfile") was wrong and is corrected — a
rewrite is not a merge — and the guide gains the third ⛔ note in the series that already
records "pushing is not merging" and "a server-side merge is not a local one".

No source and no behaviour change; nothing a consumer installs is affected.
46 changes: 46 additions & 0 deletions .github/workflows/changeset-release.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -518,6 +518,52 @@ jobs:
cache: 'pnpm'
registry-url: 'https://registry.npmjs.org'

# ⚠️ MEASURED 2026-08-26 (objectui#6391): this job performs NO local merge,
# so the driver configured below has no occasion to fire HERE. The step is
# kept anyway — see the ⛔ at the bottom of this comment, which is the part
# that matters.
#
# The sweep, so nobody re-derives it a fourth time (objectui#6358 and
# objectui#6369 each re-derived it for a different workflow):
#
# Every `git` in this file, enumerated rather than grepped-for-absence:
# the two `git config` lines below, `git status --porcelain` (x2),
# `git checkout -- .` and `git clean -fdq` in "Restore the pre-version
# tree". No `merge`, `rebase`, `pull`, `cherry-pick`, `am`, `apply` or
# `revert` anywhere in the file — each of those zero-hits was taken with
# a control term that DID hit the same file, because a zero-hit with no
# control is not a reading.
#
# `git checkout -- .` (below, in the restore step) takes tracked paths
# from the INDEX to undo what `pnpm changeset:version` wrote. That is a
# discard, not a merge; no merge driver participates.
#
# ⭐ The load-bearing part is not in this file at all — it is what
# `changesets/action@v1` does, and it has to be read to be known. Read at
# v1.9.0 (`a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d`), `src/git.ts` and the
# executed `dist/` bundle agreeing: the action's COMPLETE git surface is
# `checkout <branch>` / `checkout -b`, `reset --hard <sha>`, `add .`,
# `commit -m`, `push origin HEAD:<branch> --force`, `push origin <tag>`
# and `config user.*`. The version-branch update is `prepareBranch`
# (checkout, then `reset --hard github.context.sha`) followed by a commit
# and a FORCE-PUSH. It never merges, rebases or three-ways anything, so on
# this side too the driver has no occasion to fire. (Its `commitMode:
# github-api` path — not selected here; the default is `git-cli` — builds
# the commit through the GitHub API instead, and the bundle reads no
# `.gitattributes` and implements no merge driver at all.)
#
# ⛔ DO NOT delete this step "because it is dead" without a ruling. It is
# dead only in the CI half. The `.gitattributes` line it depends on
# (`pnpm-lock.yaml merge=pnpm-merge`) is NOT dead: `CONTRIBUTING.md` tells
# contributors to configure this same driver locally and then to
# `git merge upstream/main`, which is a real local merge on the attributed
# path. Measured both ways in a scratch repo: with the attribute the driver
# fires and the lockfile is regenerated; with the attribute removed and
# nothing else changed, the same merge ends in `CONFLICT (content)` with
# conflict markers in `pnpm-lock.yaml`. Removing the CI half forces
# `ci-cd-pipeline-doc.test.ts` to demand the attribute's removal too, which
# would break that live contributor path — so the two must be decided
# together, not dropped as one more dead row. objectui#6391 carries it.
- name: Configure Git merge driver for pnpm-lock.yaml
run: |
# Configure custom merge driver for pnpm-lock.yaml
Expand Down
36 changes: 35 additions & 1 deletion content/docs/guide/ci-cd-pipeline.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -1699,7 +1699,35 @@ One workflow carries that step:

| Workflow | Why it needs the driver |
|---|---|
| `changeset-release.yml` | version bumps rewrite the lockfile on the release branch |
| `changeset-release.yml` | ⚠️ configures it — but performs no local merge, see the measurement below |

⚠️ **That row's stated reason was wrong, and the row is now the whole question**
([#6391](https://github.com/objectstack-ai/objectui/issues/6391)). It used to read "version bumps
rewrite the lockfile on the release branch". A **rewrite is not a merge**: `changeset:version`
overwrites `pnpm-lock.yaml` outright, and git runs a merge driver only when it has to *reconcile
two versions* of an attributed path. Measured on `changeset-release.yml`, and recorded in the file
itself so it is not re-derived a fourth time:

- Every `git` in that workflow, enumerated rather than grepped for absence: the two `git config`
lines, `git status --porcelain` twice, and `git checkout -- .` plus `git clean -fdq` in "Restore
the pre-version tree". No `merge`, `rebase`, `pull`, `cherry-pick`, `am`, `apply` or `revert` —
every zero-hit taken with a control term that hit the same file.
- `git checkout -- .` there takes tracked paths from the **index** to undo what the version step
wrote. That is a discard, not a merge.
- The deciding fact is in the marketplace action, not the workflow. Read at `changesets/action`
v1.9.0 (`a45c4d5`), `src/git.ts` and the shipped `dist/` bundle agreeing: its entire git surface
is `checkout`, `reset --hard`, `add .`, `commit -m`, `push --force` and `config user.*`. The
version-branch update is a checkout, a `reset --hard` to the triggering commit, a commit, and a
**force-push**. A force-push resolves no merge, so the driver has no occasion to fire.

⭐ **But the `.gitattributes` line is not dead, and that is why this is not simply a third
removal.** The attribute is repository-wide, and its live consumer is the contributor path this
page already points at: `CONTRIBUTING.md` tells contributors to configure this same driver and
then to `git merge upstream/main`. Measured in a scratch repository, one variable changed between
the two runs — **with** the attribute the driver fires and the lockfile is regenerated; **without**
it, and nothing else altered, the identical merge ends in `CONFLICT (content)` with conflict
markers left in `pnpm-lock.yaml`. So the CI half is dead and the repository half is live, while the
pin below binds them together. Resolving that is a decision, not a cleanup.

`scripts/__tests__/ci-cd-pipeline-doc.test.ts` pins that table against the workflows that
actually configure `merge.pnpm-merge`, in both directions. It is pinned because the claim had
Expand DownExpand Up@@ -1729,6 +1757,12 @@ needs no driver, and giving it one buys nothing while implying a lockfile hazard
— `gh pr merge`. But GitHub executes that one itself, not on the runner, so no local git config
takes part in it.

⛔ **A rewrite is not a merge, and a force-push resolves none.** `changeset-release.yml` carries
the step on the strength of "version bumps rewrite the lockfile"
([#6391](https://github.com/objectstack-ai/objectui/issues/6391)). Regenerating a file is not
reconciling two versions of it, and the version branch is updated by `reset --hard` plus a
force-push inside `changesets/action`, which merges nothing on the runner.

## Adding a New Workflow

> **Give it a section on this page in the same PR.** Not a convention — a test.
Expand Down
Loading