Chapter 07Lesson 04~145 minutes

Pull Requests, Drafts, Linked Issues, Change Sets, and Collaboration Patterns: Diagnostics, Failure Modes, Security, and Performance

Diagnose pull requests from preserved base/head/ref evidence when the wrong branch, unrelated commits, force-pushes, closing keywords, checks, or deployment assumptions make the hosted review object misleading or unsafe.

DiagnosticsWrong baseHistory riskChecks

Learning objectives

  • Apply a repeatable diagnostic sequence to wrong base/head, unrelated-commit, stale-review, and policy/check failures.
  • Engineer an intentionally misleading pull request whose topic branch contains an unrelated base commit and repair it without hiding the cause.
  • Distinguish changing PR metadata/base from rewriting Git history and know when each correction is appropriate.
  • Explain why force-pushing during active review is a communication and evidence hazard even when technically permitted.
  • Prevent accidental Issue closure caused by closing keywords and distinguish approval/check success from deployment success.
  • Keep destructive/security-sensitive GitHub and Git operations isolated to disposable resources with explicit recovery context.
Availability: The mandatory failure lab uses one GitHub.com public disposable repository on GitHub Free. No branch protection, paid CI, enterprise audit log, or second reviewer is required. Policy-dependent failures are also shown as realistic evidence fixtures.
Shell portability: multi-line examples with trailing \, command substitution such as $(...), and printf are labeled Git Bash/Bash/zsh. In PowerShell, use the same Git/gh arguments on one line or use the backtick for line continuation; PowerShell-native alternatives are shown for the key file-writing steps. The GitHub resource semantics are identical.

1. Diagnostic sequence: preserve → scope → inspect → correct → verify

  1. Preserve evidence: PR URL/number, title/body, base/head names and OIDs, commit list, diff summary, check rollup, review state, and linked Issues.
  2. Identify scope: which repository owns base/head, which ref moved, which Issue/check/workflow/deployment is being discussed.
  3. Inspect: Git graph and merge base, gh pr view/diff, REST response, rules/checks, and workflow logs when present.
  4. Choose least destructive correction: metadata edit or base change before history rewrite; new commit before force push when possible.
  5. Verify independently: repeat both local Git and hosted PR inspection; never trust only the surface you just changed.

2. Failure matrix: symptom is not cause

Symptom Likely layers to inspect Do not jump to
PR shows unrelated commits branch ancestry, merge base, selected base branch force-push immediately
PR targets wrong branch PR base metadata, release policy recreate PR automatically
“No permission” updating PR head ownership, repository role, fork policy, token repository Admin
Checks green but release failed check SHA/context, merge SHA, deployment system rerun random checks
Issue closed after merge PR body/development link + default branch + auto-close setting reopen without fixing lifecycle policy
Review comments look outdated base/head changed, force push/rebase, file lines moved delete review history

3. Intentionally broken example: the branch was based on the wrong line

This example creates a base branch experiment/base containing an unrelated commit, then creates topic branch feature/actual-change from it. The author intends to target main but forgets that the topic inherited the experiment commit. The PR is valid GitHub state—but its change set is misleading.

gh auth status --active --hostname github.com
OWNER=$(gh api user --jq .login)
REPO="c07-pr-diagnostics-lab"

gh repo create "$OWNER/$REPO" --public --add-readme --clone
cd "$REPO"
DEFAULT_BRANCH=$(git branch --show-current)

# Wrong foundation: add an unrelated experiment commit.
git switch -c experiment/base
printf '
Unrelated experiment marker.
' >> README.md
git add README.md
git commit -m "experiment: unrelated base marker"
git push -u origin experiment/base

# Actual topic inherits that unrelated commit.
git switch -c feature/actual-change
printf '
Actual Chapter 07 diagnostic change.
' >> README.md
git add README.md
git commit -m "feat: actual diagnostic change"
git push -u origin feature/actual-change

