Chapter 09Lesson 02~235 minutes

Merge Methods, Merge Trains, Mergeability Checks, Conflict Resolution, and Integration Strategies: Guided Hands-On Workflow and Core Operations

Inspect a disposable project, compare merge-commit and fast-forward outcomes, create and repair a controlled conflict, inspect MR/API state, and model a merge train without requiring a paid tier.

Disposable labMerge commitFast-forwardConflict repairglabREST evidence

Learning objectives

  • Capture the project merge method and target/source SHAs before mutation.
  • Demonstrate merge-commit and fast-forward outcomes safely in a disposable project or local mirror.
  • Engineer a deterministic text conflict, preserve both tips, resolve it locally, and verify the MR becomes mergeable.
  • Compare Git commit graphs with GitLab MR/API metadata after integration.
  • Model merge-train ordering and pipeline identity without requiring Premium/Ultimate.
Availability baseline (verified 2026-08-21). Merge commit, merge commit with semi-linear history, fast-forward merge, squash options, ordinary merge-request pipelines, conflict resolution, auto-merge, merge checks such as pipeline/thread requirements, and source-branch cleanup are available on GitLab Free across GitLab.com, Self-Managed, and Dedicated. Merged results pipelines and merge trains are Premium/Ultimate. GitLab 19.2 documents automatic rebase before merge for semi-linear and fast-forward methods as generally available; older Self-Managed versions can differ. The mandatory chapter path therefore uses Free merge methods, local conflict resolution, and ordinary MR/API evidence, while merge trains are optional or simulated.

1. Scenario and safety boundary

Use a disposable project such as GROUP/integration-sandbox. You need Git, an authenticated glab, and Maintainer/Owner only if you choose the optional project-setting changes. No new token, runner, cloud account, protected production branch, or paid feature is required.

  • Mandatory refs: ch09-target, ch09-merge, ch09-ff, and ch09-conflict.
  • Safety: never change the production/default branch merge method solely for training. Use a dedicated disposable project.
  • Evidence: record every source tip and target tip before deleting any branch.

2. Preflight: capture current configuration and graph

REPO="GROUP/integration-sandbox"
PROJECT_ID="123456"
BASE="main"   # replace after checking the API
mkdir -p ch09-evidence

glab auth status
glab api "projects/$PROJECT_ID"   --jq '{path_with_namespace,default_branch,merge_method,squash_option,remove_source_branch_after_merge,merge_pipelines_enabled,merge_trains_enabled}'   | tee ch09-evidence/project-before.json

git fetch origin --prune
git log --graph --decorate --oneline --all -n 25   | tee ch09-evidence/graph-before.txt

3. First prove the graph mechanics locally

Before changing hosted settings, create a local scratch repository. This makes the Git mechanics observable without any platform permission.

rm -rf /tmp/ch09-graph-lab
mkdir /tmp/ch09-graph-lab && cd /tmp/ch09-graph-lab
git init -b main
git config user.name "GitLab Course Lab"
git config user.email "lab@example.invalid"
printf 'base
' > app.txt
git add app.txt && git commit -m "A: base"

git switch -c feature-merge
printf 'merge-path
' >> app.txt
git commit -am "B: merge-path"
git switch main
printf 'target-change
' > target.txt
git add target.txt && git commit -m "C: target advances"
git merge --no-ff feature-merge -m "M: explicit merge commit"
git log --graph --decorate --oneline --all

# Separate fast-forward example.
git switch -c ff-base HEAD~2
git switch -c feature-ff
printf 'ff-path
' > ff.txt
git add ff.txt && git commit -m "D: ff change"
git switch ff-base
git merge --ff-only feature-ff
git log --graph --decorate --oneline --all

4. Optional: compare two methods in the disposable GitLab project

The Projects API reports merge_method as merge, rebase_merge, or ff. If you own the disposable project, record the original value and change it only long enough to test the intended method. The UI path is Settings → Merge requests → Merge method.

Do not use this procedure on a shared or production project. Changing merge method changes every subsequent MR in that project. If the project is not disposable, keep this as a read-only comparison and use the local graph lab instead.
ORIGINAL_METHOD="$(glab api "projects/$PROJECT_ID" --jq .merge_method)"
printf 'original_merge_method=%s
' "$ORIGINAL_METHOD" | tee ch09-evidence/original-method.txt

# Read-only after any UI change:
glab api "projects/$PROJECT_ID" --jq '{merge_method,squash_option}'   | tee ch09-evidence/method-current.json

5. Engineer a controlled conflict and preserve both tips

Create two branches from the same known target and change the same line differently. Keep the original SHAs in evidence before resolving.

