Skip to content

fix(train): retarget stacked MRs to the train target before rebase - #111

Merged
sairus2k merged 5 commits into
mainfrom
fix/stacked-mr-retarget
Oct 15, 2026
Merged

sairus2k merged 5 commits into
mainfrom
fix/stacked-mr-retarget

Conversation

@sairus2k

Copy link
Copy Markdown
Owner

Problem

Merging a stack of MRs (feature-b → feature-a → main) in one train merged the second MR into feature-a, not main.

GitLab retargets dependent MRs only when the base MR's source branch is deleted on merge, and does it asynchronously. glmt deletes no branches, so after the base merged, the stacked MR still targeted feature-a: the runner rebased it onto feature-a and merged it there. The final pipeline wait then polled main for that merge commit until it timed out.

Fix

Before rebasing an MR, the runner checks whether its target branch is the source branch of an MR already merged by this train. If so, it retargets the MR to the train's target branch via the new Client.UpdateMergeRequestTargetBranch (PUT /merge_requests/:iid with target_branch), then rebases and merges as usual.

  • Base skipped (conflict, not mergeable, …) → every MR stacked on it is skipped with base branch X was not merged, instead of merging into a branch that never reached main.
  • Retarget fails → the MR is skipped, and so is the stack above it.
  • The TUI shows a Retarget to main step, and the rebase label names the new target.

Commits

  1. fix(train) — client method (API, demo, logging, mocks) and runner logic
  2. fix(tui) — retarget step and rebase label
  3. test(e2e) — stack of three MRs
  4. docs — README note on stacked MRs

Verification

  • Runner: table test over a 3-MR stack — all merged with retargets ordered before each rebase; skipped base skips the stack; failed retarget skips the MR and the stack above it.
  • Client: httptest for the request body and error wrapping. TUI: model-state test for the step names.
  • E2E (GitLab CE 18.8.5, go test -tags e2e, passed in 499s): a stacked MRs subtest reuses the TestTrainMergesMRs container, since a second boot would not fit the 25-minute CI timeout. It moves main after creating the stack so the base rebase rewrites its commits, then asserts all three MRs are merged into main and each commit appears on main exactly once — GitLab's rebase drops the stale copies of the base's commits.

Not covered

A stacked MR queued before its base still merges into the base branch, as before. The README now says to select the base first.

An MR stacked on another MR of the train (targeting its source branch)
kept that branch as its target after the base merged: GitLab retargets
dependent MRs only when the base's source branch is deleted on merge,
and does it asynchronously. glmt deletes no branches, so the stacked MR
was rebased onto and merged into the stale base branch, and the final
pipeline wait on the train target timed out looking for its merge
commit.

The runner now retargets such an MR to the train target branch through
the new Client.UpdateMergeRequestTargetBranch before rebasing it. An MR
whose base was skipped is skipped too, since merging it would land its
commits in a branch that never reached the target. A failed retarget
skips the MR.
The rebase step label used the MR's original target branch, which reads
"Rebase onto feature-a" for a stacked MR the runner has just retargeted
to main.
Runs as a subtest on the GitLab instance of TestTrainMergesMRs, since a
second container boot would not fit the 25-minute CI timeout.

main is moved after the stack is created so the base MR's rebase
rewrites its commits; the stacked MRs then carry stale copies of them.
The test asserts each commit lands on main exactly once, i.e. GitLab's
rebase drops the copies already merged.
@sairus2k
sairus2k enabled auto-merge (rebase) October 15, 2026 15:05
@sairus2k
sairus2k merged commit e1158a9 into main Oct 15, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant