Git & GitHub for Beginners
A practical, example-driven reference. Learn what version control is, how the Git workflow actually feels, and what all those words (origin, HEAD, rebase, PR) mean.
1. What is Git?
Git is a distributed version control system (DVCS). It records snapshots of your project over time so you can:
- See exactly what changed, when, and by whom.
- Go back to any previous state.
- Work on several ideas in parallel without breaking the main code.
- Combine work from multiple people.
Git runs entirely on your computer. GitHub is a website that hosts Git repositories and adds collaboration features on top. You can use Git without GitHub, but GitHub is useless without Git.
| Git | GitHub | |
|---|---|---|
| What it is | A program on your machine | A website / cloud service |
| Job | Tracks versions of files | Stores repos, hosts collaboration |
| Works offline? | Yes, fully | No |
| Made by | Linus Torvalds (2005) | GitHub Inc. (now Microsoft) |
| Alternatives | Mercurial, SVN, Fossil | GitLab, Bitbucket, Codeberg |
Git is a chain of snapshots, not a list of file differences. Each snapshot (a commit) points back to its parent, forming a history graph. A branch is just a movable label pointing at one commit in that graph.
2. The Three Areas
Almost every confusing thing about Git disappears once you understand that your work lives in three places.
| Area | Also called | What lives there |
|---|---|---|
| Working tree | working directory, workspace | The actual files you edit in your editor. |
| Staging area | index, stage, cache | Changes you've marked to go into the next commit. |
| Repository | history, .git, object database |
All commits ever made. Stored in the hidden .git folder. |
Staging lets you commit only some of your changes. You might fix a bug and rename a file in the same editing session β stage and commit them separately so history stays readable.
3. First-Time Setup
Install Git, then tell it who you are. This is done once per machine.
# Identity β attached to every commit you make
git config --global user.name "Ada Lovelace"
git config --global user.email "ada@example.com"
# Name the default branch "main" instead of "master"
git config --global init.defaultBranch main
# Nicer output
git config --global color.ui auto
git config --global pull.rebase false
# Verify everything
git config --list
# Where does Git look for settings? (--global = ~/.gitconfig)
git config --list --show-origin
Connecting to GitHub over SSH (recommended)
# 1. Create a key pair
ssh-keygen -t ed25519 -C "ada@example.com"
# Press Enter for the default path, then set a passphrase
# 2. Copy the PUBLIC key
cat ~/.ssh/id_ed25519.pub
# 3. Paste it into GitHub β Settings β SSH and GPG keys β New SSH key
# 4. Test the connection
ssh -T git@github.com
The file id_ed25519 (no .pub) is private.
Only id_ed25519.pub goes to GitHub.
4. Starting a Repo
Option A β Create a brand new repository
mkdir my-project
cd my-project
git init
# Initialized empty Git repository in /path/my-project/.git/
echo "# My Project" > README.md
git add README.md
git commit -m "Initial commit"
Option B β Copy an existing repository
# HTTPS (asks for a token)
git clone https://github.com/octocat/Hello-World.git
# SSH (uses your key)
git clone git@github.com:octocat/Hello-World.git
# Clone into a specific folder name
git clone git@github.com:octocat/Hello-World.git my-folder
# Shallow clone β faster, no full history
git clone --depth 1 git@github.com:octocat/Hello-World.git
git clone does four things: downloads the history,
creates a remote named origin pointing at the URL,
checks out the default branch, and sets up tracking.
5. The Daily Loop
This is 90% of what you'll ever type:
# 1. See where you are and what's changed
git status
# 2. Look at the actual changes
git diff # unstaged changes
git diff --staged # what's about to be committed
# 3. Stage what you want in the next commit
git add file.txt # one file
git add src/ # a folder
git add . # everything in the current dir
git add -p # choose changes hunk by hunk (very useful)
# 4. Save the snapshot
git commit -m "Add login form validation"
# 5. Send it to GitHub
git push
Reading the log
git log
git log --oneline
git log --oneline --graph --decorate --all
git log -p # with full diffs
git log --author="Ada"
git log --since="2 weeks ago"
git log -- src/app.js # history of one file
git show a1b2c3d # inspect one commit
git blame src/app.js # who last touched each line
Every commit stores: a SHA hash (its ID), the author,
the timestamp, a message, a pointer to its parent commit, and a
snapshot of the whole tree. The SHA is derived from all of that β
change anything and the ID changes.
Writing a good commit message
# Bad
git commit -m "fix stuff"
# Good β imperative mood, explains WHY
git commit -m "Fix crash when email field is empty"
# Better β short subject + blank line + body
git commit -m "Fix crash when email field is empty" \
-m "The validator assumed a non-null value. Added a guard and
a regression test in tests/validation.test.js."
Convention: subject line β€ 50 characters, imperative mood ("Add", "Fix", "Remove" β not "Added" or "Fixes").
6. Branching & Merging
A branch is a lightweight, movable pointer to a commit. Creating one costs nothing and takes no time β so create them liberally.
Working with branches
git branch # list local branches
git branch -a # list local + remote
git branch -v # with last commit
git switch -c feature/login # create AND switch
git switch main # go back to main
# Older syntax (still works everywhere)
git checkout -b feature/login
git checkout main
git branch -d feature/login # delete (safe: only if merged)
git branch -D feature/login # force delete
git branch -m new-name # rename current branch
Merging
# Bring feature work into main
git switch main
git merge feature/login
# Two possible outcomes:
# Fast-forward β main just slides forward, no merge commit
# Three-way β Git creates a merge commit
# Force a merge commit even when fast-forward is possible
git merge --no-ff feature/login
# Undo a merge you haven't pushed
git merge --abort
Merge conflicts
A conflict happens when both branches changed the same lines. Git marks the file and stops:
<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> feature/login
To resolve:
- Open the file and edit it into the version you want.
- Delete the
<<<<<<<,=======, and>>>>>>>markers. git add <file>git commit(Git pre-fills the merge message).
git status # "Unmerged paths" lists conflicted files
git diff # shows conflict markers
# ...edit files...
git add .
git commit
# Or bail out entirely:
git merge --abort
Rebase β the alternative to merging
# Replay your branch's commits on top of the latest main
git switch feature/login
git rebase main
# Interactive: reorder, edit, squash, drop commits
git rebase -i HEAD~3
# If it goes wrong
git rebase --abort
git rebase --continue
Never rebase commits that others have already pulled. Rebase rewrites history (new SHAs); merge preserves it. Rebase your own unpushed work only.
7. GitHub & Remotes
A remote is a named URL to another copy of the repo.
The default name is origin.
# See your remotes
git remote -v
# Add one
git remote add origin git@github.com:ada/my-project.git
# Change where origin points
git remote set-url origin git@github.com:ada/renamed.git
# Remove one
git remote remove origin
Push, fetch, pull
# First push of a new branch: -u sets the upstream tracking link
git push -u origin main
# After that, plain "git push" knows where to go
git push
# Push a different branch
git push origin feature/login
# Delete a remote branch
git push origin --delete feature/login
# Download remote changes WITHOUT touching your files
git fetch
git fetch --all --prune
# Download AND integrate into your current branch
git pull
# git pull = git fetch + git merge (or + git rebase)
# Pull with rebase to keep history linear
git pull --rebase
| Command | Downloads? | Changes your files? |
|---|---|---|
git fetch | Yes | No β safe to run anytime |
git pull | Yes | Yes β merges into current branch |
git push | Uploads | No (changes the remote) |
Fork vs. clone vs. branch
| Term | Where | What it means |
|---|---|---|
| Fork | GitHub (server-side) | Your own copy of someone else's repository under your account. |
| Clone | Your machine | Downloading a repository so you can work on it locally. |
| Branch | Inside one repo | A parallel line of development within the same repository. |
To contribute to a project you don't own: fork it β clone your fork β create a branch β commit β push β open a pull request.
# Keep your fork in sync with the original project
git remote add upstream git@github.com:original-owner/project.git
git fetch upstream
git switch main
git merge upstream/main
git push origin main
8. The Pull Request Flow
A Pull Request (PR) is a GitHub feature, not a Git one. It says: "here's a branch of mine; please review it and merge it into yours."
- Branch off the latest main.
git switch main git pull git switch -c fix/empty-email - Commit your work in small, logical chunks.
git add src/validator.js tests/validator.test.js git commit -m "Guard against empty email in validator" - Push the branch.
git push -u origin fix/empty-email - Open the PR on GitHub. Fill in what changed and why.
- Respond to review β push more commits to the same branch; the PR updates automatically.
- Merge via the GitHub button, then clean up.
git switch main git pull git branch -d fix/empty-email
Merge strategies on GitHub
| Strategy | Result |
|---|---|
| Merge commit | Keeps every commit plus a merge commit. Full history. |
| Squash and merge | Combines all PR commits into one. Clean main history. |
| Rebase and merge | Replays commits onto main with no merge commit. Linear. |
A 50-line PR gets a careful review in 10 minutes. A 2,000-line PR gets "LGTM" and a prayer. Keep them small.
9. Undoing Things
Git almost never loses data β but it helps to know which tool to reach for.
| I want to⦠| Command | Safe? |
|---|---|---|
| Discard changes in a file (not staged) | git restore file.txt |
β οΈ Destructive β no undo |
| Unstage a file (keep the changes) | git restore --staged file.txt |
β Safe |
| Fix the last commit message | git commit --amend -m "New message" |
β οΈ Rewrites history |
| Add a forgotten file to the last commit | git add file && git commit --amend --no-edit |
β οΈ Rewrites history |
| Undo last commit, keep changes staged | git reset --soft HEAD~1 |
β Safe |
| Undo last commit, keep changes unstaged | git reset HEAD~1 |
β Safe |
| Nuke the last commit and all its changes | git reset --hard HEAD~1 |
π Very destructive |
| Undo a commit that's already pushed | git revert <sha> |
β Safe β makes a new commit |
| Park work temporarily | git stash / git stash pop |
β Safe |
| Recover something you thought was lost | git reflog |
β Read-only |
reset vs. revert
-
resetmoves your branch pointer backwards and erases commits from the branch. Use on local, unpushed work. -
revertcreates a new commit that undoes an old one. Use on anything already shared.
Stashing
git stash # save & clean working tree
git stash push -m "wip: login" # with a label
git stash -u # include untracked files
git stash list
git stash pop # reapply and remove from stash
git stash apply stash@{2} # reapply but keep in stash
git stash drop stash@{0}
git stash clear # delete all stashes
The reflog β your safety net
git reflog
# a1b2c3d HEAD@{0}: commit: Fix typo
# 9f8e7d6 HEAD@{1}: reset: moving to HEAD~1
# Recover the "lost" commit
git switch -c rescue 9f8e7d6
# or
git reset --hard 9f8e7d6
Git records every place HEAD has been for ~90 days,
even commits that no longer belong to any branch. Almost nothing is
truly unrecoverable.
Force pushing, safely
# After amending or rebasing a pushed branch
git push --force-with-lease
# Safer than --force: refuses if someone else pushed in the meantime
10. .gitignore & Good Habits
A .gitignore file at the repo root lists patterns Git should
pretend don't exist.
# Dependencies
node_modules/
vendor/
# Build output
dist/
build/
*.min.js
# Environment & secrets β NEVER commit these
.env
.env.local
*.pem
# Editor / OS cruft
.vscode/
.idea/
.DS_Store
Thumbs.db
# Logs
*.log
npm-debug.log*
# Negate: keep this one even though *.log is ignored
!important.log
If you already committed a file you now want ignored
git rm --cached .env # untrack it, keep it on disk
git rm -r --cached node_modules
echo ".env" >> .gitignore
git commit -m "Stop tracking .env"
Adding it to .gitignore afterwards is not enough β
it's still in history. Rotate the credential immediately,
then rewrite history with a tool like git-filter-repo or
BFG Repo-Cleaner.
Habits worth building
- Commit often, commit small. One logical change per commit.
- Pull before you start.
git pull --rebaseon main. - Branch for everything. Never commit straight to
mainon a shared repo. - Run
git statusconstantly. It tells you what Git thinks is happening. - Write messages for future-you, who will have forgotten everything.
- Never commit secrets, large binaries, or
node_modules.
11. Command Cheat Sheet
Setup
git config --global user.name "N" | Set your name |
git config --global user.email "E" | Set your email |
git config --list | Show all settings |
Create & copy
git init | Start a new repo here |
git clone <url> | Copy a remote repo locally |
Inspect
git status | Current state of the three areas |
git diff | Unstaged changes |
git diff --staged | Staged changes |
git log --oneline --graph --all | Compact visual history |
git show <sha> | Details of one commit |
git blame <file> | Who changed each line |
git reflog | Everywhere HEAD has been |
Change
git add <file> | Stage a file |
git add -p | Stage interactively, hunk by hunk |
git commit -m "msg" | Commit staged changes |
git commit --amend | Rewrite the last commit |
git rm <file> | Delete and stage the deletion |
git mv a b | Rename/move and stage it |
Branch & merge
git branch | List branches |
git switch -c <name> | Create and switch |
git switch <name> | Switch branch |
git merge <branch> | Merge into current branch |
git rebase <branch> | Replay commits on top of another |
git cherry-pick <sha> | Copy one commit here |
git branch -d <name> | Delete merged branch |
Share
git remote -v | List remotes |
git fetch | Download, don't merge |
git pull | Download and merge |
git push | Upload commits |
git push -u origin <branch> | Push and set upstream |
git push --force-with-lease | Force push, safely |
Undo
git restore <file> | Discard file changes |
git restore --staged <file> | Unstage |
git reset --soft HEAD~1 | Uncommit, keep staged |
git reset --hard HEAD~1 | Uncommit and delete changes |
git revert <sha> | Undo a pushed commit safely |
git stash / git stash pop | Park / restore work |
12. Common Errors & What They Mean
- fatal: not a git repository
-
You're in a folder that isn't a repo (or a subfolder of one).
cdinto the project or rungit init. - Please tell me who you are
-
Git needs an identity. Run the
git config --global user.nameanduser.emailcommands from Β§3. - Updates were rejected because the remote contains work that you do not have
-
Someone pushed before you.
git pull --rebase, resolve any conflicts, thengit push. - CONFLICT (content): Merge conflict in <file>
-
Two branches changed the same lines. Edit the file, remove the
<<</===/>>>markers,git add,git commit. - Your local changes would be overwritten by merge
-
You have uncommitted edits that clash. Commit them, or
git stashfirst, then pull, thengit stash pop. - detached HEAD
-
You checked out a specific commit or tag rather than a branch. You can
look around, but new commits won't belong to any branch. Fix with
git switch mainorgit switch -c new-branch. - Permission denied (publickey)
-
GitHub doesn't recognize your SSH key. Check
ssh -T git@github.com, make sure your public key is uploaded and your remote URL usesgit@github.com:β¦. - remote: Support for password authentication was removed
- GitHub no longer accepts account passwords over HTTPS. Use SSH, or a Personal Access Token (PAT) as the password.
13. Glossary
Core concepts
- Repository repo
- A project tracked by Git β the files plus the entire history in
.git/. - Working tree (a.k.a. working directory)
- The files as they currently exist on disk, which you edit directly.
- Index (a.k.a. staging area, stage, cache)
- The middle ground where you assemble the next commit.
git addwrites here. - Commit
- A permanent snapshot of the whole project plus metadata (author, message, parent). Identified by a SHA hash.
- SHA (a.k.a. hash, object ID)
- The 40-character hex ID of a commit or object, e.g.
a1b2c3dβ¦. Usually abbreviated to the first 7β10 characters. - Branch
- A movable pointer to a commit. Not a copy of files β just a label.
mainis the conventional primary branch. - HEAD
- A pointer to "where you are right now" β normally the tip of the branch you have checked out.
- Detached HEAD
- HEAD points directly at a commit instead of a branch. New commits here belong to nothing.
- Remote
- A named reference to another copy of the repo, usually on a server. The default is
origin. - origin
- The conventional name of the remote you cloned from. Just a nickname β you can rename it.
- upstream
- Two meanings: (1) the remote branch your local branch tracks; (2) in forking workflows, the original repo you forked from.
- Tracking branch
- A local branch linked to a remote branch, so
git pushandgit pullwork with no arguments. - Clone
- A full local copy of a remote repository, including history.
- Fork
- A server-side copy of someone else's repo into your own GitHub account.
- Merge
- Combining the histories of two branches into one.
- Fast-forward
- A merge where the target branch has no new commits, so Git just slides the pointer forward. No merge commit is created.
- Merge conflict
- Git can't automatically combine changes because both sides edited the same lines. You resolve it by hand.
- Rebase
- Replaying your commits on top of another branch to create a linear history. Rewrites commit SHAs.
- Cherry-pick
- Copying a single commit from one branch onto another.
- Stash
- A temporary shelf for uncommitted changes, so you can switch context cleanly.
- Tag
- A permanent label on a specific commit, typically used for releases, e.g.
v1.2.0. - Diff
- The line-by-line difference between two states of a file.
- Hunk
- A contiguous block of changed lines inside a diff.
git add -pworks hunk by hunk. - HEAD~1 / HEAD^
- Shorthand for "the commit one step before HEAD".
HEAD~3= three commits back. - Reflog
- Git's local log of every place HEAD and branches have pointed. Your recovery tool.
- Detached / dirty working tree
- "Dirty" means you have uncommitted changes. "Clean" means everything is committed.
- .gitignore
- A file listing paths Git should never track.
GitHub terms
- Pull Request PR
- A GitHub request to merge one branch into another, with review and discussion attached. GitLab calls it a Merge Request (MR).
- Issue
- A GitHub thread for reporting a bug, requesting a feature, or discussing a task.
- Review
- Feedback on a PR. Reviewers can Comment, Approve, or Request Changes.
- Actions
- GitHub's built-in CI/CD system. YAML files in
.github/workflows/define automated jobs. - Pages
- Free static website hosting straight from a repo.
- Release
- A tag plus release notes and optional downloadable assets.
- Gist
- A shareable single-file or snippet repository.
- Personal Access Token PAT
- A scoped, revocable token used instead of a password over HTTPS.
- Protected branch
- A branch with rules β e.g. "no direct pushes to main" and "require one approval".
- CODEOWNERS
- A file that auto-assigns reviewers based on which paths a PR touches.
Idioms & slang you'll hear
- "Commit early, commit often"
- Frequent small commits beat one giant commit. Easier to review, revert, and understand.
- "Atomic commit"
- A commit that does exactly one logical thing and leaves the project in a working state.
- "Bikeshedding"
- Arguing at length about trivial details (naming, formatting) while ignoring the hard problems.
- "Nit"
- A minor, optional review comment β "nit: this variable name could be clearer". Not a blocker.
- "LGTM"
- "Looks Good To Me" β approval in review slang.
- "WIP"
- "Work In Progress" β a branch or PR that isn't ready to merge.
- "The golden rule of rebase"
- Never rebase commits that have already been pushed and shared.
- "Force push with lease"
- Using
--force-with-leaseinstead of--force, so you won't clobber a teammate's work. - "Merge hell"
- A huge, painful conflict caused by long-lived branches diverging too far from main.
- "YOLO merge"
- Merging without reading the diff. Don't.
- "Blame"
git blameshows which commit last changed each line. It's a diagnostic tool, not an accusation.- "Bisect"
git bisectbinary-searches your history to find which commit introduced a bug.- "Clean tree"
git statusreports nothing to commit. A nice place to be before switching branches.- "History rewrite"
- Changing existing commits β via
amend,rebase, orfilter-repo. Changes SHAs. - "Squash"
- Combining several commits into one, usually right before merging a PR.
- "The sacred main branch"
- The half-joking idea that
mainmust always be deployable and never receive direct pushes. - "Working on a dirty tree"
- Having uncommitted changes while trying to switch branches β a common source of confusion.
14. Acronyms
| Acronym | Stands for | Meaning in context |
|---|---|---|
| VCS | Version Control System | Software that tracks file history. |
| DVCS | Distributed Version Control System | Every clone has the full history β Git is one. |
| SCM | Source Control Management | Another name for version control tooling. |
| SHA | Secure Hash Algorithm | The commit ID hash, e.g. a1b2c3d. |
| HEAD | β (not an acronym) | Pointer to your current commit/branch. |
| PR | Pull Request | GitHub's merge proposal + review thread. |
| MR | Merge Request | GitLab's equivalent of a PR. |
| CI | Continuous Integration | Automatically building and testing every push. |
| CD | Continuous Delivery / Deployment | Automatically shipping tested code. |
| SSH | Secure Shell | Key-based authentication method for Git. |
| PAT | Personal Access Token | Password replacement for HTTPS Git operations. |
| 2FA | Two-Factor Authentication | Required for GitHub accounts; forces PATs over HTTPS. |
| LGTM | Looks Good To Me | Reviewer approval shorthand. |
| WIP | Work In Progress | Not ready to merge. |
| OSS | Open Source Software | Publicly licensed, community-developed code. |
| CLI | Command-Line Interface | Using Git in a terminal. |
| GUI | Graphical User Interface | GitHub Desktop, GitKraken, VS Code's Git panel, etc. |
| LFS | Large File Storage | Git extension for big binaries (images, video, datasets). |
| YAML | YAML Ain't Markup Language | Config format used by GitHub Actions workflows. |
| MIT / GPL / Apache | β | Common open-source license types. |
Official book: Pro Git (free at git-scm.com/book) Β·
Interactive practice: Learn Git Branching Β·
Docs: docs.github.com Β· Quick help: git help <command>
or git <command> --help.