Keep auto-merge when automatic rebase handles target branch

What does this MR do and why?

When a project's merge method requires the source branch to sit on top of the target (Fast-forward merge or Merge commit with semi-linear history), pushing to a target branch aborts any pending auto-merge on the merge requests targeting it, and opens a to-do for the author. See RefreshService#abort_ff_merge_requests_with_auto_merges. That behaviour assumes the author now has a rebase to perform by hand, which a pending auto-merge cannot do for them.

That assumption does not hold when the project has Enable automatic rebase prior to merge turned on. In that case FromSourceBranch#use_create_ref_service? routes the merge through MergeRequests::CreateRefService, which rebases onto the target and then fast-forwards it. The merge checks still gate the merge.

Mergeability::CheckRebaseStatusService already exempts these projects from the "source branch must be rebased" merge check for exactly this reason. The abort never received the matching exemption, so a project with automatic rebase turned on still has its auto-merges cancelled for a condition GitLab resolves on its own, and the author has to re-arm auto-merge by hand every time the target branch moves. This MR aligns the two.

Deliberately unchanged:

  • Merge train strategies. The loop already skips anything other than merge_when_checks_pass, and merge trains are mutually exclusive with that strategy.
  • Aborting when the source branch is updated (#abort_auto_merges). That is a different condition and remains correct.

Considerations:

  • Behind a feature flag. retain_auto_merge_with_automatic_rebase, type gitlab_com_derisk, disabled by default. The flag is checked after the project setting, so projects without automatic rebase before merge do not pay for a flag lookup on every push to a target branch.
  • Automatic rebase does not re-run CI/CD. A retained auto-merge can therefore merge a rebased result that no pipeline has tested. That is inherent to the existing feature rather than new here, and is already documented under automatic rebase before merge, but it is the main behavioural consequence of this change.
  • No changelog trailer, because the change is behind a flag that is disabled by default. One belongs in the merge request that removes the flag.

References

Screenshots or screen recordings

No user interface changes.

How to set up and validate locally

  1. In a project with a repository, go to Settings > Merge requests, and:

    • Set Merge method to Merge commit with semi-linear history (or Fast-forward merge).
    • Select Enable automatic rebase prior to merge.
  2. In the rails console, enable the feature flag for that project:

    Feature.enable(:retain_auto_merge_with_automatic_rebase, Project.find(<project_id>))
  3. Create a merge request from a feature branch, and set it to auto-merge.

  4. Push a new commit to the target branch, so the source branch falls behind.

  5. Observe the merge request:

    • With the flag disabled: auto-merge is cancelled, with the system note aborted the automatic merge because target branch was updated, and a to-do for the author.
    • With the flag enabled: auto-merge stays active, and the merge request merges once its checks pass, rebasing at merge time.

Specs:

bundle exec rspec spec/services/merge_requests/refresh_service_spec.rb -e abort_ff_merge_requests_with_auto_merges

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Mika Fischer

Merge request reports

Loading