Git basics

Status: 🟩 COMPLETE Last updated: 2026-06-20 Plain-English tagline: The mental model and the 15 commands that cover 95% of day-to-day Git work.


In plain English

Git is the tool you use to track changes to your code over time. It was created by Linus Torvalds in 2005 to manage the Linux kernel (he was unhappy with the existing tools). Today it’s used by virtually every software project on the planet.

Git is a command-line tool β€” you run commands like git commit, git push, git pull. There are GUIs (VS Code’s Git panel, GitHub Desktop, Tower, Fork) that wrap the commands, but understanding the underlying commands matters because that’s what tutorials, error messages, and Claude Code will speak in.

The good news: you can do 95% of daily work with about 15 commands. This entry covers those.


Why it matters

You can’t really work on modern software without Git. Tutorials assume Git. Hosting providers (Vercel, Netlify) assume Git. Collaboration assumes Git. Even your AI assistant assumes Git.

The depth Git rewards is real β€” there are hundreds of commands and many edge cases β€” but the bar for β€œcompetent enough” is much lower than people fear. A short list of patterns covers most of what you’ll do.


The mental model

Git has three β€œplaces” where your files can live at any moment:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    git add     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   git commit   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Working     β”‚ ─────────────▢ β”‚  Staging     β”‚ ─────────────▢ β”‚  Repository  β”‚
β”‚  directory   β”‚                β”‚  area        β”‚                β”‚  (history)   β”‚
β”‚  (your files)β”‚                β”‚  (cart)      β”‚                β”‚              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Working directory β€” the files you’re editing right now.
  2. Staging area β€” a β€œshopping cart” where you select which changes to include in the next commit.
  3. Repository β€” the permanent history of all your commits.

You edit in the working directory, stage changes you want to keep (git add), then commit them (git commit). The commit is permanent in your local history.

To share with others (or back yourself up), you push your commits to a remote β€” usually GitHub.


Setting up Git (once per machine)

# Tell Git who you are (used in commit metadata)
git config --global user.name "George"
git config --global user.email "george@example.com"
 
# Pick your default branch name (modern convention: "main", not "master")
git config --global init.defaultBranch main
 
# Pick how Git handles line endings (CRLF on Windows, LF on Unix)
# Windows users:
git config --global core.autocrlf true
# Mac/Linux users:
git config --global core.autocrlf input

Done. These config values persist forever on this machine.


Starting a new repository

Two ways:

Option A: Start fresh in an existing folder

cd /path/to/project
git init
# Now this folder is a Git repo.

Option B: Clone an existing repo from GitHub

git clone https://github.com/user/repo.git
cd repo
# Now you have a local copy of the repo.

For modern web projects, npx create-next-app automatically runs git init for you. You don’t have to do it manually for new Next.js projects.


The 15 daily-use commands

These are what you’ll actually type:

1. git status β€” what changed?

git status

Shows: files you’ve modified, files staged for commit, files Git doesn’t know about (untracked). Run this constantly. It’s free and reassuring.

2. git add β€” stage changes

git add file.txt                 # stage one file
git add file1.txt file2.txt       # stage multiple
git add .                         # stage everything in the current folder (and below)

Staging is β€œI want this in the next commit.” You can stage some changes and leave others for a future commit β€” useful for keeping commits focused.

3. git commit β€” record the staged changes

git commit -m "Add dark mode toggle"

The -m flag is the commit message. Without it, Git opens an editor for you to write the message.

Good commit messages explain WHY, not what. The diff already shows what changed. Future-you (or your team) wants to know why.

4. git log β€” see the history

git log                  # full log
git log --oneline        # condensed (one line per commit)
git log --oneline -10    # last 10 commits
git log --graph --oneline --all   # visual tree

5. git diff β€” see what changed

git diff                 # unstaged changes
git diff --staged        # staged but not committed changes
git diff HEAD~1          # changes since the previous commit

6. git branch β€” manage branches

git branch                       # list branches
git branch feature/dark-mode     # create a branch (doesn't switch)
git branch -d feature/dark-mode  # delete a branch (only if merged)
git branch -D feature/dark-mode  # FORCE delete (even if not merged β€” careful)

7. git checkout (or modern git switch) β€” switch branches

git checkout main                       # switch to existing branch
git checkout -b feature/dark-mode       # create AND switch
# Modern equivalent:
git switch main
git switch -c feature/dark-mode

git switch is newer and clearer; git checkout is older and overloaded (it does many things). Use switch for branch switching when you can.

8. git merge β€” combine branches

git checkout main
git merge feature/dark-mode

Pulls the changes from feature/dark-mode into main.

9. git push β€” send your commits to the remote

git push                           # push the current branch to its remote tracking branch
git push origin main               # explicit: push main to the remote called "origin"
git push -u origin feature/dark-mode  # first push: set the upstream

10. git pull β€” bring others’ commits to your local repo

git pull               # fetch + merge in one step

