🔧 Git & GitHub FoundationTheory · Part 7 of 7

"Git is the engine. GitHub is the garage where the team parks their work. The engine runs fine without the garage — but the garage makes collaboration possible at scale."

Git and GitHub Are Not the Same Thing

Git is version control software. It runs locally, tracks history, manages branches, and works completely offline. It was created by Linus Torvalds in 2005 and has no dependency on any external service.

GitHub is a cloud platform that hosts Git repositories. It adds a web UI, team permissions, pull requests, issue tracking, and automation via GitHub Actions. Microsoft acquired it in 2018. It is not the only option — GitLab, Bitbucket, and Azure DevOps offer similar hosting — but it is the most widely used.

The relationship: your local Git repository and a GitHub repository are two separate copies of the same history, kept in sync by git push and git pull. Neither is authoritative by default. The convention is that the remote becomes the shared source of truth for teams, but Git itself does not enforce this.

Everything you have done in this series so far — commits, branches, merges, rebases — happened entirely locally. This post connects that local history to the internet.

Why Password Authentication No Longer Works

On 13 August 2021, GitHub removed support for password authentication for all Git operations over HTTPS. Attempting git push with a username and password today returns an immediate rejection. The reason: passwords are a weak credential for automated operations — they can be phished, reused across sites, and don't support per-machine revocation.

Two alternatives replaced them:

Personal Access Tokens (PAT) — a long random string generated in GitHub Settings that acts as a password substitute. They support scopes (read-only, write, etc.) and expiry dates. They work over HTTPS but must be stored somewhere: a credential manager, environment variable, or CI secret. The right choice for scripts and automated pipelines.

SSH keys — an asymmetric key pair where your private key never leaves your machine and GitHub holds only the public key. Authentication happens via a cryptographic challenge-response: GitHub sends a challenge, your SSH client signs it with the private key, GitHub verifies the signature with the public key. No secret is ever transmitted. The right choice for interactive developer workflows — and what you will set up in Hands-On Part 7.

SSH Keys — What They Are and Why ed25519

An SSH key pair produces two files:

  • Private key (~/.ssh/id_ed25519) — stays on your machine. Never share it, never copy it to a server, never paste it anywhere. This is your identity.
  • Public key (~/.ssh/id_ed25519.pub) — the counterpart you give to GitHub. Anyone can have it; it is useless without the matching private key.

The algorithm: ed25519 is the modern choice over RSA. It produces shorter keys (68 characters public vs. 800+ for RSA 4096), signs faster, and is more resistant to implementation errors. GitHub has supported it since 2019 and recommends it for all new keys.

The generate command:

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

The -C flag adds a comment — conventionally your email — to the end of the public key file. It is a label for your own identification when managing multiple keys across machines. It has no cryptographic function.

When prompted for a passphrase: setting one encrypts the private key file at rest. If someone steals the file, they still cannot use it without the passphrase. Recommended for any machine that is not physically secured. The SSH agent (ssh-add) can cache the decrypted key in memory so you are not prompted on every operation.

Remotes — What origin Actually Is

A remote is a named URL stored in your local repository's config. It points to another copy of the repository — on GitHub, on a teammate's machine, on a server. A repository can have multiple remotes.

origin is a convention, not a special name. When you clone a repository, Git names the source origin automatically. When you add a remote yourself, you choose the name. Most repositories have one remote and by convention call it origin.

git remote add origin git@github.com:username/repo.git
git remote -v

Output of git remote -v:

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

Two lines per remote: one for fetch, one for push. They are almost always the same URL but can differ — for example, a read-only mirror as fetch and a write-enabled endpoint for push.

The SSH form git@github.com:username/repo.git uses your key pair for authentication. The HTTPS form https://github.com/username/repo.git would require a PAT or credential manager.

Push, Pull, Fetch — The Three Verbs

These three operations move commits between a local repository and a remote. They are distinct.

git fetch — downloads new commits, branches, and tags from the remote. Updates remote-tracking references (origin/main) in your local repository. Does not modify your working directory, local branches, or HEAD. Always safe to run; no local side effects.

git fetch origin

git pull — fetch + merge (or fetch + rebase if configured). Downloads new commits and immediately integrates them into your current branch. If the remote has commits you don't have, your working directory changes. Can produce merge conflicts.

git pull                   # fetch + merge into current branch
git pull --rebase          # fetch + rebase instead of merge

