Checkpoint Lab — Branches, Forks, Remotes, Synchronization, and Contribution Workflows
Operate a complete two-repository contribution checkpoint: create independent upstream and contributor changes, prove branch ownership, synchronize safely, clean topic branches only after dependency checks, and document the workflow as an auditable operating model.
Learning objectives
- Create a complete two-repository contribution topology from scratch with explicit owner, visibility, authentication, and cleanup assumptions.
- Predict hosted/local branch and remote-tracking ref changes before performing them, then verify each prediction independently.
- Make independent canonical and contributor commits, synchronize the contributor topic without pushing to the wrong repository, and prove exact OIDs.
- Demonstrate the distinction between hosted destination synchronization and local fetch/update state.
- Clean up topic branches only after dependency checks, then delete only the disposable repositories created by the lab.
- Produce a reusable contribution-topology runbook and bridge the operating model into Issues/triage in Chapter 05.
1. Checkpoint mission: prove who owns every ref
Your final artifact is not “two repositories that seem to work.” It is an evidence package: topology diagram, remote URLs, initial and final OIDs, hosted branch inspection, permission assumptions, synchronization decisions, branch cleanup evidence, and a short runbook another engineer could follow without guessing where a push goes.
2. Setup and preflight
gh auth status --active --hostname github.com
OWNER=$(gh api user --jq .login)
ROOT="atlas-c04-checkpoint"
UP="$ROOT-upstream"
FORKSIM="$ROOT-contrib"
git --version
gh --version
for R in "$UP" "$FORKSIM"; do
gh repo view "$OWNER/$R" >/dev/null 2>&1 && {
echo "STOP: $OWNER/$R already exists" >&2
exit 2
}
done
printf 'owner=%s
upstream=%s
contrib=%s
' "$OWNER" "$UP" "$FORKSIM"
Assumptions: you are authenticated as the intended personal account;
repository content is synthetic; public visibility is acceptable. If
your policy requires private repositories, use
--private for both repositories. This still remains a
two-repository simulation, not a GitHub private fork.
3. Write four predictions before mutation
- P1: initial upstream and contributor default branches can point to the same commit even though GitHub reports the contributor repository is not a fork.
-
P2: pushing
topic/telemetry-docsto contributororigincreates that branch only in the contributor repository. -
P3: after upstream advances and the contributor
runs
git fetch upstream, only local upstream-tracking knowledge changes; hosted contributor refs do not change yet. - P4: after the topic is synchronized and pushed, deleting the contributor topic branch will remove that hosted ref only after you prove no open PR/automation dependency exists; local commits remain while reachable from local refs/reflog.
4. Target topology
flowchart LR
U[("GitHub canonical
OWNER/atlas-c04-checkpoint-upstream")]
C[("GitHub contributor
OWNER/atlas-c04-checkpoint-contrib
NOT a GitHub fork")]
L[("Local contributor clone
origin -> contributor
upstream -> canonical")]
M[("Canonical maintainer clone")]
U <--> |"origin"| M
C <--> |"origin"| L
U --> |"fetch upstream"| L
L --> |"push topic only"| C
Every arrow is a Git network operation. There is intentionally no GitHub fork-network relationship arrow. The lab therefore proves the portable Git mechanics while keeping hosted fork metadata clearly separate.
5. Create canonical repository and baseline commit
gh repo create "$OWNER/$UP" --public --add-readme --clone
cd "$UP"
git config user.name "Checkpoint Maintainer"
git config user.email "maintainer@example.invalid"
mkdir -p docs
printf '%s
' '# Telemetry Contract' '' 'version: 1' > docs/telemetry.md
git add docs/telemetry.md
git commit -m "docs: seed telemetry contract"
git push origin HEAD
BASE_BRANCH=$(git branch --show-current)
BASE_OID=$(git rev-parse HEAD)
cd ..
printf 'base_branch=%s
base_oid=%s
' "$BASE_BRANCH" "$BASE_OID"
Record $BASE_OID. This is the common ancestor you will
use to prove the later independent changes.
6. Create contributor repository with identical history and prove P1
git clone "https://github.com/$OWNER/$UP.git" "$FORKSIM"
cd "$FORKSIM"
git config user.name "Checkpoint Contributor"
git config user.email "contributor@example.invalid"
git remote rename origin upstream
gh repo create "$OWNER/$FORKSIM" --public
git remote add origin "https://github.com/$OWNER/$FORKSIM.git"
git push -u origin "$BASE_BRANCH"
CONTRIB_BASE=$(git ls-remote origin "refs/heads/$BASE_BRANCH" | cut -f1)
test "$CONTRIB_BASE" = "$BASE_OID"
gh repo view "$OWNER/$FORKSIM" --json isFork,parent,nameWithOwner --jq '{nameWithOwner,isFork,parent:(.parent.nameWithOwner // null)}'
P1 passes if the branch OID equals $BASE_OID while
isFork=false. Same objects and branch contents are not
enough to create hosted fork lineage.
7. Prove remote ownership before contributor work
printf '%s
' '--- remotes ---'
git remote -v
printf '%s
' '--- remote refs ---'
git for-each-ref refs/remotes/ --format='%(refname:short) %(objectname)'
printf '%s
' '--- hosted repos ---'
gh repo view "$OWNER/$UP" --json nameWithOwner,viewerPermission --jq .
gh repo view "$OWNER/$FORKSIM" --json nameWithOwner,viewerPermission --jq .
Write one sentence in your evidence file: “origin
publishes contributor refs; upstream is the canonical
fetch source.” Do not proceed if the URLs disagree.
8. Contributor change: create topic and prove P2
git switch -c topic/telemetry-docs
printf '%s
' '' 'consumer: dashboards' >> docs/telemetry.md
git add docs/telemetry.md
git commit -m "docs: add telemetry consumer"
CONTRIBUTOR_OID=$(git rev-parse HEAD)
git push -u origin topic/telemetry-docs
C_REMOTE=$(git ls-remote origin refs/heads/topic/telemetry-docs | cut -f1)
U_REMOTE=$(git ls-remote upstream refs/heads/topic/telemetry-docs | cut -f1)
test "$C_REMOTE" = "$CONTRIBUTOR_OID"
test -z "$U_REMOTE"
printf 'contrib_topic=%s
upstream_topic=%s
' "$C_REMOTE" "${U_REMOTE:-<absent>}"
P2 is verified by two remote queries: contributor owns the branch; canonical upstream does not.
9. Independent upstream change
cd "../$UP"
printf '%s
' '' 'retention: 7d' >> docs/telemetry.md
git add docs/telemetry.md
git commit -m "docs: define telemetry retention"
git push origin HEAD
UPSTREAM_OID=$(git rev-parse HEAD)
cd "../$FORKSIM"
printf 'upstream_oid=%s
' "$UPSTREAM_OID"
The contributor topic and canonical default branch now both descend
from $BASE_OID but contain different changes. This is
the synchronization problem to solve.
10. Fetch upstream and prove P3
TRACKING_BEFORE=$(git rev-parse "refs/remotes/upstream/$BASE_BRANCH")
HOSTED_CONTRIB_BEFORE=$(git ls-remote origin "refs/heads/$BASE_BRANCH" | cut -f1)
git fetch upstream --prune
TRACKING_AFTER=$(git rev-parse "refs/remotes/upstream/$BASE_BRANCH")
HOSTED_CONTRIB_AFTER=$(git ls-remote origin "refs/heads/$BASE_BRANCH" | cut -f1)
printf 'tracking_before=%s
tracking_after=%s
hosted_contrib_before=%s
hosted_contrib_after=%s
' "$TRACKING_BEFORE" "$TRACKING_AFTER" "$HOSTED_CONTRIB_BEFORE" "$HOSTED_CONTRIB_AFTER"
test "$TRACKING_AFTER" = "$UPSTREAM_OID"
test "$HOSTED_CONTRIB_BEFORE" = "$HOSTED_CONTRIB_AFTER"
P3 passes: local upstream/$BASE_BRANCH learned the new
canonical OID while the hosted contributor default branch stayed
untouched.
11. Inspect divergence before choosing integration
git merge-base topic/telemetry-docs "upstream/$BASE_BRANCH"
git log --oneline --left-right --graph "topic/telemetry-docs...upstream/$BASE_BRANCH" -12
git diff --stat "upstream/$BASE_BRANCH...topic/telemetry-docs"
You should see one contributor-side commit and one upstream-side commit beyond the shared base. Because both edit the same file, the merge may conflict. That is useful evidence, not a reason to discard a side.
12. Synchronize the published topic with a merge
git switch topic/telemetry-docs
git merge "upstream/$BASE_BRANCH"
If Git reports a conflict, run git status and inspect
docs/telemetry.md. Keep both intended lines—consumer: dashboards
and retention: 7d—remove conflict markers, stage, and
commit:
# Run these commands only if the merge stopped for a conflict.
git status
git add docs/telemetry.md
git commit
After the merge has completed—automatically or after the conflict-resolution block—capture the final topic OID, push it to the contributor repository, and verify the exact hosted branch:
SYNCED_OID=$(git rev-parse HEAD)
git push origin topic/telemetry-docs
HOSTED_TOPIC=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" "/repos/$OWNER/$FORKSIM/branches/topic/telemetry-docs" --jq .commit.sha)
test "$SYNCED_OID" = "$HOSTED_TOPIC"
The exact hosted OID proves the contributor topic is synchronized. Canonical upstream still does not contain that topic ref.
13. Synchronize the hosted contributor default branch independently
cd ..
gh repo sync "$OWNER/$FORKSIM" --source "$OWNER/$UP" --branch "$BASE_BRANCH"
C_DEFAULT=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" "/repos/$OWNER/$FORKSIM/commits/$BASE_BRANCH" --jq .sha)
test "$C_DEFAULT" = "$UPSTREAM_OID"
cd "$FORKSIM"
Again, this changes hosted contributor state. Refresh local knowledge separately:
LOCAL_ORIGIN_BEFORE=$(git rev-parse "origin/$BASE_BRANCH")
git fetch origin "$BASE_BRANCH"
LOCAL_ORIGIN_AFTER=$(git rev-parse "origin/$BASE_BRANCH")
printf 'origin_before=%s
origin_after=%s
' "$LOCAL_ORIGIN_BEFORE" "$LOCAL_ORIGIN_AFTER"
test "$LOCAL_ORIGIN_AFTER" = "$UPSTREAM_OID"
This double verification is the heart of the chapter: hosted sync and local fetch are distinct state transitions.
14. Pre-delete dependency check for the topic branch
There is no pull request in this simulation. Still, prove that assumption instead of relying on memory. Query open PRs and record the branch OID before deletion.
TOPIC_BEFORE_DELETE=$(git ls-remote origin refs/heads/topic/telemetry-docs | cut -f1)
gh pr list --repo "$OWNER/$FORKSIM" --state open --json number,headRefName,headRepositoryOwner,url --jq '.[] | select(.headRefName=="topic/telemetry-docs")'
printf 'topic_before_delete=%s
' "$TOPIC_BEFORE_DELETE"
The query should return no matching open PR. In a production repository, you would also inventory workflow/deployment/external automation dependencies. This lab has no workflows, releases, packages, or Pages, so deletion scope is intentionally small.
15. Delete the disposable hosted topic and prove P4
git push origin --delete topic/telemetry-docs
REMOTE_AFTER=$(git ls-remote origin refs/heads/topic/telemetry-docs | cut -f1)
test -z "$REMOTE_AFTER"
git show --no-patch --oneline "$SYNCED_OID"
git branch --contains "$SYNCED_OID"
The hosted ref is gone. The commit can still exist locally while reachable from the local topic branch/reflog and because its objects are present. This demonstrates why “branch deleted” and “commit instantly erased everywhere” are different claims.
Now remove the local topic branch only after switching away:
git switch "$BASE_BRANCH"
git branch -d topic/telemetry-docs || {
echo "Branch is not fully merged into local base; preserve it or inspect before forced local deletion."
}
Do not replace the safety check with -D just to make
cleanup succeed. If Git says the local topic is not merged, that is
valid evidence that your local base does not contain the
contribution.
16. Final evidence table
| Evidence | Expected result |
|---|---|
Contributor repo isFork |
False (simulation), despite shared initial Git history |
| Initial upstream/contributor default OID | Same $BASE_OID |
| Contributor topic after first push |
Exists only in contributor repo, OID
$CONTRIBUTOR_OID
|
| Upstream default after independent change | $UPSTREAM_OID |
| Local upstream tracking after fetch | Matches $UPSTREAM_OID |
| Contributor topic after merge/push | Matches $SYNCED_OID |
Hosted contributor default after gh repo sync
|
Matches $UPSTREAM_OID |
Local origin/$BASE_BRANCH after fetch |
Matches $UPSTREAM_OID |
| Hosted topic after dependency-checked delete | Absent |
17. Write the contribution runbook
Your runbook should fit on one page but encode the operating model:
- Confirm account/host and repository owner/name.
-
Inspect
git remote -v;originmust be the contributor repository andupstreamthe canonical source. - Fetch upstream before creating or refreshing a topic branch.
- Create work on a topic branch, not the fork/default synchronization branch.
-
Push topic only to
origin; verify exact hosted OID. - Before review, inspect merge-base/diff and merge or rebase according to publication/history policy.
- Treat fork-originated automation as untrusted until policy/review permits it.
- After merge/closure, inventory PR/automation dependencies before deleting the hosted topic branch.
- Prune local tracking refs only after hosted deletion is intentional and verified.
18. Cleanup the two disposable repositories
Capture your evidence/runbook first. Then delete only
$OWNER/$UP and $OWNER/$FORKSIM. The safest
course path uses the GitHub web Settings danger zone so the
owner/name confirmation is visually explicit. If you use CLI
deletion in your own environment, read the current command help and
verify the target twice; repository deletion is destructive and
requires appropriate authorization.
19. Verification checklist
- Preflight proved authenticated account, tool availability, and repository-name uniqueness.
- Four predictions were written before mutation and independently checked.
- Topology diagram correctly separated local clone, hosted contributor repository, and hosted canonical repository.
- Initial repositories shared an OID but contributor correctly reported no GitHub fork relationship.
- Topic branch existed only in contributor repository until cleanup.
- Upstream default advanced independently and fetch updated only local upstream-tracking knowledge.
- Published topic was synchronized by merge, not silent history rewrite.
- Hosted contributor default sync and local origin fetch were verified as separate operations.
- Open-PR dependency check and branch OID capture happened before remote branch deletion.
- No force sync, force push, bypass, token exposure, workflow privilege change, or production resource was used.
- Only the two disposable repositories were selected for final cleanup.
Knowledge check
P1 passed even though isFork=false. What did that
prove?
Git repositories can share identical commits/history without GitHub recording a fork-network relationship.
Which operation proved P3: hosted sync or local fetch?
Local git fetch upstream. It updated the
remote-tracking ref while leaving hosted contributor refs
unchanged.
Why did the checkpoint merge upstream into the published topic instead of rebasing it?
To preserve already-published topic commit identities and avoid a force-style remote update in the mandatory path.
What must you verify before deleting a hosted topic branch?
At minimum exact OID and absence of open PR/dependency; in production also workflows, deployments, releases, external automation, branch policy, and recovery refs.
What production control does Chapter 04 add?
An explicit contribution topology: repository/ref ownership, remote-target verification, synchronization policy, permission boundary, automation trust boundary, and dependency-aware cleanup.
20. What Chapter 04 adds to the production GitHub operating model
Chapters 01–03 established platform boundaries, credentials, and repository provisioning. Chapter 04 adds change topology: where contributor branches live, which remote may receive pushes, how upstream state is learned, how fork/default branches are synchronized, and how ref deletion is governed. This topology becomes the substrate for pull requests, reviews, rulesets, and Actions security later in the course.
A production team can now write a contribution policy that is testable: actor class → repository ownership → branch location → remote convention → synchronization method → review path → automation trust → cleanup evidence.
21. Bridge to Chapter 05
The next chapter moves from code/ref topology to work-intake topology: Issues, labels, milestones, issue forms/templates, Discussions, and triage. The same principle carries forward—identify the hosted resource, owner, permission, lifecycle state, and automation consequences before changing it.
Authoritative references
Forks
Configuring a remote repository for a fork
Syncing a fork
Deleting and restoring branches in a pull request
gh repo sync
gh repo view
REST API endpoints for branches
REST API versions
git-remote
git-fetch
git-merge
git-push
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.