Creating Repositories, Templates, Settings, Visibility, Topics, and Default Branches: Guided Hands-On Workflow and Core Operations
Create and inspect disposable repositories, connect hosted state to local Git, modify safe repository metadata, and prove the difference between ordinary, template-derived, and forked repository relationships.
Learning objectives
- Create a disposable public repository with deliberate owner, visibility, description, and initialization choices using GitHub CLI or the web UI.
- Verify repository identity, visibility, default branch, and permissions before cloning or pushing.
- Connect hosted default-branch/ref state to a local clone, create a small commit, push it, and prove the exact commit OID on GitHub.
- Edit non-destructive hosted metadata—description and topics—and verify that the Git commit OID does not change.
- Create a disposable template repository, generate a derived repository, and prove that template provenance is not fork provenance.
- Choose the correct GitHub surface or control from the resource model instead of memorizing one creation sequence.
1. Scenario: provision three disposable Atlas repositories
You are creating a tiny service called Atlas Echo. The lab uses three repositories in your personal namespace: a normal project repository, a template repository, and a repository generated from that template. Every name contains a timestamp so repeated runs do not collide.
The important part is not speed. Before every mutation you will state which resource changes: GitHub repository metadata, a Git ref/commit, or local Git configuration. Afterward you will verify through a different interface.
2. Preflight: prove identity and tooling first
git --version
gh --version
gh auth status --active --hostname github.com
OWNER=$(gh api /user --jq .login)
printf 'GitHub owner: %s\n' "$OWNER"
The active GitHub CLI account is the default owner when
gh repo create receives only a repository name. We
still capture OWNER and use
OWNER/REPO explicitly so the target is unambiguous.
3. Create unique lab names and predict the first state change
Git Bash, Bash, or zsh
STAMP=$(date +%Y%m%d%H%M%S)
REPO="github-repo-model-$STAMP"
TEMPLATE="github-template-model-$STAMP"
DERIVED="github-derived-model-$STAMP"
printf '%s\n' "$OWNER/$REPO" "$OWNER/$TEMPLATE" "$OWNER/$DERIVED"
PowerShell
$OWNER = gh api /user --jq .login
$STAMP = Get-Date -Format yyyyMMddHHmmss
$REPO = "github-repo-model-$STAMP"
$TEMPLATE = "github-template-model-$STAMP"
$DERIVED = "github-derived-model-$STAMP"
"$OWNER/$REPO`n$OWNER/$TEMPLATE`n$OWNER/$DERIVED"
Prediction: creating $REPO with
--add-readme will create a GitHub repository resource,
one initial Git commit, one branch selected as default, and hosted
description/visibility metadata. It will not create a local clone
unless --clone is requested.
4. Create the normal repository deliberately
Use the CLI path below, or perform the equivalent choices in GitHub’s current New repository page: owner = your personal account, visibility = public (or private if policy requires), description = synthetic lab text, initialize with README.
gh repo create "$OWNER/$REPO" \
--public \
--description "Disposable GitHub repository-model lab" \
--add-readme
Resource change: GitHub creates $OWNER/$REPO. Because
--add-readme requests content, GitHub also creates the
initial commit and branch. The command does not edit any
pre-existing local Git repository.
--public with --private. Do not choose
--internal unless you are intentionally operating
inside an eligible Enterprise Cloud organization.
5. Verify creation through structured hosted state
gh repo view "$OWNER/$REPO" \
--json nameWithOwner,visibility,defaultBranchRef,description,isEmpty,viewerPermission \
--jq '{nameWithOwner,visibility,defaultBranch: .defaultBranchRef.name,description,isEmpty,viewerPermission}'
gh api -H "X-GitHub-Api-Version: 2026-03-10" \
"/repos/$OWNER/$REPO" \
--jq '{full_name,visibility,default_branch,archived,is_template,permissions}'
Expected observations: the full name matches the intended
owner/name, visibility matches your creation choice,
defaultBranchRef.name is populated because the README
created history, and your viewer permission is sufficient to
administer your personal repository. If any owner or visibility
value is wrong, stop before adding more state.
Notice that the API result is a repository resource, not a Git commit. You will verify the commit separately.
6. Clone and connect hosted state to local Git
gh repo clone "$OWNER/$REPO"
cd "$REPO"
git remote -v
git branch --show-current
git status --short --branch
git log --oneline --decorate -3
LOCAL_HEAD=$(git rev-parse HEAD)
REMOTE_HEAD=$(git ls-remote origin HEAD | awk '{print $1}')
printf 'local=%s\nremote=%s\n' "$LOCAL_HEAD" "$REMOTE_HEAD"
test "$LOCAL_HEAD" = "$REMOTE_HEAD"
The clone gives you a separate local Git repository.
origin is local configuration pointing at GitHub.
Matching OIDs prove the local checked-out commit and GitHub’s
advertised HEAD currently identify the same Git object.
This does not mean GitHub metadata was cloned into
.git.
7. Make one local commit, push it, and verify causality
printf '%s\n' 'service=atlas-echo' > service.env.example
git add service.env.example
git commit -m "docs: add synthetic service marker"
NEW_OID=$(git rev-parse HEAD)
git push origin HEAD
HOSTED_OID=$(gh api -H "X-GitHub-Api-Version: 2026-03-10" \
"/repos/$OWNER/$REPO/commits/$(git branch --show-current)" --jq .sha)
printf 'local=%s\nhosted=%s\n' "$NEW_OID" "$HOSTED_OID"
test "$NEW_OID" = "$HOSTED_OID"
The commit operation changed only local Git first. The push then transferred objects and requested a hosted branch-ref update. The API GET independently confirms the branch now resolves to the exact commit you created. Hosted description/topics have not changed because Git content and hosted metadata are separate resource layers.
8. Change hosted metadata without changing Git history
Record the commit OID before changing description/topics:
BEFORE_META=$(git rev-parse HEAD)
gh repo edit "$OWNER/$REPO" \
--description "Disposable Atlas Echo repository architecture lab" \
--add-topic devops \
--add-topic github-learning
gh repo view "$OWNER/$REPO" \
--json description,repositoryTopics \
--jq '{description,topics: [.repositoryTopics[].name]}'
AFTER_META=$(git rev-parse HEAD)
test "$BEFORE_META" = "$AFTER_META"
The description/topics changed the GitHub repository resource. The local commit OID stayed identical because no Git object or ref changed. This is a simple but important example of hosted metadata that automation can query without assuming it is version-controlled.
9. Create a template repository with reusable starter content
Return to the parent directory and create a second disposable repository. A template repository is an ordinary repository with a hosted template flag; its Git data is still ordinary Git data.
cd ..
gh repo create "$OWNER/$TEMPLATE" --public --add-readme --clone
cd "$TEMPLATE"
mkdir -p .github
printf '%s\n' '# Atlas Service Template' '' 'Replace this text in generated projects.' > README.md
printf '%s\n' 'SERVICE_NAME=replace-me' > .env.example
printf '%s\n' 'node_modules/' '.env' > .gitignore
git add README.md .env.example .gitignore
git commit -m "chore: prepare disposable service template"
git push origin HEAD
cd ..
gh repo edit "$OWNER/$TEMPLATE" --template
gh repo view "$OWNER/$TEMPLATE" --json isTemplate,defaultBranchRef --jq '{isTemplate,defaultBranch: .defaultBranchRef.name}'
The first commit/update modifies Git content;
gh repo edit --template changes hosted repository
metadata. The verification must therefore check both layers when you
care about both. Current GitHub CLI exposes
--template on gh repo edit.
10. Generate a repository from the template and inspect provenance
gh repo create "$OWNER/$DERIVED" \
--public \
--template "$OWNER/$TEMPLATE"
gh repo view "$OWNER/$DERIVED" \
--json nameWithOwner,isFork,parent,templateRepository,defaultBranchRef \
--jq '{nameWithOwner,isFork,parent:(.parent.nameWithOwner // null),template:(.templateRepository.nameWithOwner // null),defaultBranch:.defaultBranchRef.name}'
gh repo clone "$OWNER/$DERIVED"
git -C "$DERIVED" log --oneline --decorate --all -5
Expected model: the generated repository is not a fork. GitHub records template provenance where exposed, and the generated repository starts its own history rather than sharing a fork network. GitHub’s current template documentation describes template-generated branches as having unrelated histories, so you should not plan to synchronize future template changes through ordinary upstream pull requests.
11. Compare template provenance with fork provenance
| Question | Generated from template | Fork |
|---|---|---|
| Primary intent | Start a new project from reusable structure/content. | Develop/contribute relative to an upstream repository. |
| History relationship | New/unrelated generated history. | Includes upstream history and remains in a repository network. |
| Hosted relationship |
Template provenance may be visible;
isFork=false.
|
isFork=true with parent/upstream relationship.
|
| Can later upstream changes be merged automatically because of template relation? | No special merge lineage is created by the template relationship. | Normal Git history can be fetched/merged from upstream subject to access/policy. |
| Visibility behavior | Chosen for the generated repository subject to owner/policy. | Fork visibility follows repository-network rules. |
An informal “starter repository” can be any ordinary repository containing starter files. If reproducible project creation is the goal, template semantics are explicit and machine-readable. If ongoing upstream contribution is the goal, fork semantics are the relevant relationship.
12. Map each action to the correct GitHub surface
| Need | GitHub surface/control | Underlying state |
|---|---|---|
| Change project description/topics |
Repository “About” metadata or gh repo edit.
|
Hosted repository metadata; no Git commit. |
| Change README content | Edit/commit/push through Git or GitHub file editor. | Git tree/commit/ref state. |
| Change default branch |
Repository settings or
gh repo edit --default-branch.
|
Hosted setting pointing at an existing branch. |
| Create derived project baseline |
Template repository /
gh repo create --template.
|
New GitHub repository + generated Git history. |
| Contribute relative to upstream | Fork. | Repository-network relationship + Git history. |
13. Challenge: choose the control before seeing the command
- A platform team wants every new microservice to begin with the same CI skeleton but then diverge independently. Choose template, fork, or ordinary copy and justify the relationship.
- A contributor wants to propose changes back to an upstream open-source project. Choose template, fork, or ordinary repository.
- A repository’s description says “old service name,” but Git history is correct. Decide whether a commit is necessary.
- A new hosted repository contains a README, while your local project already has its own initial commit. Before forcing anything, state which two histories now exist and what evidence you need.
14. Verification checklist
- Normal repository owner/name, visibility, and default branch match the intended design.
- Local and hosted branch OIDs matched after the push.
- Description/topics changed without changing the Git commit OID.
- Template repository reports
isTemplate=true. -
Derived repository reports
isFork=falseand is explainable as a new project baseline. - No real credentials, secrets, or proprietary content were stored in any disposable repository.
- You can point to the exact resource layer changed by each CLI command.
Knowledge check
After gh repo edit --description, should
git rev-parse HEAD change?
No. Description is hosted repository metadata, not a Git commit.
Why did the lab compare local and hosted commit OIDs after push?
It independently proves that the hosted branch ref now points to the exact commit created locally, rather than assuming success from the push message alone.
A generated repository says isFork=false. Is that
consistent with being created from a template?
Yes. Template generation creates a new project/history; it is not a fork-network relationship.
Which is safer when you already have a meaningful local history: remote README initialization or an empty remote?
Usually an empty remote, because it avoids creating an unrelated initial history that must later be reconciled.
A team needs ongoing synchronization with upstream history. Should it depend on template provenance?
No. A fork/upstream Git relationship is the model for ongoing contribution/synchronization; a template is for independent project generation.
15. Summary
You have now created and verified repository state across three layers: hosted repository resource metadata, Git refs/commits, and local clone configuration. You also proved that changing metadata does not change history and that template generation is a different provenance model from forking.
The next step is to choose these controls deliberately before production dependencies form. Ownership, visibility, initialization, default branches, and merge methods all trade convenience against governance and compatibility.
Authoritative references
Creating a new repository
gh repo create
gh repo view
gh repo edit
Creating a template repository
Creating a repository from a template
Forks
Classifying your repository with topics
REST API endpoints for repositories
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.