git pull is shorthand for git fetch (download changes) + git merge (apply them). For more control, run them separately.

11. git fetch β€” download without applying

git fetch              # see what others have pushed, but don't apply

Useful when you want to inspect remote changes before integrating them.

12. git stash β€” set aside uncommitted work temporarily

git stash              # tuck away uncommitted changes
git stash pop          # bring them back
git stash list         # see your stashes

Useful when you need to switch branches but have uncommitted work you don’t want to commit yet.

13. git remote β€” manage remotes

git remote -v                                         # list remotes
git remote add origin https://github.com/u/r.git      # add a remote
git remote remove origin                              # remove

β€œorigin” is the conventional name for the main remote. You usually have just one.

14. git reset β€” undo

git reset HEAD~1               # uncommit the last commit, keep the changes
git reset --hard HEAD~1        # uncommit AND delete the changes (DANGEROUS)

See Git rescue moves for safer alternatives in most cases.

15. git clone β€” copy a repo from a remote

git clone https://github.com/user/repo.git

Already mentioned but it’s daily-use important.


A typical day, command by command

What a real session looks like:

# Start the day β€” pull the latest
git checkout main
git pull
 
# Create a branch for today's work
git switch -c feature/add-search
 
# ... do work in your editor ...
 
# See what changed
git status
git diff
 
# Stage and commit a coherent chunk
git add lib/search.ts components/SearchBox.tsx
git commit -m "Add fuzzy search to the navbar"
 
# ... more work ...
 
git add app/results/page.tsx
git commit -m "Add results page rendering search hits"
 
# Push the branch to GitHub
git push -u origin feature/add-search
 
# Open a pull request on GitHub (in the web UI or via gh CLI)
gh pr create --title "Add search feature" --body "Adds fuzzy search across notes."
 
# Later β€” after review, merge the PR in GitHub UI
 
# Sync local main and delete the merged branch
git checkout main
git pull
git branch -d feature/add-search

That’s a normal day. Once it’s automatic, you barely think about it.


.gitignore β€” files Git should ignore

A file at your project root called .gitignore lists patterns of files Git should never track:

# Dependencies
node_modules/

# Build outputs
.next/
dist/
build/

# Environment files (often have secrets!)
.env
.env.local
*.env

# IDE files
.vscode/
.idea/

# OS files
.DS_Store
Thumbs.db

Modern frameworks (Next.js, etc.) generate a sensible .gitignore for you. Tweak as you add tools.

Critical: .env* files almost always belong in .gitignore. Accidentally committing secrets to a public repo is one of the most common security disasters.


What a β€œgood” commit looks like

The standards:

  • Focused. One coherent change per commit. Not β€œvarious changes to the app.”
  • Buildable. The code should compile/pass tests at every commit. Don’t commit half-broken state.
  • Well-described. First line = a clear, imperative summary (β€œAdd search,” not β€œAdded search” or β€œadded search functionality to the navbar component because we needed it”). Optional longer body explains why.
  • Why-focused. The diff shows what. The message should illuminate why.

Example:

Add fuzzy search to the navbar

Users were complaining that finding old notes required scrolling
through pages. Fuzzy search lets them type partial titles or
fragments and jump straight to matches.

Uses the `fzf` library (3KB gzipped) β€” small enough that loading
it in the navbar doesn't hurt initial paint.

That commit message will be useful in two years when someone asks β€œwhy does our navbar have a search box?”


Common gotchas

  • .env* files in Git. Triple-check .gitignore before committing a new project. Once a secret is in Git history, it’s effectively public β€” even if you delete the file.

  • Line endings on Windows. git config core.autocrlf true for Windows; otherwise Git will tell you the entire file changed when you just edited one line.

  • git push after rewriting history. Force-pushing (--force) can overwrite work others have based on. Use --force-with-lease instead, which refuses if someone has pushed since you fetched.

  • git add . can stage things you didn’t expect. Including secret files you forgot to gitignore. Use git status to verify before committing, especially for first commits.

  • git commit -a skips the staging step. It auto-stages all modified tracked files. Convenient but bypasses the β€œreview what’s in this commit” benefit. Use carefully.

  • git checkout is overloaded. It switches branches, but also discards file changes β€” git checkout file.txt reverts file.txt to the last committed version. This is why git switch and git restore were introduced.

  • Detached HEAD state. If you git checkout <commit-hash>, you’re in β€œdetached HEAD.” Commits made here aren’t on any branch and can be lost. Switch back to a branch or create one.

  • Branch already exists. git switch -c name fails if name exists. Use git switch name to switch, or git branch -D name to delete first.

  • Pull while having uncommitted changes. Git refuses if it would conflict. Stash, commit, or discard first.

  • β€œYour branch is behind origin/main by N commits.” Normal. Run git pull.

  • β€œYour branch and origin/main have diverged.” Each has commits the other doesn’t. You’ll need to merge or rebase.


See also


Sources