cd /path/to/integration-sandbox
git fetch origin "$BASE"
git switch -C ch09-target "origin/$BASE"
printf 'mode=baseline
' > conflict.txt
git add conflict.txt && git commit -m "ch09: conflict baseline"
git push -u origin ch09-target
TARGET_SHA_BEFORE="$(git rev-parse HEAD)"

git switch -c ch09-conflict
printf 'mode=feature
' > conflict.txt
git commit -am "ch09: feature interpretation"
SOURCE_SHA_BEFORE="$(git rev-parse HEAD)"
git push -u origin ch09-conflict

# Advance the target with a competing semantic change.
git switch ch09-target
printf 'mode=target
' > conflict.txt
git commit -am "ch09: target interpretation"
git push origin ch09-target
TARGET_SHA_AFTER_ADVANCE="$(git rev-parse HEAD)"

printf 'source=%s
target_before=%s
target_after=%s
'   "$SOURCE_SHA_BEFORE" "$TARGET_SHA_BEFORE" "$TARGET_SHA_AFTER_ADVANCE"   | tee ch09-evidence/conflict-tips.txt

6. Open the MR and inspect the failed mergeability check

glab mr create -R "$REPO"   --source-branch ch09-conflict   --target-branch ch09-target   --title "ch09: controlled conflict"   --description "Disposable conflict-resolution lab." --yes

MR_IID="REPLACE_WITH_IID"
glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"   --jq '{iid,state,sha,source_branch,target_branch,has_conflicts,detailed_merge_status,diff_refs}'   | tee ch09-evidence/mr-conflict-before.json

Expected state: after GitLab finishes checking, the MR should report a conflict-related mergeability state. Preserve that evidence rather than immediately editing the file.

7. Resolve locally: understand before you edit

Fetch the target into the source branch and inspect the conflict block. The correct resolution for this synthetic example is a third explicit value that documents the combined intent.

git switch ch09-conflict
git fetch origin ch09-target
git merge --no-commit --no-ff origin/ch09-target || true

git status
git diff -- conflict.txt

# Resolve semantically; do not blindly choose ours/theirs.
printf 'mode=feature-plus-target
' > conflict.txt
git add conflict.txt
git commit -m "ch09: reconcile feature and target semantics"
RESOLVED_SHA="$(git rev-parse HEAD)"
git push origin ch09-conflict

# Poll until GitLab finishes mergeability checking.
for i in 1 2 3 4 5; do
  glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"     --jq '{sha,has_conflicts,detailed_merge_status}' | tee "ch09-evidence/mr-after-$i.json"
  sleep 2
done

The lesson does not hide the failed git merge; that non-zero exit is the evidence that created the conflict state. The repair is the explicit resolution commit.

8. Premium/Ultimate merge-train simulation

A merge train is not “auto-merge with a nicer queue.” It requires merge-request pipelines plus merged-results pipelines. Model three entries:

train_fixture:
  target: main
  cars:
    - mr: 101
      candidate: target + MR101
      status: passed
    - mr: 102
      candidate: target + MR101 + MR102
      status: running
    - mr: 103
      candidate: target + MR101 + MR102 + MR103
      status: waiting

If MR101 leaves the train or fails, later candidate context can change and later pipelines may need to be recreated. This ordered context is the central distinction from independent MR pipelines.

9. Compare GitLab metadata with the actual graph

git fetch origin --prune
git log --graph --decorate --oneline --all -n 40   | tee ch09-evidence/graph-after.txt

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"   --jq '{iid,state,sha,merge_commit_sha,squash_commit_sha,detailed_merge_status,merged_at}'   | tee ch09-evidence/mr-after.json

Do not infer target identity from the MR source SHA. A merge commit or squash can create new SHAs. Verify the remote target ref independently with git ls-remote or git rev-parse origin/<target>.

10. Challenge: select the right integration surface

Your team needs a linear target history, must retain each source commit, and refuses to merge if the source is behind the target. Which project method fits best? Fast-forward without squash. If the team also wants an explicit branch-boundary merge commit while still requiring up-to-date source history, choose semi-linear.

Knowledge check

Why is the local graph lab useful before changing a GitLab project setting?

What evidence should be captured before resolving a conflict?

Why does the lesson intentionally keep the failing merge command visible?

What makes a merge train different from several independent MR pipelines?

Which method gives a linear history while retaining all source commits?

Summary

You inspected before mutation, modeled graph mechanics locally, created a real conflict, preserved both tips, repaired the conflict semantically, and compared GitLab MR metadata with the resulting Git graph. Merge trains remained an honest Premium/Ultimate simulation rather than a hidden paid requirement.

Official references

Next lesson

Choose integration policy deliberately

Lesson 3 turns these mechanics into a production decision framework for history, CI validity, cost, latency, conflict tooling, and branch cleanup.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.