🔧 Git & GitHub FoundationHands-On · Part 7 of 7
📖
Concept First
Understand the why before you dive in?
Read the Concept Guide →

Running Project: my-notes

Starting state (from Part 6): five files on main — notes.txt, todos.txt, goals.txt, progress.txt, scratch.txt. Nine or more commits. Annotated tag v1.0. Linear history after rebase. No remote configured.

Ending state: my-notes live on GitHub. Every commit, tag, and file visible in the GitHub UI.

What you need before starting: a GitHub account (free). If you don't have one, create it at github.com — no payment required for public or private repositories up to standard limits.

Step 1 — Generate an SSH Key

Why: GitHub requires SSH keys (or Personal Access Tokens) in place of passwords for all Git operations since August 2021. SSH key authentication means your private key never leaves your machine — far safer than any password.

Check if you already have one:

ls ~/.ssh/id_ed25519.pub

If the file exists, skip to Step 2. If you get "No such file or directory," continue:

ssh-keygen -t ed25519 -C "your@email.com"

Use the email address on your GitHub account. At the prompts:

  • File location — press Enter to accept the default ~/.ssh/id_ed25519
  • Passphrase — recommended but optional. A passphrase encrypts the private key file at rest; without one, anyone with the file can impersonate you.

Expected output:

Your identification has been saved in /home/you/.ssh/id_ed25519
Your public key has been saved in /home/you/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:AbCdEfGhIjKlMnOpQrStUvWx1234567890abc your@email.com

Self-check: ls ~/.ssh/id_ed25519* lists both id_ed25519 (private) and id_ed25519.pub (public).

Step 2 — Copy Your Public Key

Why: The public key is what you give to GitHub. You need its full text on your clipboard. Always copy the .pub file — never the private key file (no extension).

cat ~/.ssh/id_ed25519.pub

Expected output:

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... your@email.com

One line starting with ssh-ed25519, a long base64 string, then your email comment. Select and copy the entire line.

Shortcut: macOS: cat ~/.ssh/id_ed25519.pub | pbcopy
Windows Git Bash: cat ~/.ssh/id_ed25519.pub | clip

Self-check: Output starts with ssh-ed25519 and ends with your email. One line only.

Step 3 — Add the Public Key to GitHub

Why: GitHub stores your public key to verify your identity during SSH operations. You register it once per machine — after that, all Git operations authenticate automatically without typing anything.

  1. Click your profile avatar (top-right) → Settings
  2. Left sidebar → SSH and GPG keys
  3. Click New SSH key
  4. Title: a label identifying this machine (e.g., "Work laptop" or "Home desktop") — useful if you ever need to revoke one specific machine's access
  5. Key type: leave as Authentication Key
  6. Key: paste the full public key line from Step 2
  7. Click Add SSH key

Self-check: The key appears in the SSH keys list with the title you gave it. Its fingerprint matches the one ssh-keygen printed in Step 1.

Step 4 — Test the SSH Connection

Why: Before touching your repository, verify the key works. This command authenticates with GitHub's SSH endpoint and returns your username — confirming the entire setup is correct with no risk to your repository.

ssh -T git@github.com

Expected output:

Hi your-username! You've successfully authenticated, but GitHub does not provide shell access.

"Does not provide shell access" is not an error — it is expected. GitHub's SSH endpoint exists only for Git operations. Your username in the greeting confirms everything is working.

If you see a host fingerprint confirmation prompt on first connection, type yes. This is standard SSH behaviour for an unknown host and is a one-time confirmation per machine.

Self-check: Your GitHub username appears in the greeting. No "Permission denied" or "Connection refused" output.

Step 5 — Create an Empty Repository on GitHub

Why: You need a remote destination. The repository must be completely empty — if GitHub creates any initial commit (README, .gitignore, license), it will conflict with your existing local history and block the push.

  1. Click + (top-right, next to your avatar) → New repository
  2. Repository name: my-notes
  3. Visibility: Public or Private — your choice. Public lets anyone view it; Private keeps it visible only to you and collaborators you invite.
  4. Initialize this repository with: leave ALL checkboxes unchecked — no README, no .gitignore, no license
  5. Click Create repository

After creation, GitHub shows a "Quick setup" page. Copy the SSH URL — it looks like git@github.com:your-username/my-notes.git. You need this in Step 6.

Self-check: The page shows "...or push an existing repository from the command line" instructions, confirming the repo is empty and ready to receive your history.

Step 6 — Connect Your Local Repository to GitHub

Why: Your local my-notes repository has no remote configured. Adding origin registers the GitHub URL so Git knows where to send commits on push.

In your my-notes directory:

git remote add origin git@github.com:your-username/my-notes.git

Replace your-username with your actual GitHub username. A typo here produces a "Repository not found" error on push — verify the URL matches exactly before continuing.

Verify:

git remote -v

Expected output:

origin  git@github.com:your-username/my-notes.git (fetch)
origin  git@github.com:your-username/my-notes.git (push)

Self-check: Both lines show your exact GitHub URL. SSH form (git@github.com:), not HTTPS.

Step 7 — Push Your Full History to GitHub

Why: git push -u origin main sends every commit on local main to the remote and sets the upstream tracking relationship in one command. After this, future git push and git pull need no arguments.

git push -u origin main

Expected output:

Enumerating objects: 35, done.
Counting objects: 100% (35/35), done.
Compressing objects: 100% (28/28), done.
Writing objects: 100% (35/35), 8.42 KiB | 2.81 MiB/s, done.
Total 35 (delta 8), reused 0 (delta 0), pack-reused 0
To git@github.com:your-username/my-notes.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

The final line confirms upstream tracking is set. From now on, git push alone sends new commits to GitHub.

Self-check: No error output. "Branch 'main' set up to track" line present.

Step 8 — Verify on GitHub

Why: Close the loop. Confirm the push actually worked by reading the result in the GitHub UI — files, full commit history, and the annotated tag. This is also a first look at how GitHub presents the repository your local Git built.

Navigate to github.com/your-username/my-notes in a browser.

Check three things:

1. Files — the Code tab should show all five files: notes.txt, todos.txt, goals.txt, progress.txt, scratch.txt. Click any file to view its content.

2. Commits — click the commit count link (e.g., "9 commits"). Every commit from your local history appears, from "Add initial notes file" at the bottom through to the most recent at the top. Click any commit to see its diff rendered in the GitHub UI.

3. Tag — click the branch selector dropdown and switch to the Tags tab. v1.0 should appear. Click it to see the annotated tag message "First stable version of my notes" and the commit it points to.

Self-check: Five files visible. Commit count matches your local git log --oneline. Tag v1.0 present with its annotated message.

What Comes Next — After Your First Push

With origin configured and upstream set, daily use for solo projects reduces to three commands:

git add specific-file.txt
git commit -m "Describe the why"
git push

For collaborative projects, pull before you push to integrate changes teammates pushed while you were working:

git pull
# resolve conflicts if any
git push

Everything else in the Git toolkit — branches for isolation, rebase for clean history, tags for release markers, reflog for recovery — sits on top of this same foundation.

🎉

You just completed the Git & GitHub Foundation series.

Seven hands-on posts. One real repository, built from scratch and pushed live to GitHub. You initialised the repo, traced the object graph, branched, merged a conflict by hand, rebased for linear history, recovered a deleted branch from reflog, tagged a milestone, and pushed the full history to a remote. That is not a tutorial exercise — that is the actual workflow used in production teams. Take my-notes as the template and apply the same sequence to every real project from here.