Merge Methods, Merge Trains, Mergeability Checks, Conflict Resolution, and Integration Strategies: Diagnostics, Failure Modes, Security, and Performance
Diagnose stale CI evidence, unexpected commit identities, unsafe conflict resolutions, merge-train confusion, and premature branch cleanup with preserved SHAs and least-destructive repair.
Learning objectives
- Diagnose a merge blocked by target advancement without assuming a previously green pipeline is still valid.
- Reconcile source, merge, squash, and target SHAs when the resulting history differs from expectation.
- Repair a bad conflict resolution by returning to preserved evidence rather than rewriting history blindly.
- Distinguish ordinary MR pipeline status from merged-results and merge-train status.
- Recover from premature source-branch deletion using MR metadata and reachable commits.
1. Diagnostic sequence: preserve, scope, inspect, repair, verify
Integration incidents invite destructive reactions: force-push the branch, rebase repeatedly, delete the MR, or bypass a gate. Resist that. Use a stable sequence:
- Preserve: source SHA, target SHA, MR IID/URL, pipeline ID/SHA, merge/squash SHA fields, conflict output.
- Scope: offering, project, source/target refs, merge method, squash setting, mergeability reason, pipeline type.
-
Inspect: Git graph, API
detailed_merge_status, head pipeline SHA, project settings, and discussion/approval state. - Repair: use the least destructive action—rerun/rebase/resolve/update policy—without hiding the original failure.
- Verify: compare exact SHAs and target reachability after the correction.
2. Failure: pipeline passed, but the target moved
Suppose MR pipeline 900 passed on source SHA S1.
Another MR advances target from T1 to T2.
The green pipeline proves S1 passed as a source-branch
MR pipeline; it does not prove S1 + T2 is valid.
MR_IID="17"
glab api "projects/$PROJECT_ID/merge_requests/$MR_IID" --jq '{sha,diff_refs,detailed_merge_status,head_pipeline}'
git fetch origin
git rev-parse origin/main
git log --graph --decorate --oneline --all -n 25
If the method is fast-forward or semi-linear, the MR may report
need_rebase. On Free, rebase/update the source and let
the MR pipeline run again if the project requires exact source
validation. On paid tiers, merged-results pipelines or merge trains
can validate a more representative integration candidate.
3. Failure: “the merge SHA is not the source SHA”
This is often expected, not corruption. A merge commit creates a new commit with two parents. Squash creates a new commit representing multiple source commits. Fast-forward without squash may make the target equal the source tip. Diagnose using all identities:
glab api "projects/$PROJECT_ID/merge_requests/$MR_IID" --jq '{sha,merge_commit_sha,squash_commit_sha,target_branch,state,merged_at}'
git fetch origin --prune
git show --no-patch --pretty=raw origin/main
git log --graph --decorate --oneline --all -n 40
The repair is usually documentation or a policy choice, not rewriting the target. Rewrite history only under an explicit incident/recovery procedure; this chapter never requires force-push.
4. Failure: the conflict markers disappeared, but behavior is wrong
An operator resolves mode=feature versus
mode=target by keeping only mode=feature.
Git is satisfied because the syntax conflict is gone, but the
target-side semantic requirement vanished.
Return to the preserved tips and compare:
git show "$SOURCE_SHA_BEFORE:conflict.txt"
git show "$TARGET_SHA_AFTER_ADVANCE:conflict.txt"
git show "$RESOLVED_SHA:conflict.txt"
# Run the smallest relevant test after semantic resolution.
./scripts/test-config-behavior.sh
5. Failure: merge-train status is mistaken for ordinary pipeline status
A train car can be waiting/running because it is validating an ordered candidate that includes earlier MRs. The source MR’s own head pipeline might already be green. These are different objects. On Premium/Ultimate, inspect the merge-train UI/API and candidate pipeline rather than treating the head pipeline as train proof.
# Premium/Ultimate, read-only example if your project already uses trains.
glab api "projects/$PROJECT_ID/merge_trains" --paginate --jq '.[] | {id,target_branch,status,merge_request:{iid:.merge_request.iid},pipeline}'
The REST response represents train entries and does not expose an
explicit queue-position field. For exact position, current docs
recommend sorting IDs or using GraphQL
MergeTrainCar.index.
6. Failure: source branch was deleted before evidence capture
Do not assume the work is lost. The MR can still retain
sha, merge_commit_sha, and
squash_commit_sha; the target may contain the
integrated commits. Preserve API output immediately and test
object/reachability locally.
glab api "projects/$PROJECT_ID/merge_requests/$MR_IID" | tee ch09-evidence/mr-recovery.json
git fetch origin --prune
SOURCE_SHA="$(jq -r .sha ch09-evidence/mr-recovery.json)"
git cat-file -t "$SOURCE_SHA" || echo "object not present locally yet"
git fetch origin "$SOURCE_SHA" || true
git show --no-patch --oneline "$SOURCE_SHA" || true
If the source commit is still reachable remotely or by MR refs, create a new recovery branch only when needed and only in the disposable lab. Do not reconstruct by guessing from commit messages.
7. Intentionally broken example: outdated source under fast-forward policy
Expected GitLab state:
detailed_merge_status=need_rebase or equivalent current
message because the target advanced. The unsafe response is to
bypass the policy. The correct response is to preserve SHAs, rebase
the source onto the latest target, inspect changed commit
identities, rerun required validation, and then merge.
git switch ch09-feature
git fetch origin main
OLD_SOURCE="$(git rev-parse HEAD)"
git rebase origin/main
NEW_SOURCE="$(git rev-parse HEAD)"
printf 'old_source=%s
new_source=%s
' "$OLD_SOURCE" "$NEW_SOURCE"
# Push normally when the branch has never been published. If the branch was already
# shared and the rebase rewrote it, follow your repository's explicit collaboration
# policy; this lesson does not instruct a force push.
8. Reliability, performance, and cost belong to the causal chain
A merge train can spend more compute than independent pipelines because later cars may be rebuilt when earlier context changes. That cost can be justified when integration failures are expensive. Conversely, repeatedly rebasing every MR in a fast-moving Free project can also consume CI minutes and developer attention. Measure the bottleneck rather than weakening gates because “CI is slow.”
Knowledge check
A green MR pipeline references source SHA S1, but main advanced afterward. What is the first conclusion?
The pipeline is evidence for S1 as tested, not proof of the current integration candidate with the newer target.
When can target SHA legitimately differ from source SHA?
With merge commits, squash commits, rebases, or combinations of those settings. The graph and MR SHA fields determine the actual outcome.
Why is removing conflict markers insufficient verification?
Git only knows the text is syntactically resolved; semantic intent can still be wrong, so compare both preserved tips and run relevant tests.
Why might a merge-train entry be pending when the MR head pipeline is green?
The train validates a different ordered candidate including earlier train entries; head-pipeline success is not train-candidate success.
What is the first recovery source after premature branch deletion?
Preserved MR/API metadata and target/reachable Git objects, not guessed branch reconstruction.
Summary
Integration diagnosis is identity-driven. Preserve exact SHAs and pipeline context, distinguish head pipelines from integrated candidates, interpret expected new merge/squash identities correctly, and repair semantic conflicts without erasing evidence. Most failures need a targeted rebase, rerun, correction, or documentation fix—not history rewrite.
Official references
- GitLab Docs — Merge methods
- GitLab Docs — Squash and merge
- GitLab Docs — Merge conflicts
- GitLab Docs — Merge trains
- GitLab Docs — Merged results pipelines
- GitLab Docs — Merge request pipelines
- GitLab Docs — Auto-merge
- GitLab Docs — Merge requests API
- GitLab Docs — Projects API
- GitLab Docs — Project settings
- GitLab Docs — Merge requests
- GitLab Docs — Default branch
- GitLab Docs — Merge trains API
- GitLab Docs — REST API pagination
- GitLab Docs — glab API
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.