Chapter 07Lesson 05~235 minutes

Checkpoint Lab — Merge Requests, Drafts, Review Threads, Suggestions, and Change Collaboration

Execute a complete disposable issue-to-branch-to-draft-MR-to-review-to-merge workflow, predict commit identity and issue state, preserve independent evidence, diagnose one stale discussion, and clean up safely.

CheckpointIssue → MRPredictionsEvidenceMerge identityChapter 08 bridge

Learning objectives

  • Run one complete Free-compatible issue → branch → draft MR → review suggestion → ready → merge workflow in a disposable project.
  • Predict source/target commit identity and linked-issue state before each consequential transition.
  • Use UI, local Git, glab, and REST as independent evidence surfaces rather than relying on one green widget.
  • Diagnose one deliberately stale/unresolved review condition before merge and repair it without bypassing policy.
  • Produce a compact evidence packet and perform targeted cleanup without deleting the project or rewriting history.
Availability baseline (verified 2026-08-21). Core merge requests, draft/ready state, reviewers, comments/review threads, suggestions, basic approvals, branch/fork workflows, merge-request pipelines, the Merge Requests/Discussions REST APIs, and the glab mr command family are documented for Free/Premium/Ultimate on GitLab.com, Self-Managed, and Dedicated. On GitLab Free, eligible users can approve an MR, but approvals are optional and do not enforce a merge gate; required approval rules are Premium/Ultimate. Draft MRs cannot merge until marked ready, but by default they run the same MR pipelines as ready MRs. Current fork-pipeline behavior and protected-resource rules are version-sensitive, so production policy must be checked against the deployed GitLab version.

1. Checkpoint mission and preflight

Your goal is to deliver one tiny documentation change with a traceable reason and a reviewable source identity. The lab remains deliberately small so you can focus on causality rather than application complexity.

  • Project: disposable GitLab.com Free project you own.
  • Local tools: Git + current glab; sha256sum is optional but useful for evidence integrity.
  • Role: sufficient to create branch/MR and merge into the disposable target under its existing protection rules.
  • Second reviewer: optional existing test collaborator. Do not grant new access solely for this exercise.
  • No paid dependencies: required approval rules, Code Owners, merge trains, privileged runners, protected variables, Dedicated administration, Kubernetes, cloud, and AI are not required.

2. Predict the state transitions before touching GitLab

Checkpoint state transitions
flowchart TD
I[Open synthetic issue] --> B[Feature branch at base SHA]
B --> C[New commit / source SHA]
C --> D[Draft MR: target unchanged]
D --> R[Review thread + suggestion]
R --> S[Apply suggestion: new source SHA]
S --> U[Ready state]
U --> E{Evidence current?}
E -->|No| FIX[Re-review / repair]
FIX --> E
E -->|Yes| M[Merge exact reviewed SHA]
M --> T[Target branch changes]
M --> Q[Issue closes if default-branch closing semantics apply]
T --> X[Cleanup source branch + archive evidence]
Q --> X

Write down at least two predictions now: (1) draft-MR creation will not move the target branch; (2) applying the suggestion will move the source branch; (3) merge will move the target branch; (4) the linked issue should close only if the closing pattern reaches the default branch under current project settings.

3. Set up evidence directory and capture baseline

REPO="GROUP/ch07-checkpoint"
PROJECT_ID="123456"
DEFAULT="main"      # verify from project; change if needed
BRANCH="ch07-checkpoint-change"
mkdir -p ch07-checkpoint

glab auth status
glab repo view -R "$REPO" --output json   --jq '{path_with_namespace,visibility,default_branch}'   | tee ch07-checkpoint/project.json

git fetch origin --prune
git status --short
BASE_SHA="$(git rev-parse "origin/$DEFAULT")"
printf 'base_sha=%s
' "$BASE_SHA" | tee ch07-checkpoint/01-base.txt

4. Create the traceable work item

Create a synthetic issue titled CH07 checkpoint: document probe behavior. Record the actual IID in ISSUE_IID. The issue is the problem statement; it is not the code change.

glab issue create -R "$REPO"   --title "CH07 checkpoint: document probe behavior"   --description "Synthetic Chapter 07 checkpoint issue. No production data."   --yes
ISSUE_IID="21"  # replace with actual IID

glab issue view "$ISSUE_IID" -R "$REPO" | tee ch07-checkpoint/02-issue.txt

5. Create the branch and first commit

git switch -c "$BRANCH" "origin/$DEFAULT"
printf '
## Probe behavior

