integration: Move regeneration out of merge driver#1252
Open
ed-irl wants to merge 5 commits into
Open
Conversation
Collaborator
Author
This was referenced Jun 12, 2026
Open
2744c7a to
b0ecc92
Compare
fa21086 to
95531f4
Compare
b0ecc92 to
af57956
Compare
95531f4 to
682c26c
Compare
The regenerate merge driver previously ran generators (mise generate,
go test -update) from inside git's merge process. Those generators
side-effect on many files in one pass, and git aborts subsequent merge
steps with 'your local changes would be overwritten' when it sees a
worktree dirtied by an earlier driver invocation. The existing
stage_outputs workaround called git add from inside the driver to
stage the side effects, but git holds the index lock for the duration
of the merge — git add silently failed with rc=128 every time.
This commit moves regeneration out of the merge driver entirely:
- The driver becomes take-incoming + log: cp the incoming version
into place, append the path to the file named by
$GS_INTEGRATION_REGEN_LOG. No side effects.
- gs runs all tip merges with that env var pointing at a per-merge
temp file, accumulates the deduplicated path list across the
rebuild, and invokes .gs/integration-regenerate (a project-level
executable at the repo root) with the list on stdin. The script
chooses what to regenerate based on which categories of files
appear in its input — so a rebuild with no derived conflicts
pays one process spawn and exits.
- Whatever the script wrote to the worktree gets folded into the
last merge commit via git add -A && git commit --amend --no-edit
--allow-empty.
The contract is well-orthogonalized: gs hands the script an
allow-listed list of paths (only files tagged merge=regenerate in
.gitattributes can appear there), the script returns by writing to
the worktree, gs takes care of the commit-amend wrap-up. Project
generator knowledge stays in the project's script; gs doesn't carry
a dispatch table.
2cd315d to
572934b
Compare
67a7acf to
9f7d7a8
Compare
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.
integration: Move regeneration out of merge driver
The regenerate merge driver previously ran generators (mise generate,
go test -update) from inside git's merge process. Those generators
side-effect on many files in one pass, and git aborts subsequent merge
steps with 'your local changes would be overwritten' when it sees a
worktree dirtied by an earlier driver invocation. The existing
stage_outputs workaround called git add from inside the driver to
stage the side effects, but git holds the index lock for the duration
of the merge — git add silently failed with rc=128 every time.
This commit moves regeneration out of the merge driver entirely:
The driver becomes take-incoming + log: cp the incoming version
into place, append the path to the file named by
$GS_INTEGRATION_REGEN_LOG. No side effects.
gs runs all tip merges with that env var pointing at a per-merge
temp file, accumulates the deduplicated path list across the
rebuild, and invokes .gs/integration-regenerate (a project-level
executable at the repo root) with the list on stdin. The script
chooses what to regenerate based on which categories of files
appear in its input — so a rebuild with no derived conflicts
pays one process spawn and exits.
Whatever the script wrote to the worktree gets folded into the
last merge commit via git add -A && git commit --amend --no-edit
--allow-empty.
The contract is well-orthogonalized: gs hands the script an
allow-listed list of paths (only files tagged merge=regenerate in
.gitattributes can appear there), the script returns by writing to
the worktree, gs takes care of the commit-amend wrap-up. Project
generator knowledge stays in the project's script; gs doesn't carry
a dispatch table.
integration regenerate: Regenerate CLI reference