git push — sends your local commits to the remote. Fails if the remote has commits you don't have locally — you must pull first. Requires write permission on the remote branch.

git push origin main       # push local main to remote main

For a solo repository: push after every commit. For shared repositories: fetch to see what is new, pull to integrate, resolve conflicts if any, then push.

Upstream Tracking — Why -u Matters

When you first push a branch, Git does not know which remote branch it corresponds to. The -u flag sets the upstream tracking relationship:

git push -u origin main

This pushes the commits and records that local main tracks origin/main. After this one-time setup, every subsequent push and pull on that branch works without specifying the remote or branch name:

git push    # equivalent to: git push origin main
git pull    # equivalent to: git pull origin main

Verify tracking relationships:

git branch -vv

Output:

* main   b3d9f12 [origin/main] Add scratch notes on experiment branch

[origin/main] confirms the upstream is set. [origin/main: ahead 2] means 2 local commits not yet pushed. [origin/main: behind 3] means the remote has 3 commits you haven't pulled.

How RR Skillverse Actually Deploys — The Full Circle

The series opened with the question of why any of this matters to a working developer. Here is the answer, grounded in a real deployment.

The RR Skillverse platform runs on Azure App Service and is deployed via GitHub Actions. The trigger is a push to origin/main. Every production change flows through this sequence:

git add public/blog.html public/css/main.css public/sw.js
git commit -m "Add Git taxonomy filter and bump SW to v18"
git push origin main

Three things worth noting in this workflow:

Specific files, never git add . — staging by filename means consciously choosing what enters the commit. git add . stages everything in the working directory, including build artifacts, temporary files, and any secret accidentally written to disk. Naming files prevents entire categories of production incidents.

Commit messages describe the why — the message references the service worker version and the taxonomy feature because those are the facts a future engineer needs when reading the log during an incident. "Update files" communicates nothing useful under pressure.

The push triggers the pipeline — GitHub Actions detects the push to main, runs the configured workflow, and the new version deploys to Azure. The local Git command and the production deployment are connected by a single push. That connection is what makes version control foundational to modern engineering, not just a backup mechanism.

Everything in this series — objects, branches, merges, rebases, stashes, tags — exists to make that sequence trustworthy. You can trace exactly what changed, who changed it, when, and why. You can roll back to any tag. You can recover any accidentally lost commit from reflog. The seven posts built the foundations; the git push is where they connect to the real world.

🎯 Quick Check

Q1: What is the difference between git fetch and git pull?

Show Answer

git fetch downloads new commits from the remote and updates remote-tracking references (origin/main) but does not touch your local branches or working directory. git pull is fetch followed by a merge (or rebase) — it downloads and immediately integrates changes into the current branch. Fetch is always safe; pull can produce merge conflicts.

Q2: Why is -u only needed once when pushing a branch?

Show Answer

-u writes the upstream tracking relationship to .git/config. Once written, Git knows that local main corresponds to origin/main. Every subsequent git push and git pull reads that config entry automatically — no need to repeat the remote and branch names.

Q3: Why stage specific files rather than git add . in a production workflow?

Show Answer

Naming files forces a conscious review of what enters the commit. git add . stages everything in the working directory including build artifacts, .env files, and temporary files. In production codebases, one accidentally staged secret or generated file can cause a security incident or a broken deploy. Specificity is the safeguard.

Key Takeaways

  • Git is local version control; GitHub is a cloud hosting platform — separate tools that work together via push and pull
  • GitHub removed password auth in August 2021; SSH keys (ed25519) are the recommended replacement for interactive use
  • Private key stays on your machine; public key goes to GitHub — never the reverse
  • origin is a conventional name for the primary remote, stored as a named URL in .git/config
  • git fetch is safe and read-only; git pull = fetch + merge; git push sends local commits to the remote
  • git push -u origin main sets upstream tracking once; after that git push and git pull work without arguments
  • In real deployment workflows: stage specific files, write meaningful messages, push — and the pipeline does the rest

That is the Git & GitHub Foundation series complete. Seven theory posts, from Git's object model to GitHub deployments. If any concept clicked differently — the staging area as a deliberate buffer, the branch as a 41-byte pointer, why rebase produces linear history — that is exactly what this series was built to deliver. The hands-on track is where those concepts became muscle memory on a repository you own. Take it to your own projects from here.

🛠
Hands-On Practice
Ready to practice what you just read?
Go to Tutorial →