Chapter 03Lesson 04~120 minutes

Creating Repositories, Templates, Settings, Visibility, Topics, and Default Branches: Diagnostics, Failure Modes, Security, and Performance

Diagnose repository-creation and lifecycle mistakes from evidence before changing state, including wrong ownership/visibility, unrelated histories, stale remotes after rename, and unsafe transfer or deletion assumptions.

DiagnosticsLifecycle safetyUnrelated historiesRecovery

Learning objectives

  • Apply a repeatable evidence-first diagnostic sequence to repository creation, identity, and lifecycle failures.
  • Diagnose wrong owner/visibility without immediately transferring or changing visibility.
  • Engineer and repair an unrelated-history push rejection without using force push to hide the cause.
  • Explain GitHub repository rename redirects while still updating local remotes and dependent integrations deliberately.
  • Explain why changing the hosted default branch does not rename local branches automatically.
  • Inventory Actions, Pages, packages, webhooks, forks, permissions, and backups before archive/transfer/delete operations.
Availability: All required failures are reproduced with GitHub Free + disposable repositories. Transfer and visibility-change operations are explained and simulated rather than required. Repository rename may be performed only on a disposable lab repo. Enterprise-only policy/audit examples are optional.

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

  1. Preserve evidence. Save non-secret command output, owner/name, remote URLs, branch/ref names, commit OIDs, HTTP status/body, and timestamps before changing anything.
  2. Identify scope. Is the failure about local Git history, the GitHub repository resource, owner/role, visibility, default branch, integration, Actions, package, fork network, or enterprise policy?
  3. Inspect effective state. Use git status/log/remote, gh repo view --json, documented REST GETs, and relevant settings/logs.
  4. Choose the least destructive correction. Prefer fetching/reconciling or updating metadata/remotes over force push, delete/recreate, transfer, or visibility changes.
  5. Verify independently. Re-run read-only inspection from both Git and GitHub layers; confirm the original symptom is gone for the right reason.
Security-sensitive/destructive controls in this chapter: visibility change, transfer, delete, archive, force-updating refs, and history rewrite. They are never “try this and see” troubleshooting steps.

2. Failure mode: repository created under the wrong owner

Symptom: a service intended for acme-platform/atlas exists as developer/atlas. Git operations may work perfectly, so this is not a Git transport failure. It is a hosted ownership/governance error.

gh repo view OWNER/REPO \
  --json nameWithOwner,isInOrganization,owner,viewerPermission,visibility \
  --jq '{nameWithOwner,isInOrganization,owner:.owner.login,viewerPermission,visibility}'

Do not transfer immediately. First inventory the target organization’s repository-creation permission, plan/policy, existing same-name repositories/forks, team access, Pages, packages, Actions, webhooks, and whether transfer is allowed. A disposable repository can simply be deleted/recreated if no useful history or hosted metadata exists; a production repository requires a migration plan.

Transfer is security-sensitive. GitHub documents owner/target constraints and warns that plan/policy differences can change feature availability. Treat transfer as a controlled change with approval and rollback/redirect planning.

3. Failure mode: repository created with the wrong visibility

Symptom: a repository intended to be private is public, or a learner selected private but expected public discovery. If confidential material was exposed publicly, this is an incident, not merely a settings correction. Preserve evidence, remove/rotate exposed credentials first, and follow incident response.

For ordinary non-secret lab data, inspect before changing:

gh repo view OWNER/REPO --json nameWithOwner,visibility,isPrivate,viewerPermission

Current gh repo edit --visibility requires an explicit flag accepting visibility-change consequences. That requirement is useful design feedback: GitHub treats visibility change as consequential. In this course, recreate a disposable repository with the correct visibility instead of using visibility changes as a practice toggle.

Never “fix” public secret exposure by only making the repository private. Revoke/rotate exposed credentials first; copies may already exist.

4. Intentionally broken example: remote README versus unrelated local history

This failure is safe to engineer in a disposable repository and teaches the most common initialization mistake. The remote gets one README commit; the local repository independently gets one different initial commit. Neither history is “wrong,” but a direct push cannot fast-forward the remote branch.

Setup

OWNER=$(gh api /user --jq .login)
BAD="github-unrelated-history-lab-$(date +%Y%m%d%H%M%S)"
gh repo create "$OWNER/$BAD" --public --add-readme
DEFAULT=$(gh repo view "$OWNER/$BAD" --json defaultBranchRef --jq .defaultBranchRef.name)

