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.
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.
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
# 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?
That GitLab’s mergeability gate blocked integration because the source and target had incompatible changes; it did not prove anything about paid approvals or merge trains.
Why are two local graph demonstrations included?
They make merge-commit versus fast-forward history observable without requiring repeated project-wide setting changes.
If squash was used, why can merge-base ancestry from source tip to target fail?
The target may contain a new squash commit instead of the original source commits, so identity verification must use MR squash/merge metadata rather than a naive ancestry assumption.
What should happen if fixing the conflict reveals a pipeline gate?
Preserve the new status and satisfy the pipeline requirement separately; never bypass an unrelated gate just to finish the lab.
What evidence links the reviewed change to the final target?
Source SHA, pre/post target SHAs, MR IID/state, merge_commit_sha/squash_commit_sha as applicable, and the final Git graph.
What is the bridge to Chapter 10?
The next chapter explains how GitLab CI/CD creates the pipeline/job evidence that mergeability and integration policies rely on.
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
- 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.