Show what a force push changed since a review
Problem and behavior
A reviewer who asks for a rebase or a squash gets a force push back, and --since then records not an ancestor of the head, so the whole diff is reviewed. After this change the bundle says what the author changed:
- On the same base (a squash, an amend, a reorder),
since.diffholds the tree diff of the two heads and the manifest saysrewritten. For #585 fromd8d4fe8that is 22 lines instead of 1130. - After a rebase,
since.range-diff.txtholdsgit range-diffof the old commits against the new ones and the manifest saysrebased. A commit whose only change is itsChange-Idreads as unchanged. - An old head that cannot be resolved or compared keeps the earlier behavior.
Approach
A tree diff after a rebase also carries what the base brought in: for #584 it is 1754 lines against a whole diff of 1284. So a moved base gets a range-diff, and --since-base names the old base when the old head's merge base with the PR's base is not where it started.
--creation-factor=100 keeps a small commit with a resolved conflict paired with its old version, at the cost of pairing commits that may be unrelated. The pairing is a heuristic and skips merge commits, so SKILL.md and lenses.md say both files only point to what to read first and the whole diff is still reviewed. The comparison also fetches objects the bundle did not need before, by full SHA.
A commit's marker is read only from its header line, so a subject containing ! or a message line shaped like a header cannot mark a changed commit as unchanged.
The semantic comparison jserv raised on #587 is not part of this change.
Validation
./scripts/test.sh allpasses exceptshell-syntax, which reports SC2319 inscripts/git-post-commit.sh;shellcheckgives identical output onmain. Removing the new branch fails the new tests.- Replayed on #585, #584 and #586:
rewrittenwith 22 lines,rebasedwith 624 lines of 1284, andrebasedwith 925 lines of 1200. - Four commits of #585 rebased onto
e64598e, which touches none of their files, read as=in 4 lines, with or without everyChange-Idreplaced. One more file added to the second commit marks only that commit!. - The fetch path in a clean clone and the cleanup after a failed
awkorgitwere run by hand, with injected failures, and have no test in the tree.
Close #587
Summary by cubic
After a force push, --since compares the old and new heads instead of always reviewing the whole diff: same-base rewrites produce since.diff (rewritten), and rebases produce since.range-diff.txt (rebased). If comparison fails, the bundle keeps the whole-diff behavior.
- Use
--since-base <sha>when the old head’s original base cannot be inferred. - These files only point to what to read first; range-diff pairing is heuristic and skips merge commits, and the full diff still needs review.
- Comparison may fetch missing Git objects; commits changed only by a
Change-Idare treated as unchanged.
Closes #587.