mkdir "$BAD-local"
cd "$BAD-local"
git init -b "$DEFAULT"
git config user.name "Learner Example"
git config user.email "learner@example.invalid"
printf '%s\n' 'service=local-first' > service.txt
git add service.txt
git commit -m "feat: create local independent history"
git remote add origin "https://github.com/$OWNER/$BAD.git"
git push -u origin "$DEFAULT"

Interpret the rejection

! [rejected]        main -> main (fetch first)
error: failed to push some refs ...
hint: Updates were rejected because the remote contains work that you do not have locally.

The exact wording/branch name can vary, but the causal evidence is: remote branch already points at a commit not reachable from your local branch. The correct next step is inspection, not --force.

Preserve and inspect both histories

git fetch origin
git log --oneline --decorate --graph --all --boundary
git show --stat HEAD
git show --stat "origin/$DEFAULT"

You should see two root histories. The remote README commit and local service commit have no common ancestor because they were created independently.

Least-destructive repair for this synthetic case

git merge "origin/$DEFAULT" --allow-unrelated-histories --no-edit
git log --oneline --decorate --graph --all -8
git push -u origin "$DEFAULT"
gh api -H "X-GitHub-Api-Version: 2026-03-10" \
  "/repos/$OWNER/$BAD/commits/$DEFAULT" --jq .sha
git rev-parse HEAD

Because the two roots contain different files, this small example should merge without a content conflict and create a merge commit joining the histories. In a real project, decide whether the remote seed or local history is authoritative; sometimes recreating an unused remote is cleaner. The lesson is to preserve evidence and choose deliberately—not to normalize unrelated-history merges everywhere.

Do not force-push to “make the error go away.” A force update would overwrite the remote ref and hide the initialization mistake while potentially discarding someone else’s work.

5. Failure mode: repository renamed but dependencies still use the old coordinate

GitHub redirects most web and Git traffic from the old repository name to the new one, so a stale origin can appear to work. That compatibility is not permission to leave the estate inconsistent. GitHub specifically warns that calls to an action hosted in a renamed repository are not redirected. Pages URLs and external systems can also need deliberate updates.

Before rename: inspect dependencies

git remote -v
gh repo view OWNER/OLD --json nameWithOwner,url,homepageUrl,isArchived
# Search your own code/config for OWNER/OLD before changing it.

If you intentionally rename a disposable lab repository, update the local clone afterward:

git remote set-url origin https://github.com/OWNER/NEW.git
git remote -v
gh repo view OWNER/NEW --json nameWithOwner,url
Rename is a controlled lifecycle operation. Inventory Actions references, Pages, badges, webhooks, package links, external CI, documentation, deployment systems, and automation before renaming a production repository.

6. Failure mode: changing the GitHub default branch and expecting local clones to rename

Suppose GitHub’s default changes from main to trunk. Existing clones still have whatever local branch names and upstream configuration they had. Fetching can update the remote-tracking view, but GitHub cannot rewrite branch names on every developer workstation.

git branch -vv
git remote show origin
git remote set-head origin -a
git symbolic-ref refs/remotes/origin/HEAD

git remote set-head origin -a asks Git to update the local symbolic origin/HEAD based on the remote’s advertised default. That is still different from renaming your local checked-out branch. If a local rename is part of a migration, plan and execute it explicitly with the correct upstream tracking—not as an assumed side effect of the GitHub setting.

7. Before transfer/archive/delete: inventory the hosted resource graph

A Git repository is not the whole GitHub repository resource. Before a lifecycle operation, capture both Git and hosted dependencies. The exact endpoints/features available depend on permission and plan; absence of a field is not proof that the integration does not exist.

Inventory item Why it matters before lifecycle change Example evidence
Git refs/tags/default branch Defines source/history/release identities. git ls-remote --heads --tags, repository default-branch field.
Actions/workflows/secrets/environments Repository coordinate, permissions, logs, secrets, OIDC trust may be bound to repo. Workflow list/settings; never export secret values.
Pages Rename/transfer can affect URLs/domains/source. Pages settings + custom-domain inventory.
Packages/releases/assets Ownership/linkage/consumer URLs may change or transfer differently. Package/release metadata and dependency inventory.
Webhooks/Apps/deploy keys External integrations may target old repository ID/name or receive events under new owner. Webhook/App inventory without secret material.
Fork network Visibility/delete/transfer constraints can affect forks. Fork/network metadata.
Teams/collaborators/policies Transfer changes governing owner context. Non-secret role/team/policy inventory.
Backup/restore evidence Deletion restore is conditional; Git backup alone omits hosted metadata. Verified mirror + separate metadata/runbook where required.

