feat(analyze): surface pinned files that are behind upstream - #21
Merged
Merged
Conversation
Pinned/ignored files win whole-file, so when upstream also changed one since the last sync its hunks are dropped without a trace: analyze showed the file like any other protected file and sync said nothing. A pinned tailwind.css missed seven upstream @Utility rules across three syncs this way. - analyze-core: flag protected files both sides changed (`upstreamChanged`) and size the dropped change with one batched numstat (`upstreamChangedLines`) - display: new "protected but behind upstream" section (supersedes the plain pinned group), and the sync summary lists `protectedConflicts` with the same hint right when the drop happens - merge-engine: record `protectedConflicts` (batch-restored protected files upstream changed + conflicts auto-resolved to fork) on the MergeResult - analyze --list/--json: include these files in the all/protected scopes and emit the new fields; README documents the section and its last-sync-point limit - git: shared `getDiffStat` (lifted from contributions) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The protected-but-behind check is relative to the last sync point, so a drop that happened in an earlier sync reads as plain `ahead` afterwards. For every pinned (not ignored) `ahead` file whose blobs differ, one batched `git diff --numstat --no-renames <upstream> HEAD` records the deletion count as `upstreamLinesAbsent`: lines upstream has that the fork lacks, compared at the tips. Binaries are skipped. The "protected in fork" section suffixes lines with `· N upstream lines absent` when N > 0 and adds a hint to diff and decide; `--json` (and thus `--scope protected`) carries the field. Co-Authored-By: Claude Fable 5.1 <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.
Why
Pinned and ignored files win whole-file. When upstream also changed such a file since the last sync, its hunks are dropped without a trace:
analyzeshowed the file like any other protected file andsyncsaid nothing. A pinnedtailwind.cssin raak missed seven upstream@utilityrules across three syncs this way.This is the cella-cli half of the fork drift convergence work (pairs with cellajs/cella#1121).
What
Protected but behind upstream (
7ef0a7d)analyze-core: flags protected files both sides changed (upstreamChanged) and sizes the dropped change with one batched numstat (upstreamChangedLines)display: new⚠ protected but behind upstreamsection, superseding the plain pinned group; the sync summary listsprotectedConflictswith the same hint, right when the drop happensmerge-engine: recordsprotectedConflictson theMergeResult(batch-restored protected files upstream changed, plus conflicts auto-resolved to the fork)analyze --list/--json: includes these files in theallandprotectedscopes and emits the new fieldsgit: sharedgetDiffStat, lifted out ofcontributionsUpstream lines absent (
e1af815)aheadafterwards. For every pinned (not ignored)aheadfile whose blobs differ, one batchedgit diff --numstat --no-renames <upstream> HEADrecords the deletion count asupstreamLinesAbsent, compared at the tips. Binaries are skipped.↑ protected in forksection suffixes lines with· N upstream lines absentwhen N > 0;--jsoncarries the field.README documents the section and its last-sync-point limit.
Testing
tests/protected-behind.test.ts(238 lines)pnpm ts,pnpm lint,pnpm testgreen locally (18 files, 167 tests)🤖 Generated with Claude Code