Repository navigation
feat(pull): rebase local splice changes onto the upstream with --rebase - #208
roschaefer wants to merge 10 commits into
Conversation
With a protected main, a pull of the fork's rebased patch branch reaches main as a squash merge, together with a local change. The squash commit records the rebased branch as the synced commit, but its folder isn't that branch's, so the rebuild joins it with the history before it, still built on the dropped patch, and the next push publishes that patch again. A pull request's own branch can't pull the patch branch either: it syncs with the upstream branch named like it. The scenario shows both, to decide on them before git splice pull --rebase (#55) builds on the result.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Only the end state was drawn, which didn't show where the dropped patch comes back: after the pull and on the pull request's branch, R is still linear on top of the rebased branch; only the squash merge joins the old history in. The steps now run in the document, each followed by a checked drawing, and one unchecked drawing shows the proposed rebuild.
A drawing that shows a pull request's branch next to main is hard to follow without the branches' names, but a branch name in a box only named an upstream branch. In a box on a monorepo commit, it now names the monorepo's branch, even where the upstream has one named alike.
With a single patch that upstream takes, the rebased patch branch ends up on upstream main, so the drawings showed T = patches = main. A real fork's patch branch (the scrut fork's, say) keeps patches upstream hasn't taken: one patch drops out, the other gets a new commit on top of main, and main and patches differ. The drawings name the monorepo's and the upstream's branches, so the pull request steps are easier to follow, and the squash-merged page proposes --branch for pulling the patch branch on a pull request's branch.
…anch A pull request's branch syncs with the upstream branch named like it. When a protected main follows a fork's patch branch, the upstream has no branch for the pull request, so its pull finds nothing, and taking a rebased patch branch had to happen on a local main first. --branch names the branch for that one command, without writing it to .splice (default-branch belongs to the upstream, not to one monorepo branch), and only for the splices the command selected: the ones below keep syncing with their own.
…ritten upstream A squash merge of a pull request that pulled a rebased patch branch and changed the folder records the new synced commit, but its folder isn't that commit's. The rebuild joined it with the history before it, still built on the commits the rebase dropped, so the next push published them again. On a protected main, nothing can rewrite that commit, and which upstream commits should carry its changes is the user's call. So push, status and the other commands that show the rebuild refuse, and say the way out: commit the folder's changes on top of the upstream branch by hand, push them there, and pull. That pull records the branch with the folder's files, so the rebuild starts there again. merge and pull therefore still rebuild past the refusal: they only compare with it.
With several upstreams, a pull from the original after the fork moves the synced commit from the fork's patch to the original's release, and the patch is no ancestor of the release. That's no rewrite: the fork still has the patch, so joining both sides is right, as the several-upstreams scenario shows. Like merge, the rebuild only takes it for a rewrite when no fetched upstream branch has the earlier commit.
A pull that merges a diverged upstream makes the next push send a merge commit, which upstreams with linear history don't take (#55). After the upstream rebased its branch, e.g. a fork's patch branch onto a release, the pull even refused: the local changes, rebuilt on the dropped commits, would bring them back. Redoing the changes by hand on top took five commands. pull --rebase and merge --rebase do it like git pull --rebase: they take the upstream branch in on top of the newest commit whose folder has exactly the synced commit's files, which merges without a conflict from there, and rebase the commits since onto that pull. The rebuild then starts at the pulled commit and sends the local changes linearly on top. It rewrites the monorepo branch, so it refuses when a remote-tracking branch has any of those commits; a pull request's branch is where it belongs, together with --branch. The refusal after an upstream rewrite now names it. A rebase in progress, like a cherry-pick, stops the next pull, before the detached HEAD would hide why.
…, fix by hand The squash-merged page now takes the release on the pull request's branch with --branch, shows status and push refusing the squash merge that mixed a local change into it, and the way out by hand: commit the folder's changes on top of the patch branch upstream, push, and pull. The rebuild then starts at that commit, without a new rebuild rule.
The box above q covered the vendor/a/ label of the lane it sits in.
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d4ec7af1d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if [[ -z "${REBUILD_JOINS_REWRITTEN:-}" && -n "$previous" ]] && | ||
| git cat-file -e "$previous^{commit}" 2>/dev/null && | ||
| ! git merge-base --is-ancestor "$previous" "$synced" && | ||
| [[ -z "$(git for-each-ref --count=1 --contains "$previous" refs/splices/)" ]]; then |
There was a problem hiding this comment.
Scope the rewrite exception to this splice's upstreams
The refs/splices/ query searches fetched branches for every splice, so a different splice whose upstream happens to retain previous suppresses this safety check. In that case rebuild_splice joins the rewritten-away history and succeeds, allowing the next push to republish precisely the commits this guard is intended to reject. Limit the search to the upstream keys configured for path, as on_no_upstream_branch does.
Useful? React with 👍 / 👎.
| if ! git -c advice.mergeConflict=false rebase -q --onto "$pull" "$base"; then | ||
| log_err "$path: conflict while rebasing onto the $verb -- resolve it, then 'git rebase --continue' (or 'git rebase --abort' to give up)" | ||
| return 1 |
There was a problem hiding this comment.
Distinguish pre-rebase failures from conflicts
When the index or worktree contains tracked changes, this git rebase invocation exits before creating any rebase state, but every nonzero exit is reported as a conflict with instructions to run git rebase --continue. The same misdiagnosis can occur when a pre-rebase hook rejects the operation. Git's --autostash documentation identifies that option as what permits rebasing a dirty worktree; since it is not used here, detect preflight failures and tell the user to commit or stash instead of directing them to a nonexistent rebase.
Useful? React with 👍 / 👎.
Stacked on #207. Taking a fork's rebased patch branch into a monorepo whose protected
mainonly takes squash-merged pull requests, as when dogfooding the scrut splice.git splice pull --rebase/merge --rebase(feat: rebase local splice changes onto upstream for linear pushes #55): likegit pull --rebase, takes the upstream branch in on top of the newest commit whose folder has exactly the synced commit's files, and rebases the commits since onto that pull. The next push sends the local changes linearly on top of the upstream branch, also after the upstream rebased it (the old patches stay dropped). It rewrites the monorepo branch, so it refuses when a remote-tracking branch has any of those commits. The refusal after an upstream rewrite now names it.--branch <name>: names the upstream branch for one pull or merge, without writing.splice, so a pull request's branch can pull the patch branchmainfollows.main.statusandpushrefuse and name the way out by hand: commit the folder's changes on top of the upstream branch, push them there, pull. That pull records the new commit with the folder's files, so the rebuild starts there; no new rebuild rule. A pull request that only pulls squash-merges fine.Scenario
06-rewritten-history/04-patch-branch-rebasednow has two patches (one taken upstream, one rebased), drawings that name the monorepo's and upstream's branches (check-drawingreads a branch name in a box on a monorepo commit as a monorepo branch),pull --rebaseinredo-on-top, and the squash merge with its way out in02-squash-merged.Defaults taken for #55's open questions, to confirm:
--rebasewould rewrite.git rebasedoes by default.pull --rebaseandmerge --rebase;--bumpand--rebasedon't go together.Refs #55, #169