Chapter 09Lesson 05~255 minutes

Checkpoint Lab — Merge Methods, Merge Trains, Mergeability Checks, Conflict Resolution, and Integration Strategies

Run an end-to-end integration checkpoint that predicts two commit graphs, captures a failed mergeability check, resolves a controlled conflict, verifies reachability, and cleans up disposable refs safely.

CheckpointCommit graphsMergeability gateConflictReachabilityChapter 10 bridge

Learning objectives

  • Predict the exact qualitative target graph for two integration strategies before performing either merge.
  • Create and preserve one failed mergeability check, identify the responsible gate, and repair only that cause.
  • Resolve a controlled text conflict locally and verify the repaired MR state independently.
  • Compare source, target, merge, and squash identities with the final Git graph.
  • Prove required commits are reachable before deleting disposable source branches and restore any changed project setting.
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. Checkpoint mission and preflight

Build one disposable integration project and produce an evidence packet showing: (1) the starting project merge method; (2) predictions for merge-commit and fast-forward history; (3) one deliberate conflict-based mergeability failure; (4) the repaired MR state; (5) final commit graphs; and (6) safe branch cleanup only after reachability checks.

  • Required: GitLab Free, Git, authenticated glab, disposable project you control.
  • Optional: Premium/Ultimate merge-train read-only observation or fixture.
  • Not required: tokens created for the lab, runners, cloud/Kubernetes, production refs, force pushes, or history rewrite.
REPO="GROUP/integration-checkpoint"
PROJECT_ID="123456"
BASE="main"
mkdir -p ch09-checkpoint-evidence

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-checkpoint-evidence/project-before.json

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

2. Write predictions before mutation

Test Prediction to write before action Independent proof after action
Merge-commit strategy Target gets a new merge commit whose parents include prior target and integrated source line. git show --pretty=raw <target> and graph.
Fast-forward strategy Target advances along source/rebased line with no merge commit. Target SHA/parents and graph.
Conflict MR MR becomes unmergeable because source/target changed the same line differently. API has_conflicts/detailed_merge_status plus local merge failure.
Cleanup Source branches can be deleted only after required commits/identities are durable and reachable. merge-base --is-ancestor, MR metadata, and remote ref checks.

3. Strategy A: merge-commit graph in a safe local mirror

The checkpoint requires a reproducible comparison but does not require changing a shared project setting twice. Use the local graph as the mandatory proof; optionally repeat in the disposable GitLab project.

rm -rf /tmp/ch09-checkpoint-graph
mkdir /tmp/ch09-checkpoint-graph && cd /tmp/ch09-checkpoint-graph
git init -b main
git config user.name "GitLab Course Lab"
git config user.email "lab@example.invalid"
printf 'A
' > history.txt
git add history.txt && git commit -m "A"
git switch -c feature-a
printf 'B
' >> history.txt && git commit -am "B"
git switch main
printf 'C
' > target-only.txt
git add target-only.txt && git commit -m "C"
git merge --no-ff feature-a -m "M: merge commit"
git log --graph --decorate --oneline --all   | tee /path/to/project/ch09-checkpoint-evidence/graph-merge-commit.txt

4. Strategy B: fast-forward graph

rm -rf /tmp/ch09-checkpoint-ff
mkdir /tmp/ch09-checkpoint-ff && cd /tmp/ch09-checkpoint-ff
git init -b main
git config user.name "GitLab Course Lab"
git config user.email "lab@example.invalid"
printf 'A
' > history.txt
git add history.txt && git commit -m "A"
git switch -c feature-b
printf 'B
' >> history.txt && git commit -am "B"
printf 'C
' >> history.txt && git commit -am "C"
git switch main
git merge --ff-only feature-b
git log --graph --decorate --oneline --all   | tee /path/to/project/ch09-checkpoint-evidence/graph-fast-forward.txt

Compare the two evidence files. The first graph contains a new integration node; the second advances the target ref along the source line.

5. Hosted failure: create one real conflict and capture the gate

cd /path/to/integration-checkpoint
git fetch origin "$BASE"
git switch -C ch09-checkpoint-target "origin/$BASE"
printf 'owner=baseline
' > ownership.txt
git add ownership.txt && git commit -m "ch09: checkpoint baseline"
git push -u origin ch09-checkpoint-target

git switch -c ch09-checkpoint-source
printf 'owner=feature
' > ownership.txt
git commit -am "ch09: feature ownership"
SOURCE_BEFORE="$(git rev-parse HEAD)"
git push -u origin ch09-checkpoint-source

git switch ch09-checkpoint-target
printf 'owner=target
' > ownership.txt
git commit -am "ch09: target ownership"
TARGET_BEFORE="$(git rev-parse HEAD)"
git push origin ch09-checkpoint-target

glab mr create -R "$REPO" --source-branch ch09-checkpoint-source   --target-branch ch09-checkpoint-target   --title "ch09 checkpoint: conflict gate"   --description "Disposable integration checkpoint." --yes
MR_IID="REPLACE_WITH_IID"

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"   --jq '{iid,sha,has_conflicts,detailed_merge_status,diff_refs}'   | tee ch09-checkpoint-evidence/mr-failed-gate.json

6. Repair only the conflict and verify mergeability again

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

git diff -- ownership.txt | tee ch09-checkpoint-evidence/conflict-diff.txt
printf 'owner=feature-and-target
' > ownership.txt
git add ownership.txt
git commit -m "ch09: reconcile ownership semantics"
RESOLVED_SHA="$(git rev-parse HEAD)"
git push origin ch09-checkpoint-source

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,head_pipeline}'     | tee "ch09-checkpoint-evidence/mr-recheck-$i.json"
  sleep 2
