Resolve "Missing MR links on rebased merge train commits (FF merge)"
What does this MR do and why?
Right now, when we have merge requests that ran on a merge train and were merged via semi linear or fast forward merge, the commit shas get rewritten, when the merge request gets rebased. Therefore, we can no longer say from the repository commit view, which merged commit was originally which commit from a merge request.
To address this issue, we have decided to create a new table that maps the "new" commit hash (as in 'wandered into master, got a new sha, because it was rebased') of an "old" commit from a merge request with its merge request and the project that it comes from.
References
Screenshots or screen recordings
How to set up and validate locally
- Check out this branch, let all the migrations run.
- Restart gdk
- Setup a project with semi linear or fast forward merge request strategy and merge trains. You can use
bundle exec rake gitlab:seed:merge_trains:project
to create a project with some merge requests. - Set up a .gitlab-ci.yml like this for the newly created repository:
job1:
script:
- echo "This job runs in merge request pipelines"
- sleep 30
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- Merge one of the newly merge requests (be sure that it says 'add to merge train')
- After the merge request that you merged is merged, click on the "Commits" menu on the left side of your Gitlab installation and look for the newly created commits
- Click e.g. on commit #2 (closed) of mr #1 (closed) and see, if a merge request is linked to that. If so, then everything works :slight_smile::thumbsup:
MR acceptance checklist
Query-Plan:
- bulk_insert:
INSERT INTO "generated_ref_commits" ("commit_sha","merge_request_id","created_at","project_id","updated_at") VALUES ('\xffe687697427a82afaeaa2308f056a162a3a4c0f', 204, '2025-06-27 10:47:03.260217', 26, CURRENT_TIMESTAMP), ('\x5054416054dfd1c694c954cf0028e278fc8bad4c', 204, '2025-06-27 10:47:03.260227', 26, CURRENT_TIMESTAMP), ('\xb929d19dac87514e3e8fae4a09cab7fb68d59503', 204, '2025-06-27 10:47:03.260229', 26, CURRENT_TIMESTAMP), ('\xab34122d06a64d7c6c4dad0de548a8c08f43169e', 204, '2025-06-27 10:47:03.260231', 26, CURRENT_TIMESTAMP), ('\x1491ee8d12675874d40347eaacca245d2ec30eb7', 205, '2025-06-27 10:47:18.123022', 26, CURRENT_TIMESTAMP), ('\x1dad6383cdfd71a3d5d0e7e9fa7ade96e58c0311', 205, '2025-06-27 10:47:18.123031', 26, CURRENT_TIMESTAMP), ('\xe1ba2a699b1cb04a5cbd00c253f9fbf2ce4e0d7e', 205, '2025-06-27 10:47:18.123032', 26, CURRENT_TIMESTAMP), ('\xaaa2472eae64c061ea6034c3e50e29bf8bb6cff0', 205, '2025-06-27 10:47:18.123034', 26, CURRENT_TIMESTAMP), ('\x3f937010b85c47631a99ba9077a0b49bf217ea2f', 206, '2025-06-28 08:52:47.529902', 26, CURRENT_TIMESTAMP), ('\x6352c6104e24c0c5ae47863e01397f97d234f138', 206, '2025-06-28 08:52:47.529912', 26, CURRENT_TIMESTAMP), ('\xdc4051245287df14803e631c1592d29ef9d4142c', 206, '2025-06-28 08:52:47.529913', 26, CURRENT_TIMESTAMP), ('\xb4df9032c200cd7f3967cf3b3cc08de4c58c2ea4', 206, '2025-06-28 08:52:47.529915', 26, CURRENT_TIMESTAMP), ('\xca3fae3b7e774fb4ae455595a82737b3e8d4a350', 207, '2025-06-28 08:53:21.652842', 26, CURRENT_TIMESTAMP), ('\xbf4df654956f3665d31f10251e80e9ceb8b1b894', 207, '2025-06-28 08:53:21.652852', 26, CURRENT_TIMESTAMP), ('\xa089875d183003b7de80fe64e673ed187b4fceba', 207, '2025-06-28 08:53:21.652854', 26, CURRENT_TIMESTAMP), ('\xbd5d5bdf8bd6cae7af63ed084f688d1f25960345', 207, '2025-06-28 08:53:21.652856', 26, CURRENT_TIMESTAMP), ('\x08793073ccf56c924ee49fdf91f69e1174deb3d4', 209, '2025-06-30 09:55:19.515194', 26, CURRENT_TIMESTAMP), ('\x801fc7154c4738f7e5b4e806732530fca89dda17', 209, '2025-06-30 09:55:19.515203', 26, CURRENT_TIMESTAMP), ('\xde021a65c1d88dc96403dd09263dc30e980cc345', 209, '2025-06-30 09:55:19.515205', 26, CURRENT_TIMESTAMP), ('\x70fb586edd8848d4df8ac8761b4572fe48652872', 209, '2025-06-30 09:55:19.515207', 26, CURRENT_TIMESTAMP), ('\xa010980be8c9fec67c1e05429536fed2f48ffdcf', 211, '2025-07-01 15:50:37.941457', 26, CURRENT_TIMESTAMP), ('\xee5dcee70d5a56789e780857f76111f18ecd0a67', 211, '2025-07-01 15:50:37.941479', 26, CURRENT_TIMESTAMP), ('\x0ea236959ee338b1ed04997fe6186e749f34b0c7', 211, '2025-07-01 15:50:37.941481', 26, CURRENT_TIMESTAMP), ('\xc54b18cfa6e067ef867b38eb17eb99cd16ee88fc', 211, '2025-07-01 15:50:37.941483', 26, CURRENT_TIMESTAMP) ON CONFLICT ("commit_sha") DO UPDATE SET updated_at=(CASE WHEN ("generated_ref_commits"."merge_request_id" IS NOT DISTINCT FROM excluded."merge_request_id" AND "generated_ref_commits"."created_at" IS NOT DISTINCT FROM excluded."created_at" AND "generated_ref_commits"."project_id" IS NOT DISTINCT FROM excluded."project_id") THEN "generated_ref_commits".updated_at ELSE CURRENT_TIMESTAMP END),"merge_request_id"=excluded."merge_request_id","created_at"=excluded."created_at","project_id"=excluded."project_id" RETURNING "id"
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Insert on generated_ref_commits (cost=0.00..0.36 rows=24 width=80) (actual time=0.753..0.913 rows=24 loops=1)
Conflict Resolution: UPDATE
Conflict Arbiter Indexes: index_grmrc_on_commit_sha
Tuples Inserted: 0
Conflicting Tuples: 24
-> Values Scan on "*VALUES*" (cost=0.00..0.36 rows=24 width=80) (actual time=0.208..0.247 rows=24 loops=1)
Planning Time: 0.132 ms
Execution Time: 0.965 ms
(8 rows)
- Select merge request by project id and sha:
SELECT "merge_requests"."id", "merge_requests"."target_branch", "merge_requests"."source_branch", "merge_requests"."source_project_id", "merge_requests"."author_id", "merge_requests"."assignee_id", "merge_requests"."title", "merge_requests"."created_at", "merge_requests"."updated_at", "merge_requests"."milestone_id", "merge_requests"."merge_status", "merge_requests"."target_project_id", "merge_requests"."iid", "merge_requests"."description", "merge_requests"."updated_by_id", "merge_requests"."merge_error", "merge_requests"."merge_params", "merge_requests"."merge_when_pipeline_succeeds", "merge_requests"."merge_user_id", "merge_requests"."merge_commit_sha", "merge_requests"."approvals_before_merge", "merge_requests"."rebase_commit_sha", "merge_requests"."in_progress_merge_commit_sha", "merge_requests"."lock_version", "merge_requests"."title_html", "merge_requests"."description_html", "merge_requests"."time_estimate", "merge_requests"."squash", "merge_requests"."cached_markdown_version", "merge_requests"."last_edited_at", "merge_requests"."last_edited_by_id", "merge_requests"."merge_jid", "merge_requests"."discussion_locked", "merge_requests"."latest_merge_request_diff_id", "merge_requests"."allow_maintainer_to_push", "merge_requests"."state_id", "merge_requests"."rebase_jid", "merge_requests"."squash_commit_sha", "merge_requests"."sprint_id", "merge_requests"."merge_ref_sha", "merge_requests"."draft", "merge_requests"."prepared_at", "merge_requests"."merged_commit_sha", "merge_requests"."override_requested_changes", "merge_requests"."head_pipeline_id", "merge_requests"."imported_from", "merge_requests"."retargeted" FROM "merge_requests" INNER JOIN generated_ref_commits ON generated_ref_commits.merge_request_id = merge_requests.id WHERE "merge_requests"."target_project_id" = 26 AND "generated_ref_commits"."commit_sha" = '\xc54b18cfa6e067ef867b38eb17eb99cd16ee88fc'
Hint: psql uses seq scan, because my table has not many entries locally. When we force it to use index scan (SET enable_seqscan = OFF;), it will correctly use index scan.
Seq scan:
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.14..3.51 rows=1 width=918) (actual time=0.077..0.078 rows=1 loops=1)
-> Seq Scan on generated_ref_commits (cost=0.00..1.30 rows=1 width=8) (actual time=0.037..0.037 rows=1 loops=1)
Filter: (commit_sha = '\xc54b18cfa6e067ef867b38eb17eb99cd16ee88fc'::bytea)
Rows Removed by Filter: 23
-> Index Scan using merge_requests_pkey on merge_requests (cost=0.14..2.17 rows=1 width=918) (actual time=0.034..0.034 rows=1 loops=1)
Index Cond: (id = generated_ref_commits.merge_request_id)
Filter: (target_project_id = 26)
Planning Time: 1.016 ms
Execution Time: 0.166 ms
(9 rows)
Index scan:
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.28..4.37 rows=1 width=918) (actual time=0.029..0.030 rows=1 loops=1)
-> Nested Loop (cost=0.28..4.37 rows=1 width=918) (actual time=0.029..0.029 rows=1 loops=1)
-> Index Scan using index_generated_ref_mr_commits_on_project_id_and_commit_sha on generated_ref_commits (cost=0.14..2.16 rows=1 width=8) (actual time=0.024..0.024 rows=1 loops=1)
Index Cond: ((project_id = 26) AND (commit_sha = '\x9d05150a29a4f55a45308d10d6455101254b2c03'::bytea))
-> Index Scan using merge_requests_pkey on merge_requests (cost=0.14..2.17 rows=1 width=918) (actual time=0.003..0.003 rows=1 loops=1)
Index Cond: (id = generated_ref_commits.merge_request_id)
Filter: (target_project_id = 26)
Planning Time: 0.236 ms
Execution Time: 0.049 ms
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #436943 (closed)