Pull Requests and Code Review¶
Overview¶
Pull requests (PRs) — merge requests on GitLab — are the collaboration hub where code meets review, CI runs, and changes merge to protected branches. For DevOps teams managing Terraform, Kubernetes YAML, and pipeline configs, PRs enforce four-eyes principles and audit trails required by compliance frameworks.
This is Tutorial 11 in Module 4: Collaboration of the REBASH Academy Git series.
Prerequisites¶
Learning Objectives¶
By the end of this tutorial, you will be able to:
- Open and describe effective pull requests
- Request reviews and respond to feedback constructively
- Interpret CI status checks on PRs
- Choose merge strategies (merge, squash, rebase)
- Configure and work within protected branch rules
- Review IaC changes with security and blast-radius mindset
- Link PRs to tickets and deployment traceability
PR Lifecycle Diagram¶
flowchart LR
BR[Feature Branch] -->|push| PR[Open Pull Request]
PR --> CI[CI Checks Run]
CI --> REV[Code Review]
REV -->|approve| MERGE[Merge to main]
REV -->|changes requested| BR
MERGE --> DEPLOY["CD / GitOps Deploy"] Theory¶
What Is a Pull Request?¶
A PR is a request to merge one branch into another, with:
- Diff of all changes
- Description and linked issues
- Review comments on specific lines
- CI/CD status checks
- Merge button (when requirements met)
PRs are platform features (GitHub/GitLab) — not native Git commands — but they drive Git operations under the hood.
Opening a Strong PR¶
Title: Conventional commit style — feat(iam): add S3 bucket policy for logging
Description template:
## Summary
- Add CloudWatch log bucket with encryption
- Update IAM role for Lambda write access
## Test plan
- [ ] terraform plan shows expected resources
- [ ] validate in dev account
- [ ] security scan passed
## Ticket
JIRA-4521
Small PRs (< 400 lines changed) merge faster and review better.
Review Roles¶
| Role | Responsibility |
|---|---|
| Author | Clear description; respond to feedback; keep CI green |
| Reviewer | Check correctness, security, tests; approve or request changes |
| CODEOWNERS | Auto-assigned reviewers for path ownership |
CODEOWNERS Example¶
Platform auto-requests reviewers when PR touches owned paths.
CI on Pull Requests¶
Typical checks:
- Lint (terraform fmt, yamllint)
- Unit/integration tests
terraform plan(posted as comment)- Security scan (Checkov, tfsec)
- Required status checks before merge
Failed CI blocks merge on protected branches.
Merge Strategies on Platform¶
| Strategy | Result |
|---|---|
| Create merge commit | Preserves branch; adds merge commit |
| Squash and merge | One commit on main |
| Rebase and merge | Linear history; replays commits |
Team policy should document chosen strategy. Many DevOps repos prefer squash or rebase for clean main.
Protected Branches¶
Rules commonly enforced:
- Require PR before merge (no direct push)
- Require N approvals
- Require CI pass
- Require signed commits
- Restrict force push
- Require linear history
Applies to main, production, release branches.
Reviewing IaC and DevOps Changes¶
Checklist for Terraform/K8s PRs:
- Blast radius — what breaks if wrong?
- Secrets — no plaintext credentials
- Idempotency — plan shows only intended changes
- Rollback — can we revert?
- Environment scope — dev vs prod paths correct?
- Cost impact — new resources priced?
Draft PRs¶
Mark WIP PRs as Draft — signals reviewers to wait. Convert to ready when CI green and self-review done.
Review Etiquette¶
- Comment on code, not people
- Suggest alternatives (
nit:,blocking:prefixes help) - Authors: don't take feedback personally; batch fixes in commits
- Resolve conversations when addressed
Platform-Specific Notes¶
| Platform | PR name | Unique features |
|---|---|---|
| GitHub | Pull Request | CODEOWNERS, merge queue, auto-merge, Copilot review |
| GitLab | Merge Request | Approval rules, security scanning, "merge when pipeline succeeds" |
| Bitbucket | Pull Request | Jira smart commits, default reviewers |
| Azure DevOps | Pull Request | Work item linking, branch policies |
Regardless of platform, the Git operations underneath — push branch, diff against base, merge — are identical. Skills from this tutorial transfer when your organization changes hosting providers.
Required Status Checks¶
Configure required checks that must pass before merge:
terraform-plan— no destructive changes without approvalunit-tests— application logic verifiedsecret-scan— gitleaks or platform native scannerlint— formatting and static analysis
Failed required checks display a blocked merge button. Optional checks show warnings but allow merge — use sparingly to avoid alert fatigue.
Hands-on Lab¶
Step 1 – Prepare feature branch (local simulation)¶
Command:
mkdir -p /tmp/git-pr-lab && cd /tmp/git-pr-lab
git init -b main
echo "# App" > README.md && git add . && git commit -m "docs: initial README"
git init --bare /tmp/pr-remote.git
git remote add origin /tmp/pr-remote.git
git push -u origin main
git switch -c feature/add-healthcheck
cat > healthcheck.sh << 'EOF'
#!/usr/bin/env bash
curl -sf http://localhost:8080/health || exit 1
EOF
chmod +x healthcheck.sh
git add healthcheck.sh && git commit -m "feat: add healthcheck script"
Step 2 – Push feature branch¶
Command:
git push -u origin feature/add-healthcheck
git log main..feature/add-healthcheck --oneline
git diff main...feature/add-healthcheck --stat
Explanation: Three-dot diff shows PR diff scope — what reviewers see.
Step 3 – Simulate review feedback¶
Command:
# Reviewer suggests timeout flag
git commit --amend -m "feat: add healthcheck script with curl timeout"
sed -i.bak 's/curl -sf/curl -sf --max-time 5/' healthcheck.sh 2>/dev/null || \
sed -i 's/curl -sf/curl -sf --max-time 5/' healthcheck.sh
git add healthcheck.sh && git commit --amend --no-edit
git push --force-with-lease origin feature/add-healthcheck
Step 4 – Merge (simulating platform merge)¶
Command:
git switch main
git pull origin main
git merge --no-ff feature/add-healthcheck -m "Merge pull request #1: add healthcheck"
git push origin main
git log --oneline --graph -5
Step 5 – Clean up¶
Command:
Commands & Code¶
| Command | Description | Example |
|---|---|---|
git push -u origin branch | Publish branch for PR | First push of feature branch |
git diff main...feature | PR-scope diff | Review before opening |
git log main..feature | Commits in PR | PR description helper |
git push --force-with-lease | Update PR after amend/rebase | After review fixes |
gh pr create | Open PR (GitHub CLI) | gh pr create --fill |
gh pr checkout 123 | Checkout PR locally | Review locally |
PR description generator¶
#!/usr/bin/env bash
# pr-summary.sh — generate PR summary from commits
set -euo pipefail
BASE="${1:-main}"
git log "$BASE"..HEAD --oneline
echo ""
git diff "$BASE"...HEAD --stat
Common Mistakes¶
Huge PRs with unrelated changes
Split infra module refactor from one-line fix. Reviewers miss critical issues in 2000-line diffs.
Merging with failing CI
Bypassing checks defeats purpose of protected branches. Fix or waive with documented exception.
Self-approval on sensitive changes
SOC 2 requires independent review — configure branch rules to block author approval.
No test plan in IaC PRs
Always include expected terraform plan output or kubectl diff summary.
Best Practices¶
Link every PR to a ticket
Audit trail from incident → deploy → commit → ticket.
Use draft PRs for early feedback
Architecture direction before full implementation saves rework.
Automate plan output in PR comments
Terraform Cloud, Atlantis, and similar tools post plan diffs automatically.
Set review SLA
Platform teams target 24h review turnaround — unblocks delivery.
Troubleshooting¶
| Issue | Cause | Solution |
|---|---|---|
| Cannot merge — checks pending | CI still running | Wait or re-run failed jobs |
| Merge conflicts on PR | Main advanced | Rebase/merge main into feature branch |
| Reviewer not assigned | CODEOWNERS missing/wrong | Fix CODEOWNERS path |
| Force push rejected | Branch protection | Push new commits instead of amend |
| Stale PR | Long-lived branch | Rebase onto main; resolve conflicts |
| Wrong base branch | PR targets release not main | Change base on platform |
Summary¶
- Pull requests integrate review, CI, and merge into one workflow
- Strong PRs have clear titles, summaries, test plans, and small diffs
- Protected branches enforce approvals, CI, and no direct pushes
- Merge strategies (merge commit, squash, rebase) affect main history — document team policy
- IaC review focuses on blast radius, secrets, plan output, and rollback path
Interview Questions¶
- What is a pull request, and how does it differ from
git merge? - What should a good PR description include for a Terraform change?
- What are protected branch rules, and why use them?
- Compare squash merge vs merge commit for main branch.
- What is CODEOWNERS, and how does it work?
- How do CI status checks integrate with pull requests?
- What is a three-dot diff, and why is it used in PRs?
- When should you use draft pull requests?
- How do you update a PR after rebase or amend?
- What should reviewers look for in Kubernetes manifest PRs?
Sample Answers (Questions 1 and 4)
Q1 — PR vs git merge: A pull request is a platform workflow wrapping Git operations — it displays diffs, collects reviews, runs CI, and provides a merge button. git merge is the underlying Git command that integrates branches. PR adds governance layer required for team and compliance workflows.
Q4 — Squash vs merge commit: Merge commit preserves full feature branch history and adds explicit merge node — good for tracing branch work. Squash combines all feature commits into one on main — cleaner log, easier revert of entire feature, but loses granular commit history on main.
Related Tutorials¶
- Working with Remotes (previous)
- gitignore and gitattributes (next)
- Advanced Git Workflows
- Git in CI/CD and DevOps
- Signed Commits and Git Security