Checkpoint Lab — Branches, Fast-Forward and Three-Way Merges, and Branching Strategies
Checkpoint the branch/merge model with mainline, feature and hotfix work, a fast-forward, a three-way merge, a conflict resolution, reachability checks, strategy comparison, and a small-team branching policy.
Learning objectives
- Build and verify a mainline/feature/hotfix graph with both fast-forward and true merge integration.
- Predict merge eligibility and ref movement before running integration commands.
- Engineer, inspect, and resolve a controlled merge conflict.
- Prove integrated commits remain reachable after deleting merged topic refs.
- Document a small-team branching policy and compare merge/squash/rebase alternatives without rewriting shared history.
1. Checkpoint scenario — a small team with feature and hotfix work
You will build one trunk mainline, integrate a short
feature with a fast-forward, create a second feature that diverges
while a hotfix advances trunk, integrate that feature with a true
merge, then engineer and resolve one conflict. Everything stays in a
disposable local repository.
2. Predictions before mutation
-
If trunk does not move after creating
feature/health, willgit merge --ff-only feature/healthcreate a new commit? -
If
feature/alertsand trunk each gain a different commit after their common base, can--ff-onlyintegrate the feature? - After deleting a merged feature branch, should its integrated commits still be reachable from trunk?
- If both sides edit the same policy line differently, what state should Git enter?
3. Setup and preflight
Git Bash / Bash / zsh
mkdir git-branch-checkpoint
cd git-branch-checkpoint
git init -b trunk
git config user.name "Branch Checkpoint"
git config user.email "branch-checkpoint@example.invalid"
printf "service=api
health=none
" > service.conf
printf "policy=balanced
" > deploy.conf
git add service.conf deploy.conf
git commit -m "Create deployment baseline"
git status --short --branch
git log --graph --decorate --oneline --all
4. Feature 1 — observe a fast-forward integration
git switch -c feature/health
printf "service=api
health=/healthz
" > service.conf
# PowerShell: @('service=api','health=/healthz') | Set-Content service.conf
git add service.conf
git commit -m "Expose API health endpoint"
HEALTH=$(git rev-parse HEAD)
git switch trunk
git merge-base --is-ancestor trunk feature/health
git merge --ff-only feature/health
git rev-parse trunk
git log --graph --decorate --oneline --all
Expected: trunk moves to the existing health commit. No two-parent merge commit is created.
5. Feature 2 and hotfix — create divergence
git switch -c feature/alerts
printf "alerts=latency
" > alerts.conf
# PowerShell: Set-Content alerts.conf 'alerts=latency'
git add alerts.conf
git commit -m "Add latency alert configuration"
ALERTS=$(git rev-parse HEAD)
git switch trunk
git switch -c hotfix/timeout
printf "request_timeout=30s
" > timeout.conf
# PowerShell: Set-Content timeout.conf 'request_timeout=30s'
git add timeout.conf
git commit -m "Set production request timeout"
HOTFIX=$(git rev-parse HEAD)
git switch trunk
git merge --ff-only hotfix/timeout
git branch -d hotfix/timeout
git log --graph --decorate --oneline --all
git merge-base trunk feature/alerts
The feature and trunk now diverge from the health commit: trunk contains the hotfix; the feature contains the alert commit.
6. Predict failure of --ff-only, then create the true
merge
git merge --ff-only feature/alerts
# Expected: refusal because histories have diverged.
git merge feature/alerts -m "Merge latency alerts"
MERGE_ALERTS=$(git rev-parse HEAD)
git cat-file -p HEAD
git rev-parse HEAD^1
git rev-parse HEAD^2
git log --graph --decorate --oneline --all
The first command is a safe precondition check: it refuses without integrating. The second creates a two-parent merge commit because a fast-forward cannot preserve both lines.
7. Engineer and inspect a small conflict
git switch -c feature/strict-deploy
printf "policy=strict
" > deploy.conf
# PowerShell: Set-Content deploy.conf 'policy=strict'
git add deploy.conf
git commit -m "Require strict deployment policy"
git switch trunk
printf "policy=conservative
" > deploy.conf
# PowerShell: Set-Content deploy.conf 'policy=conservative'
git add deploy.conf
git commit -m "Prefer conservative deployment policy"
git merge feature/strict-deploy
git status
git diff --name-only --diff-filter=U
git ls-files -u
Both sides edited the same logical line differently, so Git cannot infer the desired policy.
8. Resolve the conflict intentionally
Choose the team-approved result explicitly. For this disposable lab,
write policy=strict-with-fallback:
printf "policy=strict-with-fallback
" > deploy.conf
# PowerShell: Set-Content deploy.conf 'policy=strict-with-fallback'
git add deploy.conf
git status
git diff --staged
git merge --continue
git log --graph --decorate --oneline --all
If the editor opens, keep or improve the merge message so it explains the integration decision. The staged file is the actual proposed merge snapshot.
9. Delete merged topic refs and verify reachability
git merge-base --is-ancestor "$HEALTH" trunk
git merge-base --is-ancestor "$ALERTS" trunk
git branch --merged trunk
git branch -d feature/health
git branch -d feature/alerts
git branch -d feature/strict-deploy
git branch --list
git log --graph --decorate --oneline --all
The graph remains; only the short-lived names disappear.
10. Compare graph shapes without rewriting this shared-style checkpoint
| Alternative | Conceptual result | What you would lose/change |
|---|---|---|
| True merge (used here) | Two-parent integration commit | Keeps feature ancestry and graph divergence visible |
| Squash integration | One new single-parent commit with combined feature content | Feature commits are not ancestors of trunk |
| Rebase then fast-forward | Linear sequence replayed on updated trunk | Feature commit IDs change during rebase |
Do not rewrite the checkpoint history just to produce all three shapes in one repository. Chapter 09 provides controlled rebase labs. The learning goal here is to choose a shape deliberately before integration.
11. Write a small-team branching policy
Create BRANCHING_POLICY.md with rules like these,
adjusted to your own delivery constraints:
# Branching policy
- trunk is the only long-lived development branch and should remain releasable.
- feature/* and fix/* branches should normally live less than 2 working days.
- integrate only after tests and review pass.
- prefer fast-forward when no explicit integration record is required.
- use a merge commit when preserving branch ancestry/integration context is valuable.
- create release branches only when multiple supported release lines require them.
- never force-rewrite shared trunk as routine cleanup.
git add BRANCHING_POLICY.md
git diff --staged
git commit -m "Document short-lived branch policy"
12. Produce a compact verification report
git status --short --branch
git branch --list
git log --graph --decorate --oneline --all
git rev-list --merges --oneline trunk
git show --no-patch --format=raw "$MERGE_ALERTS"
git merge-base --is-ancestor "$HOTFIX" trunk
This answers: Is the repository clean? Which refs remain? Where are merge commits? Did the alerts merge have two parents? Is the hotfix still in trunk ancestry?
13. Verification checklist
- One feature integration was a fast-forward with no extra merge commit.
- The hotfix advanced trunk before the second feature integrated.
-
feature/alertscould not be fast-forwarded into trunk after divergence. - The alerts integration produced a two-parent merge commit.
- The deployment-policy conflict was inspected before resolution.
- The resolved file was staged and reviewed before completing the merge.
-
Merged short-lived branch refs were deleted with
-d, not forced. - Integrated feature/hotfix commit OIDs remain ancestors of trunk.
- A branching policy was documented from actual team constraints.
- No shared-history rewrite or destructive cleanup command was used.
14. Cleanup
Git Bash / Bash / zsh
git status --short --branch
cd ..
pwd
rm -rf git-branch-checkpoint
PowerShell
git status --short --branch
Set-Location ..
Get-Location
Remove-Item -Recurse -Force git-branch-checkpoint
15. Knowledge check
Question 1. Why did the health integration not create a merge commit?
Question 2. Why did --ff-only refuse the alerts
integration?
Question 3. After deleting feature/alerts, how can
its work still be present?
Question 4. A merge reports no textual conflict but tests fail. Is that contradictory?
Question 5. Why not rebase this already integrated checkpoint merely to make the graph linear?
16. What Chapter 06 adds to a production Git operating model
You can now reason about branch refs, ancestry, merge bases, fast-forward eligibility, true merge commits, conflict state, safe branch deletion, and the operational consequences of branch lifetime. That lets you design integration policy around release/support constraints rather than command folklore.
17. Chapter checkpoint summary
A branch is a movable ref, a merge is a graph integration, and a strategy is a governance choice. Short feedback loops and explicit integration rules generally reduce delivery risk; long-lived branches are justified only when the product's release/support model requires them.
Authoritative references
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.