Synthetic checkpoint text.
' >> README.md
git add README.md
git commit -m "docs: add CH07 checkpoint probe note"
git push -u origin "$BRANCH"

FIRST_SOURCE_SHA="$(git rev-parse HEAD)"
printf 'first_source_sha=%s
' "$FIRST_SOURCE_SHA" | tee ch07-checkpoint/03-source-first.txt

Verify origin/$DEFAULT is still $BASE_SHA. If not, stop and determine what else updated the branch; do not attribute an unrelated push to your feature branch.

6. Create a draft MR with linked intent

glab mr create -R "$REPO"   --source-branch "$BRANCH"   --target-branch "$DEFAULT"   --title "CH07 checkpoint: probe documentation"   --description "Closes #$ISSUE_IID

Synthetic checkpoint. Review the exact source SHA before merge."   --draft --yes

# Find and record the actual IID from this source branch.
glab mr list -R "$REPO" --source-branch "$BRANCH" --output json   | tee ch07-checkpoint/04-mr-list.json
MR_IID="9"  # replace with actual IID

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"   --jq '{iid,state,draft,source_branch,target_branch,sha,diff_refs,detailed_merge_status,head_pipeline}'   | tee ch07-checkpoint/05-mr-draft.json

Verification: target branch remains at the baseline SHA; MR is draft; MR SHA equals the remote feature branch; no claim is made about CI if no pipeline exists.

7. Create a deliberate review concern and suggestion

In the Changes view, add a resolvable diff thread: “The heading should make the training-only nature explicit.” Capture the unresolved discussion through the REST API.

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID/discussions" --paginate   --jq '.[] | {id,notes:[.notes[] | {id,type,resolvable,resolved,body}]}'   | tee ch07-checkpoint/06-discussions-unresolved.json

Now add a suggestion that changes the heading to ## Training-only probe behavior. Before applying it, record the source SHA. Apply the suggestion in the UI, then fetch and prove the new commit.

PRE_SUGGEST="$(glab api "projects/$PROJECT_ID/merge_requests/$MR_IID" --jq '.sha')"
printf 'pre_suggest=%s
' "$PRE_SUGGEST" | tee ch07-checkpoint/07-pre-suggest.txt

# Apply the synthetic suggestion in the GitLab UI, then:
git fetch origin "$BRANCH"
POST_SUGGEST="$(git rev-parse "origin/$BRANCH")"
printf 'post_suggest=%s
' "$POST_SUGGEST" | tee ch07-checkpoint/08-post-suggest.txt

test "$PRE_SUGGEST" != "$POST_SUGGEST" || { echo "Expected a new suggestion commit"; exit 1; }
git show --format=fuller --stat "$POST_SUGGEST" | tee ch07-checkpoint/09-suggestion-commit.txt

8. Diagnose one deliberately stale discussion condition

Create a second review thread that says “Verify the sentence ends with a period.” Then deliberately leave it unresolved even after the text is already correct. This is a stale review signal: code state and discussion state disagree.

Inspect the discussion and source diff. If the code is objectively correct, reply with the evidence and resolve the thread. Do not make a meaningless code edit just to produce a commit.

CURRENT_SHA="$(glab api "projects/$PROJECT_ID/merge_requests/$MR_IID" --jq '.sha')"
glab mr diff "$MR_IID" -R "$REPO" | tee ch07-checkpoint/10-current-diff.txt
glab mr view "$MR_IID" -R "$REPO" --comments --unresolved   | tee ch07-checkpoint/11-unresolved-view.txt

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID/discussions" --paginate   | tee ch07-checkpoint/12-discussions-before-resolution.json

Resolve only after the evidence shows the concern is satisfied. Then record the discussion state again. The source SHA should remain unchanged if this was truly a stale discussion rather than a code defect.

9. Mark ready and prove the reviewed head

glab mr update "$MR_IID" -R "$REPO" --ready --yes

REVIEWED_SHA="$(glab api "projects/$PROJECT_ID/merge_requests/$MR_IID" --jq '.sha')"
glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"   --jq '{iid,draft,sha,detailed_merge_status,source_branch,target_branch,reviewers,head_pipeline}'   | tee ch07-checkpoint/13-ready.json

# Independent remote proof.
REMOTE_SOURCE_SHA="$(git ls-remote origin "refs/heads/$BRANCH" | awk '{print $1}')"
test "$REVIEWED_SHA" = "$REMOTE_SOURCE_SHA" && echo "MR head equals remote source head"

