Everyday Git: the commands that matter
In this series (8 parts)
Git has hundreds of commands. You will use about fifteen regularly. This article covers those fifteen and the mental model that ties them together.
If you read the internals article, you know that Git stores snapshots as objects and uses refs as pointers. Every command below manipulates those objects and refs in predictable ways.
Starting a repository
Two ways to begin.
# Create a new repository
git init my-project
cd my-project
# Clone an existing one
git clone https://github.com/org/repo.git
cd repo
git init creates the .git directory with an empty object database. git clone does the same, then fetches all objects from the remote and checks out the default branch.
The three areas
Git has three areas you need to understand before any command makes sense.
graph LR WD["Working Directory"] -->|git add| SA["Staging Area<br/>(Index)"] SA -->|git commit| LR["Local Repository<br/>(.git)"] LR -->|git checkout| WD LR -->|git push| RR["Remote Repository"] RR -->|git fetch| LR RR -->|git pull| WD
The three local areas plus the remote. Each command moves data between specific areas.
The working directory is what you see in your file system. The staging area (also called the index) holds the next snapshot you plan to commit. The repository stores all committed snapshots.
Tracking changes
git status
Shows which files are modified, staged, or untracked.
git status
# On branch main
# Changes not staged for commit:
# modified: src/app.js
# Untracked files:
# src/utils.js
Run this constantly. It tells you exactly where things stand.
git diff
Shows line-by-line changes.
# Changes in working directory (not yet staged)
git diff
# Changes staged for commit
git diff --staged
# Between two commits
git diff abc123 def456
Without arguments, git diff compares the working directory against the staging area. With --staged, it compares the staging area against the last commit.
Staging and committing
git add
Moves changes from the working directory into the staging area.
# Stage a specific file
git add src/app.js
# Stage all changes
git add .
# Stage parts of a file interactively
git add -p src/app.js
git add -p is worth learning. It lets you stage individual hunks within a file, which keeps commits focused.
git commit
Creates a new commit object from the staging area.
# Commit with a message
git commit -m "Add user authentication"
# Open editor for a longer message
git commit
# Stage all tracked files and commit in one step
git commit -am "Fix validation bug"
Each commit gets a SHA-1 hash, points to a tree snapshot, and links to its parent commit. The branch pointer advances to the new commit.
Amending commits
Made a typo in the last commit message? Forgot to stage a file?
# Fix the last commit message
git commit --amend -m "Add user authentication module"
# Add a forgotten file to the last commit
git add forgotten-file.js
git commit --amend --no-edit
Amend creates a new commit object with a new hash. The old commit becomes unreachable. Never amend commits that have been pushed to a shared branch.
Viewing history
git log
Shows commit history.
# Default log
git log
# Compact one-line format
git log --oneline
# With graph visualization
git log --oneline --graph --all
# Filter by author
git log --author="Alice"
# Filter by date
git log --since="2024-01-01" --until="2024-06-01"
git log --oneline --graph --all is the single most useful log command. It shows every branch and how they relate.
Working with remotes
git remote
Manages remote repository connections.
# List remotes
git remote -v
# Add a remote
git remote add upstream https://github.com/original/repo.git
A remote is a named URL. origin is the conventional name for the primary remote.
git fetch
Downloads objects and refs from a remote without changing your working directory.
# Fetch from origin
git fetch origin
# Fetch all remotes
git fetch --all
Fetch is always safe. It updates your remote-tracking branches (origin/main, origin/feature) but never touches your local branches or working directory.
git pull
Fetches and then integrates changes into your current branch.
# Pull with merge (default)
git pull origin main
# Pull with rebase
git pull --rebase origin main
git pull is shorthand for git fetch followed by git merge (or git rebase with the --rebase flag). Many teams prefer --rebase to keep linear history.
git push
Uploads local commits to a remote.
# Push current branch
git push origin main
# Push and set upstream tracking
git push -u origin feature
# Push all branches
git push --all origin
If the remote has commits you don’t have, the push is rejected. Fetch and integrate first.
The staging area in depth
The staging area is a binary file (.git/index) that stores a sorted list of filenames, permissions, and blob hashes. When you run git add, Git creates a blob object for the file and updates the index entry.
This design lets you craft precise commits. You can modify five files but only stage two of them. The commit captures exactly what you staged.
# See what is in the index
git ls-files --stage
Ignoring files
The .gitignore file tells Git which files to skip. Patterns are matched against paths relative to the repository root.
# Dependencies
node_modules/
# Build output
dist/
build/
# Environment files
.env
.env.local
# OS files
.DS_Store
Thumbs.db
# Logs
*.log
Rules:
- Patterns without a slash match filenames anywhere in the tree.
- Patterns with a trailing slash match directories.
- A leading
!negates a pattern. - Lines starting with
#are comments.
Files already tracked by Git are not affected by .gitignore. You need to untrack them first.
# Stop tracking a file that is now ignored
git rm --cached .env
Stashing work
Sometimes you need to switch context without committing half-done work.
# Stash current changes
git stash
# Stash with a message
git stash push -m "WIP: auth refactor"
# List stashes
git stash list
# Apply the most recent stash
git stash pop
# Apply without removing from stash list
git stash apply
# Apply a specific stash
git stash apply stash@{2}
Stash creates temporary commit objects that are not on any branch. pop applies the stash and removes it from the list. apply keeps it.
Stash tips
# Stash including untracked files
git stash -u
# Stash including ignored files
git stash -a
# Create a branch from a stash
git stash branch new-feature stash@{0}
Quick reference
| Task | Command |
|---|---|
| Initialize repo | git init |
| Clone repo | git clone <url> |
| Check status | git status |
| Stage files | git add <files> |
| Commit | git commit -m "msg" |
| View log | git log --oneline --graph |
| See changes | git diff |
| Fetch updates | git fetch origin |
| Pull updates | git pull --rebase |
| Push commits | git push origin <branch> |
| Stash work | git stash push -m "msg" |
| Apply stash | git stash pop |
What comes next
With the everyday commands covered, the next article explores branching and merging. You already know that a branch is a pointer to a commit. The next step is understanding what happens when two branches diverge and need to come back together.