done

If another gate now blocks merge—pipeline, discussions, approvals, draft state—do not bypass it. Record the new detailed_merge_status and address that control separately. The checkpoint requires diagnosing the responsible gate, not forcing a green button.

7. Merge only after predictions and identity checks

Use the project’s existing merge method unless this is a disposable project where you explicitly changed it. Before selecting Merge, capture the current source and target SHAs. After merge, record all MR identity fields and the remote target.

git fetch origin ch09-checkpoint-target
TARGET_PREMERGE="$(git rev-parse origin/ch09-checkpoint-target)"
SOURCE_PREMERGE="$(git rev-parse origin/ch09-checkpoint-source)"
printf 'source_premerge=%s
target_premerge=%s
'   "$SOURCE_PREMERGE" "$TARGET_PREMERGE"   | tee ch09-checkpoint-evidence/premerge-identities.txt

# Merge through the GitLab UI only after all configured checks pass.
# Then inspect:
glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"   --jq '{iid,state,sha,merge_commit_sha,squash_commit_sha,merged_at,target_branch}'   | tee ch09-checkpoint-evidence/mr-merged.json

git fetch origin ch09-checkpoint-target
TARGET_POST="$(git rev-parse origin/ch09-checkpoint-target)"
printf 'target_post=%s
' "$TARGET_POST"   | tee ch09-checkpoint-evidence/postmerge-target.txt

git log --graph --decorate --oneline --all -n 40   | tee ch09-checkpoint-evidence/hosted-graph-after.txt

8. Optional merge-train reasoning checkpoint

Without a paid tier, use this fixture. Predict which candidate each pipeline represents and what happens if MR201 fails.

merge_train_fixture:
  target: main
  entries:
    - iid: 201
      candidate: main + 201
      pipeline: passed
    - iid: 202
      candidate: main + 201 + 202
      pipeline: passed
    - iid: 203
      candidate: main + 201 + 202 + 203
      pipeline: running

If MR201 fails or leaves the train, later candidates no longer represent the correct order and must be recalculated/revalidated according to current train behavior. That is why a train is integration machinery, not just a visual queue.

9. Prove reachability before cleanup

Do not assume the source tip is an ancestor when squash was used. Check the MR identity fields first. If no squash occurred and the source commits were preserved, an ancestry test is appropriate. If squash occurred, preserve squash_commit_sha and the MR evidence before deleting the source pointer.

# Example when source commits are expected to remain in target history:
if git merge-base --is-ancestor "$SOURCE_PREMERGE" "$TARGET_POST"; then
  echo "source tip reachable from target"
else
  echo "source tip not an ancestor; inspect squash/rebase/merge identities before cleanup"
fi

git ls-remote origin refs/heads/ch09-checkpoint-source refs/heads/ch09-checkpoint-target
Cleanup is destructive only to the named disposable refs. Preserve the evidence packet first. Never delete the default branch, protected production refs, or rewrite history for this lab.
# Delete only after verifying the MR is merged/closed and evidence is captured.
if git ls-remote --exit-code --heads origin ch09-checkpoint-source >/dev/null 2>&1; then
  git push origin --delete ch09-checkpoint-source
fi
if git ls-remote --exit-code --heads origin ch09-checkpoint-target >/dev/null 2>&1; then
  git push origin --delete ch09-checkpoint-target
fi

git switch "$BASE"
for b in ch09-checkpoint-source ch09-checkpoint-target; do
  if git show-ref --verify --quiet "refs/heads/$b"; then git branch -D "$b"; fi
done

10. Hash the evidence packet

python - <<'PY2'
from pathlib import Path
import hashlib, json, datetime
root=Path('ch09-checkpoint-evidence')
rows=[]
for p in sorted(root.glob('*')):
    if p.is_file():
        rows.append({'file':p.name,'bytes':p.stat().st_size,'sha256':hashlib.sha256(p.read_bytes()).hexdigest()})
out={'captured_at_utc':datetime.datetime.now(datetime.timezone.utc).isoformat(),'files':rows}
Path('ch09-checkpoint-manifest.json').write_text(json.dumps(out,indent=2)+'
')
PY2
cat ch09-checkpoint-manifest.json

11. What Chapter 09 adds to the production model

You can now separate authorization to integrate from integration mechanics. A production policy can name the expected target graph, identify which pipeline context is acceptable evidence, require semantic conflict resolution, capture source/target/merge/squash identities, and delete short-lived branches only after durable proof exists.

Chapter 10 builds directly on that model by explaining how .gitlab-ci.yml, pipelines, jobs, stages, events, and runners produce the CI evidence that mergeability and integration decisions consume.

Knowledge check

What did the failed conflict MR prove?

Why are two local graph demonstrations included?

If squash was used, why can merge-base ancestry from source tip to target fail?

What should happen if fixing the conflict reveals a pipeline gate?

What evidence links the reviewed change to the final target?

What is the bridge to Chapter 10?

Checkpoint summary

You predicted two histories, captured a real conflict-based mergeability failure, repaired only the responsible cause, compared MR/API identities with the final graph, modeled merge-train ordering without a paid requirement, verified reachability/identity before cleanup, and hashed the evidence packet. Integration is now an auditable state transition rather than a click on Merge.

Official references

Chapter 10

GitLab CI/CD foundations

Chapter 10 introduces .gitlab-ci.yml, pipeline and job execution, stages, events, runners, logs, and the execution model behind the CI evidence used throughout merge governance.

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.