PR_URL=$(gh pr create --base "$DEFAULT_BRANCH" --head feature/actual-change   --title "feat: actual diagnostic change"   --body "Intentionally broken Chapter 07 example: inspect before repair.")
PR_NUMBER=${PR_URL##*/}
Intentional failure: do not “fix while creating.” The point is to preserve and interpret the wrong state first. This is a disposable repository.

4. Preserve the original cause before repair

gh pr view "$PR_NUMBER" --json   number,baseRefName,baseRefOid,headRefName,headRefOid,commits,files,mergeable,url

gh pr diff "$PR_NUMBER" --name-only

git fetch origin "$DEFAULT_BRANCH" experiment/base feature/actual-change

git log --graph --oneline --decorate --all --max-count=12
printf 'merge_base='; git merge-base "origin/$DEFAULT_BRANCH" origin/feature/actual-change

git log --oneline "origin/$DEFAULT_BRANCH..origin/feature/actual-change"

Expected diagnosis: the range to main contains two commits—the unrelated experiment commit and the intended feature commit. GitHub is not “adding random commits”; the head branch ancestry actually contains them.

5. Two valid repairs depend on intended integration target

Intent Least destructive repair Why
The feature truly depends on experiment/base and should land there first Change the PR base to experiment/base No history rewrite; PR now reviews only the incremental feature commit
The feature should land directly on main and must not contain experiment history Recreate/rebase/cherry-pick a clean branch from main Git ancestry must change; metadata alone cannot erase an inherited commit

For this lab, choose the first interpretation so we can repair without rewriting history:

gh pr edit "$PR_NUMBER" --base experiment/base

gh pr view "$PR_NUMBER" --json baseRefName,baseRefOid,headRefName,headRefOid,commits,files

git log --oneline "origin/experiment/base..origin/feature/actual-change"
git diff --stat "origin/experiment/base...origin/feature/actual-change"

Now the PR should contain one incremental commit. The original Git graph did not change; only the PR base coordinate changed.

6. Wrong head repository or branch: inspect ownership before pushing

A common fork failure is assuming origin means upstream. Chapter 04 established that remote names are conventions. Before pushing a review fix, inspect the PR’s headRepository, headRepositoryOwner, and headRefName, then compare with git remote -v. If you push the same branch name to a different repository, the PR does not magically follow that other ref.

gh pr view PR_NUMBER -R OWNER/REPO --json   headRepository,headRepositoryOwner,headRefName,headRefOid,baseRefName

git remote -v
git branch -vv

7. Force-pushing during active review: technically possible, operationally expensive

A rebase or history edit changes commit OIDs. Force-pushing the rewritten branch can invalidate reviewers’ mental anchors, make comments outdated, change check SHAs, and complicate audit/reproduction. The master contract therefore does not teach plain git push --force as a routine fix.

Security-sensitive/history rewrite: if a disposable lab later requires rewritten shared history, preserve old OIDs, communicate with reviewers, prefer --force-with-lease over plain force, and verify that the remote still points where you expect. This chapter does not need a force push.

8. Accidental Issue closure: diagnose the automation input

If an Issue closes after a PR merges, inspect the PR body, commit messages, manually linked development relationship, repository auto-close setting, and target/default branch. Reopening the Issue restores lifecycle state but does not remove the cause. If the relation should be informational only, replace Closes #N with a plain reference such as Related to #N.

gh pr view PR_NUMBER -R OWNER/REPO --json body,baseRefName,closingIssuesReferences

gh issue view ISSUE_NUMBER -R OWNER/REPO --json number,state,stateReason,url

9. Approval, checks, merge, and deployment are four different states

An approving review answers a human governance question. A green check answers a configured automated-validation question for a particular revision. Merge state answers whether GitHub integrated the PR. Deployment evidence answers whether an environment changed. Incident diagnosis fails when teams compress those into one “green” status.

Claim Authoritative evidence
Reviewer approved PR reviews / review decision
Required tests passed specific check runs and tested SHA
PR merged PR merged state + merge commit / base history
Production updated deployment/environment/release system evidence

10. Example policy rejection: good code can still be non-mergeable

A repository can require reviews or status checks through branch protection/rulesets. A PR may have a clean Git merge and still be blocked by policy. Conversely, a PR can have approval but be unmergeable because of a Git conflict. Diagnose the class of blocker before changing code.

gh pr view PR_NUMBER -R OWNER/REPO --json   mergeable,mergeStateStatus,reviewDecision,statusCheckRollup,baseRefName,headRefOid

gh pr checks PR_NUMBER -R OWNER/REPO --required

If your free disposable repository has no required checks/protection, treat this as a read-only model/fixture; do not enable paid or organization controls merely to manufacture a failure.

11. Security-sensitive and destructive operations in PR incidents

  • Force update a branch/tag: rewrites shared ref history and can invalidate review/check evidence.
  • Delete a head branch: can disrupt active review or automation; inspect PR dependencies first.
  • Transfer/delete repository: inventory PRs, forks, Actions, Pages, packages, webhooks, and external integrations first.
  • Change workflow permissions/secrets: affects code-execution trust; never “fix CI” by exposing secrets to fork code.
  • Bypass policy: converts a failed control into an unreviewed governance exception; record who/why/evidence when legitimate.

12. Cleanup the intentionally broken lab

gh pr close "$PR_NUMBER" --comment "Diagnostic cause preserved and repair verified."
cd ..
printf 'archive-check=%s/%s
' "$OWNER" "$REPO"
gh repo archive "$OWNER/$REPO"
rm -rf "$REPO"
Cleanup boundary: verify the exact disposable repository identity before archiving. Archive preserves evidence and is reversible; permanent deletion remains an optional destructive follow-up, not part of the diagnostic repair.

13. Lesson summary

A misleading PR is usually explainable from base/head coordinates and ancestry. Preserve that evidence before mutation. Change metadata when the target is wrong; change Git history only when the branch ancestry is wrong. Force-pushes, closing keywords, checks, approvals, and deployment status all belong to distinct operational layers.

Knowledge check

A PR contains an inherited experiment commit. Can changing the title remove it?

When is changing the PR base the least destructive repair?

Why preserve old head/base OIDs before a history rewrite?

Checks passed and the PR is approved, but production is broken. What evidence plane is missing?

An Issue was auto-closed unintentionally. Is reopening it a complete fix?

Next lesson

Checkpoint the full PR operating model

Lesson 05 combines a linked Issue, draft PR, additional commits, readiness, a controlled base change, commit-range proof, and handoff criteria without merging.

Authoritative references

 Changing a pull request base branch
 Branches and pull-request comparisons
 Linking a pull request to an issue
 Managing protected branches
 Approving workflow runs from forks
 gh pr edit
 gh pr checks
 REST API endpoints for pull requests
 REST API versions

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
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.