Repository navigation
[sync] Synced updates by the same rule as deletions, and removed syncDeletions. - #8
Merged
Merged
Conversation
…Deletions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 tasks
SgtSwagrid
added a commit
to SgtSwagrid/scala-browser-plugin-template
that referenced
this pull request
Oct 26, 2026
) ## Summary The first of two PRs that make `project/plugins-browser-plugin.sbt` follow Scala Browser Plugin Config again. Since SgtSwagrid/github-graph#8, a synced file is updated only if its content in the target is one the source had *before* the target last changed it. #14 set this file to Omnibrowser 0.3.0 at 16:17 (+01:00). The config only got that same content at 16:20 (SgtSwagrid/scala-browser-plugin-config#9). So GitHub Graph treats the template's copy as a local change, and would keep it at 0.3.0 through every later bump. A file can't be recommitted with identical content, so this PR changes it trivially (a trailing comment), and the next one restores the config's exact content. The restore is then the target's last change, after the config had that content, so the file follows again. ## Changes - `project/plugins-browser-plugin.sbt`: a temporary trailing comment, removed by the next PR. ## Testing - [ ] Code compiles without errors or warnings (`sbt compile`) - [ ] Code is formatted correctly (`sbt scalafmtCheckAll`) - [ ] All unit tests pass (`sbt test`) - [ ] Additional unit tests added for new functionality (if applicable) GitHub Graph's own `merge-files.sh` was run locally on clones of both repositories, after a fake 0.3.1 bump in the config (local only, never pushed). It printed `Kept: project/plugins-browser-plugin.sbt (changed in the target)` and left the template on 0.3.0, confirming the freeze. The same simulation is run again after the second PR. ## Notes No behaviour changes: the comment is inert, and the build stays on Omnibrowser 0.3.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
4 tasks
SgtSwagrid
added a commit
to SgtSwagrid/scala-browser-plugin-template
that referenced
this pull request
Oct 26, 2026
## Summary The second of two PRs that make `project/plugins-browser-plugin.sbt` follow Scala Browser Plugin Config again (the first was #15). This restores the config's exact content. The template's last change to the file then comes after the config had that content, so under GitHub Graph's rule (SgtSwagrid/github-graph#8) the file follows the config's later bumps again. ## Changes - `project/plugins-browser-plugin.sbt`: replaced with the config's current file, byte for byte (the same git blob, so the same content as before #15). ## Testing - [ ] Code compiles without errors or warnings (`sbt compile`) - [ ] Code is formatted correctly (`sbt scalafmtCheckAll`) - [ ] All unit tests pass (`sbt test`) - [ ] Additional unit tests added for new functionality (if applicable) The file's git blob matches the config's. Once this merges, GitHub Graph's `merge-files.sh` is run again locally, after a fake 0.3.1 bump in the config, to confirm that it now updates the file (the result goes in a comment here). ## Notes No behaviour changes: the build stays on Omnibrowser 0.3.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
SgtSwagrid
added a commit
that referenced
this pull request
Oct 26, 2026
…ce the last merged sync. (#9) ## Summary Replaces the provenance rule of #7 and #8 with a simpler model: - **Updates:** every sync copies every non-ignored file, overwriting whatever the target has. - **Deletions:** each file the source deletes is deleted from the target once. A sync deletes the files the source has deleted since the source commit of the last sync from it that the target merged. - **Opting out:** only through `ignore`. Measuring deletions from the last *merged* sync, rather than from the push that triggered the run, means: - a sync run that's skipped or fails is made up for by the next; - a sync PR rebuilt by later pushes keeps every deletion; - a file the target re-adds after a deletion was merged is left alone. All the provenance and history comparison is gone. ## Changes - **`scripts/last-sync.sh`** (new, its own workflow step): finds the source commit of the last sync this target merged, and exports it as `SOURCE_SYNCED`. - It reads the new `GitHub-Graph-Source` trailer on this source directory's commit in the most recently merged sync PR. GitHub keeps PR commits after a merge, whether squashed or not and with the branch deleted. - It searches the latest 20 merged sync PRs; 50 exceeded GitHub's GraphQL node limit. - With no such PR (the first sync, or syncs made before this version), it falls back to the commit before the triggering push, so that push's own deletions still go through. Without that either, it syncs no deletions. - **`scripts/merge-files.sh`**: copies every non-ignored file in the source root, as before #7. It then deletes the target's copy of each file deleted between `SOURCE_SYNCED` and the source's head (`git diff --diff-filter=D`), skipping ignored files. If that commit isn't in the source's history (say, after a force push), it warns and skips deletions. Over 90 lines are gone: the per-file history walks, the state map and the `Kept` reasons. - **`scripts/publish.sh`**: - Each sync commit now also carries `GitHub-Graph-Source: <source commit>`, after the key trailer. The PR body, which drops everything from the key trailer on, is unaffected. - `replay()` goes back to applying every change as it is. No carry-forward is needed: this source's commit is rebuilt each time from everything since the last merged sync. - The key calculation moved to `load-config.sh`. - **`scripts/load-config.sh`**: exports the source directory's key (`SYNC_KEY`) and the two trailer names, for `last-sync.sh` and `publish.sh`. - **`.github/workflows/sync.yml`**: a "Find last sync" step before "Merge files", given the target's token and `github.event.before`. - **`README.md`**: "Which files are synced" describes the model: copy everything, delete once since the last merged sync, opt out with `ignore`, and what a skipped run, a re-added file and a closed PR mean. "Merge semantics" says again that files are overwritten, that downstream changes are lost unless ignored, and that the most recent source wins. - **`templates/pull-request-body.md`**: the default warning is back to its original text, which is accurate again. ## Testing No CI exercises the scripts, so I ran them locally: - **`merge-files.sh`**, against a source and target with known histories: - from the last merged sync, it deleted the two files deleted by a skipped run; - it left alone a file deleted before that sync (which the target still has); - it updated a file the source deleted and re-added within the range; - it skipped an ignored deleted file; - it overwrote the target's edited and own copies, and kept a target-only file. With no `SOURCE_SYNCED` it copied everything and deleted nothing. With a commit missing from the history, it warned and skipped deletions. - **`last-sync.sh`**, with `gh` stubbed: - it read the trailer, ignoring a lookalike in the body text; - it fell back to the commit before the push when the trailer was missing, as with older syncs; - it synced no deletions for an all-zero (branch-creating) before or none at all. - **The real `--jq` filter**, against SgtSwagrid/codeswitch's merged sync PRs: it found the latest merged sync commit from scala-browser-plugin-config by its key trailer. That commit predates the new trailer, so a live run would use the fallback until the next merged sync. - **The commit message**: `%(trailers:key=…)` reads both trailers, and the rendered PR body excludes them. - **`replay()`**: an update, addition and deletion all apply onto a newer base, including over the target's changes. Deleting a file the target already deleted is a no-op. - **Syntax**: `bash -n` passes for every script. ## Notes - **Overwriting:** every config runs `sync.yml@main`, so once merged, the next sync of every target overwrites any local edits to synced files, as before #7. - **Deletions in the meantime:** until each target merges its first sync under this version, its deletions come only from the triggering push. - **Repositories:** the template's and Codeswitch's version files, and basis and abstract-nonsense, simply follow their configs again. - **Changed downstream:** the files #8 had begun keeping are overwritten at the next sync, if they still differ. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Deletions were synced only for a file whose last change in the target came from the source (#7), but updates still overwrote whatever was downstream. Now one rule decides every file, whether the source updated, added or deleted it, and
syncDeletionsis gone.The rule: every file the source has ever had is given its state in the source (its latest version, or none if deleted). That happens only if the file's state in the target is one the source had before the target last changed it, and the source has changed it since. A file's absence counts as a source state once the source has deleted it. A file the target never had is added.
Changes
scripts/merge-files.sh: one pass over every file in the source's history replaces the old two steps (copy everything, then a separate deletion check).Added,Updated,Deleted,Kept(with the reason) orSkipped(ignored); unchanged files are no longer logged asCopied.scripts/publish.sh:replay(), which re-applies queued sync commits onto the latest target branch, uses the same idea. A change, whatever its kind, is applied only where the file is still as it was when the change was made. A change already present is skipped silently, and one to a file the target changed since is kept. Before, updates were always applied and only deletions were checked.syncDeletionsis removed fromparse-config.sh,load-config.shand the README. No graph in this account sets it.README.md: a new "Which files are synced" section explains the rule. ThesyncDeletionssection is gone. "Merge semantics" no longer claims updates overwrite everything, that copies shouldn't be modified, or that the most recent source wins; with this rule the first source to sync a file keeps it. The replay remark no longer refers to deletions alone.templates/pull-request-body.md: the default warning no longer says files with matching names are overwritten.sync.yml: the comment on full history no longer mentions deletions alone.Behaviour
So a file changed downstream stops following the source altogether. To make it follow again, give it the source's latest version.
Testing
No CI exercises the scripts, so I ran them against repositories built with known commit times:
merge-files.sh: one file per case above, plus the earlier scenarios (merge commits, a file re-added in the source after a synced deletion). Every case came out as in the table. The previous script, on the same histories, overwrote or restored the three files it now keeps.replay(): a sync commit, made on an old base, replayed onto a newer base where the target had changed some files meanwhile. Its update, addition and deletion applied; the target's changed file, a file it changed that the sync deleted, and a file it added itself were kept; a change already present was skipped. The previousreplay()overwrote two of those three files.bash -npasses for every script.Notes
sync.yml@main, so this applies to every sync as soon as it merges.Kept: <file> (changed in the target)in the sync logs.🤖 Generated with Claude Code