10. Final predictions before merge

  • Target SHA: must change if the MR actually merges.
  • Source SHA: must remain the exact reviewed SHA at the moment you authorize merge.
  • MR state: becomes merged, not merely closed.
  • Issue: should close if the closing reference reaches the default branch and auto-closing is enabled.
  • Source branch: should be removed if you choose the remove-source-branch option.
TARGET_BEFORE="$(git ls-remote origin "refs/heads/$DEFAULT" | awk '{print $1}')"
printf 'reviewed_sha=%s
target_before=%s
' "$REVIEWED_SHA" "$TARGET_BEFORE"   | tee ch07-checkpoint/14-final-predictions.txt

11. Merge the exact reviewed SHA and verify independently

glab mr merge "$MR_IID" -R "$REPO"   --sha "$REVIEWED_SHA"   --remove-source-branch   --auto-merge=false   --yes

git fetch origin --prune
TARGET_AFTER="$(git rev-parse "origin/$DEFAULT")"
printf 'target_after=%s
' "$TARGET_AFTER" | tee ch07-checkpoint/15-target-after.txt

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID"   --jq '{iid,state,merged_at,sha,merge_commit_sha,squash_commit_sha,source_branch,target_branch}'   | tee ch07-checkpoint/16-mr-merged.json

glab issue view "$ISSUE_IID" -R "$REPO"   | tee ch07-checkpoint/17-issue-after.txt

git log --oneline --decorate -5 "origin/$DEFAULT"   | tee ch07-checkpoint/18-target-log.txt

If the merge command refuses because --sha no longer matches, that is a successful safety control. Do not bypass it; inspect the new source commit and repeat review evidence.

12. Build the evidence packet

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID/discussions" --paginate   > ch07-checkpoint/19-discussions-final.json

glab api "projects/$PROJECT_ID/merge_requests/$MR_IID/commits" --paginate   > ch07-checkpoint/20-commits-final.json

sha256sum ch07-checkpoint/* > ch07-checkpoint/SHA256SUMS.txt
cat ch07-checkpoint/SHA256SUMS.txt

The hashes prove whether your local evidence packet changes after capture; they do not make the API response “trusted” by themselves. Your claims are strongest when multiple independent surfaces agree on the same source/target identities.

13. Cleanup and rollback boundaries

The merge itself is intentionally retained as training history. Cleanup only disposable transient resources:

  • Return the local worktree to the default branch and delete the local feature branch.
  • Verify the remote source branch is gone if --remove-source-branch was accepted.
  • Keep the closed issue/MR and evidence packet if useful for Chapter 08; otherwise archive the evidence outside any public repository.
  • Do not delete the whole project, rewrite the merged history, alter protected-branch policy, or create a bypass to “undo” the lab.
git switch "$DEFAULT"
git branch -D "$BRANCH" 2>/dev/null || true
git remote prune origin

git ls-remote --heads origin "$BRANCH"
git status --short

14. What Chapter 07 adds to the production operating model

The operating model now has a governed change-convergence layer. Chapters 01–06 established platform boundaries, credentials, project defaults, namespace access, planning, and collaboration surfaces. Chapter 07 ties a proposed source revision to a target branch, review evidence, CI state, discussions, and delivery intent.

Chapter 08 will turn this collaborative process into enforceable governance: approval rules, CODEOWNERS, protected branches/tags, push rules, and merge constraints. The distinction matters: Chapter 07 teaches how people collaborate around a change; Chapter 08 teaches which controls may prevent an unsafe change from completing.

Knowledge check

The merge fails because the source SHA changed after you captured REVIEWED_SHA. What should you do?

You resolve the stale punctuation thread and the MR head SHA stays the same. Is that automatically suspicious?

The issue remains open after the MR merges. Which facts should you inspect before manually closing it?

Why keep both REST MR JSON and local git log evidence?

What chapter comes next, and what new problem does it solve?

Which paid feature was intentionally not required in this checkpoint?

Checkpoint summary

You completed an end-to-end GitLab change with explicit source/target identity, draft state, linked work, review thread, applied suggestion, stale-discussion diagnosis, ready transition, exact-SHA merge guard, default-branch verification, linked-issue inspection, evidence hashing, and targeted cleanup. The workflow is now ready to receive Chapter 08’s enforceable approval and protected-ref governance.

Official references

Chapter 08

Approvals, CODEOWNERS, protected branches and tags, push rules, and merge governance

The next chapter builds enforceable policy around the collaborative merge-request workflow you just operated, while keeping Free versus Premium/Ultimate boundaries explicit.

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.