8. Archive is not delete; restore is not backup

Archiving makes the repository read-only on GitHub until it is unarchived. GitHub documents that code, issues, pull requests, releases, branches, comments, permissions, and other repository content become read-only. This is useful for retired projects that must remain referenceable.

Deletion removes the repository and permissions. GitHub currently allows restoration of some deleted repositories within 90 days, but fork-network conditions can prevent restoration. A conditional restoration window is not a disaster-recovery design. If recovery matters, maintain an appropriate Git backup and a separate plan for hosted metadata/integrations.

Destructive boundary: do not delete, transfer, or change visibility on a valuable repository as troubleshooting. Use disposable resources and require explicit owner/name verification immediately before the action.

9. Hosted API errors: distinguish resource, permission, and policy

Observation Possible cause Next inspection
404 for private repository Wrong owner/name, repository moved/deleted, or authenticated caller lacks access. Confirm authenticated login, exact coordinate, and expected repository ownership.
403 on settings mutation Authenticated but insufficient repository permission, token permission, organization/enterprise policy, or rate/policy restriction. Inspect viewer permission, token model, response headers/body, and governing policy.
422 on repository creation Validation conflict such as invalid/occupied name or request parameters. Read response body; do not blind-retry with new mutations.
Git push rejected non-fast-forward Remote ref points at history not contained in local branch. Fetch and inspect commit graph before deciding integration strategy.

REST automation later in the course will add pagination/rate-limit/retry discipline. In this chapter, the important point is that HTTP status plus body and target coordinate are evidence. Never solve a 403 by immediately granting admin or widening a token.

10. Cleanup the intentionally broken repository safely

After you preserve the non-secret commit graph and confirm the repaired branch OID, return to the repository’s Settings → General → Danger Zone and delete only the disposable $BAD repository. GitHub requires destructive confirmation in the UI.

Then verify from the CLI:

gh repo view "$OWNER/$BAD"
printf 'expected gh exit=%s\n' "$?"

A not-found/access failure confirms the hosted resource is gone. Your local $BAD-local directory remains because local Git state is independent; remove it only after you have preserved any teaching evidence you need.

11. Diagnostic verification checklist

  • Every failure is classified as local Git, hosted repository metadata, identity/permission, integration, policy, or lifecycle scope before correction.
  • Wrong owner/visibility is inspected before transfer/visibility mutation.
  • The unrelated-history rejection remains visible in the evidence and was repaired without force push.
  • Rename guidance updates local remotes and inventories dependencies rather than trusting redirects forever.
  • Default-branch guidance distinguishes hosted setting, remote HEAD, and local branch name.
  • Transfer/archive/delete planning inventories non-Git hosted resources and fork/package/Pages/integration consequences.
  • No production repository is used for destructive demonstrations.

Knowledge check

A push to a newly created GitHub repository is rejected with “fetch first.” What should you inspect before considering force push?

After renaming a repository, git fetch still works using the old URL. Is your migration finished?

Why does changing the GitHub default branch not rename a developer’s local branch?

What is safer for a retired repository that must remain referenceable: archive or delete?

A repository transfer “preserves the Git commits.” Why can production still break?

12. Summary

Repository failures are easier when you keep the layers separate. A non-fast-forward rejection is Git/ref history evidence; wrong ownership and visibility are hosted resource problems; a stale remote after rename is local configuration/integration debt; default-branch changes are hosted settings with local consequences; transfer/archive/delete are lifecycle operations over a graph of hosted dependencies.

The diagnostic discipline is consistent with earlier chapters: preserve evidence, identify scope, inspect structured state, make the least destructive correction, and independently verify.

Next lesson

Integrate repository creation, template provenance, verification, and cleanup

Lesson 05 provisions a complete disposable project, predicts state changes, creates a template-derived repository, compares histories/relationships, and produces a cleanup plus ownership-transfer runbook.

Authoritative references

 Creating a new repository
 Setting repository visibility
 Renaming a repository
 Transferring a repository
 Archiving repositories
 Deleting a repository
 Restoring a deleted repository
 Backing up a repository
 Changing the default branch
 gh repo edit
 REST API endpoints for repositories

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.