git, version-control, git-commands, developer-tools, command-line, github
The Most Commonly Used Git Commands Every Developer Should Know
A practical guide to everyday Git commands, explaining when to use each one with real examples, from setting up a repository to branching, merging, rebasing, and undoing mistakes.
Git is the version control system almost every software team uses today. It records the history of your code, lets several people work on the same project without overwriting each other's changes, and makes it possible to try out ideas on a branch and throw them away if they don't work.
Git has well over a hundred commands, but day-to-day work relies on a much smaller set. This article walks through the commands you are most likely to use, grouped by the job they do. For each one you'll find what it is for, when to reach for it, and example commands you can run.
A Quick Mental Model
Before looking at commands, it helps to know the three places your changes can live in a Git repository:
- Working directory: the files you see and edit on disk.
- Staging area (also called the index): a holding area for the changes you want to include in your next commit.
- Repository: the history of commits, stored in the hidden
.gitfolder.
A typical change moves from the working directory to the staging area with git add, and from the staging area into the repository with git commit. When you work with a team, you also have a remote repository (for example on GitHub or GitLab), which you sync with using git fetch, git pull, and git push.
Working directory --git add--> Staging area --git commit--> Local repository --git push--> Remote
^ | |
+------------------------- git checkout / restore ---------+<------ git fetch/pull --+
Setting Up Git
git config
Use case: Tell Git who you are and how you like it to behave. Every commit records an author name and email, so this is the first thing to set on a new machine.
# Set your identity for every repository on this machine
git config --global user.name "Pratik Chaudhari"
git config --global user.email "pratik@example.com"
# Use "main" as the default branch name for new repositories
git config --global init.defaultBranch main
# Set your preferred editor for commit messages
git config --global core.editor "code --wait"
# Override the email for just the current repository
git config user.email "pratik@work-company.com"
# See all settings and where they come from
git config --list --show-origin
Settings saved with --global live in ~/.gitconfig and apply everywhere. Settings without it are stored in the current repository's .git/config and take priority.
git init
Use case: Turn an existing folder into a new Git repository. Use it when you start a project from scratch.
mkdir my-project && cd my-project
git init
# Initialized empty Git repository in /Users/pratik/my-project/.git/
git init creates the .git folder. Nothing is tracked until you add and commit files.
git clone
Use case: Download a copy of an existing repository, including its full history, so you can work on it locally.
# Clone over HTTPS
git clone https://github.com/user/project.git
# Clone over SSH into a folder with a different name
git clone git@github.com:user/project.git my-project
# Clone only the latest snapshot of a large repository
git clone --depth 1 https://github.com/user/huge-project.git
# Clone and check out a specific branch
git clone --branch develop https://github.com/user/project.git
Cloning also sets up a remote called origin that points back to where you cloned from.
Recording Changes
git status
Use case: See what has changed. It shows which files are modified, which are staged for the next commit, and which are untracked. Run it often, especially before committing.
git status
# On branch main
# Changes to be committed:
# modified: src/app.js
# Changes not staged for commit:
# modified: README.md
# Untracked files:
# notes.txt
# A compact, one-line-per-file view
git status -s
# M src/app.js
# M README.md
# ?? notes.txt
In the short format, the first column shows the staging area and the second shows the working directory. ?? means the file is untracked.
git add
Use case: Choose which changes go into the next commit by moving them into the staging area.
# Stage one file
git add src/app.js
# Stage everything in the current directory and below
git add .
# Stage all changes in the repository, including deletions
git add -A
# Stage only parts of a file, choosing hunk by hunk
git add -p src/app.js
git add -p is especially useful when one file contains two unrelated changes and you want to commit them separately.
git commit
Use case: Save a snapshot of the staged changes to the repository's history, with a message describing what changed and why.
# Commit with a short message
git commit -m "Add login form validation"
# Commit with a subject line and a longer body
git commit -m "Fix race condition in cache refresh" \
-m "Two threads could refresh the same key at once. Use a lock per key."
# Stage all tracked, modified files and commit in one step
git commit -am "Update dependencies"
# Fix the last commit's message or add a forgotten file
git add forgotten-file.js
git commit --amend --no-edit
Note that -a does not include brand-new files; those still need git add. Only use --amend on commits you haven't pushed yet, because it rewrites history.
git diff
Use case: See exactly what changed, line by line, before you stage or commit it.
# Changes in the working directory that are not staged yet
git diff
# Changes that are staged and will go into the next commit
git diff --staged
# Differences between two branches
git diff main..feature/login
# Only the names of changed files
git diff --name-only main..feature/login
# Changes to one file compared with the last commit
git diff HEAD -- src/app.js
git rm and git mv
Use case: Delete or rename tracked files in a way that Git records immediately.
# Delete a file and stage the deletion
git rm old-script.sh
# Stop tracking a file but keep it on disk (for example, after adding it to .gitignore)
git rm --cached .env
# Rename or move a file
git mv utils.js helpers.js
.gitignore
Use case: Not a command, but closely related. A .gitignore file lists files and folders Git should never track, such as build output, dependencies, and secrets.
cat > .gitignore <<'IGNORE'
node_modules/
dist/
.env
*.log
.DS_Store
IGNORE
git add .gitignore
git commit -m "Add .gitignore"
Inspecting History
git log
Use case: Browse the commit history to see who changed what and when.
# Full history of the current branch
git log
# One line per commit
git log --oneline
# A visual graph of all branches
git log --oneline --graph --all --decorate
# The last 5 commits
git log -5
# Commits by a particular author since a date
git log --author="Pratik" --since="2026-10-01"
# Commits whose message mentions a word
git log --grep="hotfix"
# History of a single file, including changes in each commit
git log -p -- src/app.js
# Commits that added or removed a particular string
git log -S "calculateTax"
git show
Use case: Look at the details of a single commit, tag, or file at a point in time.
# The most recent commit and its changes
git show
# A specific commit
git show 543d131
# Only the list of files a commit touched
git show --stat 543d131
# A file as it was in an older commit
git show 543d131:src/app.js
git blame
Use case: Find out who last changed each line of a file and in which commit. Handy when you need context for a confusing piece of code.
git blame src/app.js
# Only lines 40 to 60
git blame -L 40,60 src/app.js
Working with Branches
Branches let you work on a feature or fix in isolation without affecting the main line of development.
git branch
Use case: List, create, rename, and delete branches.
# List local branches (the current one is marked with *)
git branch
# List local and remote branches
git branch -a
# Create a branch without switching to it
git branch feature/payments
# Rename the current branch
git branch -m feature/checkout
# Delete a branch that has been merged
git branch -d feature/payments
# Force-delete a branch that hasn't been merged
git branch -D experiment
# Show branches already merged into main
git branch --merged main
git switch
Use case: Move between branches. git switch was added in Git 2.23 as a clearer alternative to the branch-switching side of git checkout.
# Switch to an existing branch
git switch main
# Create a new branch and switch to it
git switch -c feature/search
# Go back to the previous branch
git switch -
# Create a local branch that tracks a remote one
git switch -c bugfix/123 origin/bugfix/123
git checkout
Use case: The older, all-purpose command for switching branches and restoring files. You'll still see it everywhere in tutorials and scripts.
# Switch branches
git checkout main
# Create and switch to a new branch
git checkout -b feature/search
# Look at the project as it was at an old commit (a "detached HEAD")
git checkout 543d131
# Discard changes to a file in the working directory
git checkout -- src/app.js
git restore
Use case: Undo changes to files. Like git switch, it splits a job out of git checkout into a clearer command.
# Discard uncommitted changes to a file
git restore src/app.js
# Unstage a file but keep its changes
git restore --staged src/app.js
# Restore a file to how it was in a specific commit
git restore --source=543d131 src/app.js
Combining Work
git merge
Use case: Bring the changes from one branch into another. This is the most common way to integrate a finished feature.
# Merge feature/search into main
git switch main
git merge feature/search
# Always create a merge commit, even when a fast-forward is possible
git merge --no-ff feature/search
# Combine all of a branch's commits into one staged change, then commit it yourself
git merge --squash feature/search
git commit -m "Add search feature"
# Give up on a merge that has conflicts
git merge --abort
If both branches changed the same lines, Git stops with a merge conflict and marks the file like this:
<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> feature/search
Edit the file to keep the right version, remove the markers, then finish the merge:
git add src/config.js
git commit
git rebase
Use case: Move your branch's commits so they sit on top of another branch, producing a straight, linear history instead of merge commits. Also used to clean up commits before sharing them.
# Replay feature/search on top of the latest main
git switch feature/search
git rebase main
# If a conflict happens, fix it, then continue
git add src/config.js
git rebase --continue
# Or give up and return to how things were
git rebase --abort
# Interactively squash, reorder, reword, or drop the last 4 commits
git rebase -i HEAD~4
In the interactive editor, change pick to squash (or s) to fold a commit into the one above it, reword (or r) to edit its message, or drop (or d) to remove it.
The golden rule: don't rebase commits that others have already pulled. Rebasing creates new commits with new IDs, which causes trouble for anyone who built on the old ones.
git cherry-pick
Use case: Copy one or more specific commits from another branch onto your current branch, without merging the whole branch. Often used to bring a bug fix into a release branch.
git switch release/2.1
git cherry-pick a1b2c3d
# Pick several commits
git cherry-pick a1b2c3d e4f5g6h
# Apply the changes without committing, so you can adjust them first
git cherry-pick --no-commit a1b2c3d
Working with Remotes
git remote
Use case: Manage the list of remote repositories your local repository knows about.
# List remotes with their URLs
git remote -v
# Add a remote, for example the original repo you forked from
git remote add upstream https://github.com/original/project.git
# Change a remote's URL (for example, switching from HTTPS to SSH)
git remote set-url origin git@github.com:user/project.git
# Remove a remote
git remote remove upstream
git fetch
Use case: Download new commits and branches from a remote without changing your working files or current branch. It's the safe way to see what others have pushed.
# Fetch from origin
git fetch origin
# Fetch from all remotes and remove branches deleted on the remote
git fetch --all --prune
# See what came in on main
git log --oneline main..origin/main
git pull
Use case: Fetch from a remote and immediately integrate the changes into your current branch. It's essentially git fetch followed by git merge (or git rebase).
# Pull and merge
git pull
# Pull and rebase your local commits on top, avoiding a merge commit
git pull --rebase
# Make rebase the default for pulls
git config --global pull.rebase true
# Pull a specific branch from a specific remote
git pull upstream main
git push
Use case: Upload your local commits to a remote repository so others can see them.
# Push the current branch
git push
# Push a new branch and set it to track the remote branch
git push -u origin feature/search
# Delete a branch on the remote
git push origin --delete feature/search
# Push tags
git push origin --tags
# Safely overwrite the remote branch after a rebase
git push --force-with-lease
Prefer --force-with-lease over --force. It refuses to overwrite the remote branch if someone else has pushed to it since you last fetched, so you don't wipe out a teammate's work.
Saving Work in Progress
git stash
Use case: Temporarily put aside uncommitted changes so you can switch branches or pull, then bring them back later.
# Stash tracked changes
git stash
# Stash with a description, including untracked files
git stash push -u -m "WIP: search filters"
# List stashes
git stash list
# stash@{0}: On feature/search: WIP: search filters
# Reapply the latest stash and remove it from the list
git stash pop
# Reapply a specific stash but keep it in the list
git stash apply stash@{1}
# See what's in a stash
git stash show -p stash@{0}
# Delete a stash
git stash drop stash@{0}
A typical use: you're halfway through a feature when an urgent bug comes in.
git stash push -m "WIP: feature"
git switch main
git switch -c hotfix/login-crash
# ...fix, commit, push...
git switch feature/search
git stash pop
Undoing Things
git reset
Use case: Move the current branch back to an earlier commit, optionally unstaging or discarding changes. Best used on commits you haven't pushed.
# Undo the last commit but keep its changes staged
git reset --soft HEAD~1
# Undo the last commit and unstage its changes, keeping them in your files (the default)
git reset HEAD~1
# Undo the last commit and throw away its changes completely
git reset --hard HEAD~1
# Unstage a single file
git reset src/app.js
--hard permanently discards uncommitted work, so double-check before running it.
git revert
Use case: Undo a commit by creating a new commit that does the opposite. Unlike reset, it doesn't rewrite history, so it's the safe way to undo something that's already been pushed.
# Revert a specific commit
git revert a1b2c3d
# Revert without committing immediately, to combine several reverts
git revert --no-commit a1b2c3d e4f5g6h
git commit -m "Revert broken caching changes"
# Revert a merge commit, keeping the first parent's side
git revert -m 1 9f8e7d6
git reflog
Use case: Recover "lost" work. The reflog records every place HEAD has pointed to recently, even after a bad reset or rebase.
git reflog
# 543d131 HEAD@{0}: reset: moving to HEAD~3
# 9a8b7c6 HEAD@{1}: commit: Add payment retry logic
# ...
# Bring the branch back to before the reset
git reset --hard HEAD@{1}
# Or rescue a commit onto a new branch
git switch -c rescue 9a8b7c6
git clean
Use case: Delete untracked files and folders, such as build leftovers, from the working directory.
# Preview what would be deleted
git clean -n
# Delete untracked files
git clean -f
# Delete untracked files and directories
git clean -fd
# Also delete ignored files (like build output)
git clean -fdx
Always run git clean -n first, because deleted untracked files can't be recovered with Git.
Tagging Releases
git tag
Use case: Mark a specific commit as important, usually a release version.
# List tags
git tag
# Create an annotated tag (recommended for releases)
git tag -a v1.2.0 -m "Release 1.2.0"
# Tag an older commit
git tag -a v1.1.1 a1b2c3d -m "Patch release"
# Push a tag, or all tags
git push origin v1.2.0
git push origin --tags
# Delete a tag locally and on the remote
git tag -d v1.2.0
git push origin --delete v1.2.0
Debugging with Git
git bisect
Use case: Find the commit that introduced a bug by doing a binary search through history. Instead of checking hundreds of commits, Git narrows it down in a handful of steps.
git bisect start
git bisect bad # the current commit has the bug
git bisect good v1.1.0 # this release didn't
# Git checks out a commit in the middle; test it, then tell Git the result
git bisect good # or: git bisect bad
# Repeat until Git reports "<commit> is the first bad commit", then finish
git bisect reset
If you have a script that exits with 0 when things work and non-zero when they don't, Git can do the whole search for you:
git bisect start HEAD v1.1.0
git bisect run npm test
Handy Extras
git worktree
Use case: Check out a second branch into a separate folder at the same time, without stashing or cloning again. Useful when reviewing a pull request while your own work is half-done.
# Check out hotfix/login-crash in a sibling folder
git worktree add ../project-hotfix hotfix/login-crash
# List worktrees
git worktree list
# Remove it when you're done
git worktree remove ../project-hotfix
Aliases
Use case: Save typing on commands you use constantly.
git config --global alias.st "status -s"
git config --global alias.co checkout
git config --global alias.lg "log --oneline --graph --all --decorate"
git st
git lg
A Typical Day with Git
Here is how many of these commands fit together in a normal feature workflow:
# 1. Start from an up-to-date main
git switch main
git pull --rebase
# 2. Create a feature branch
git switch -c feature/user-profile
# 3. Work, checking and staging changes as you go
git status
git diff
git add -p
git commit -m "Add user profile page"
# 4. Keep the branch current with main
git fetch origin
git rebase origin/main
# 5. Share the branch and open a pull request
git push -u origin feature/user-profile
# 6. After the pull request is merged, tidy up
git switch main
git pull
git branch -d feature/user-profile
git fetch --prune
Quick Reference
| Command | What it's for |
|---|---|
git config |
Set your identity and preferences |
git init |
Create a new repository |
git clone |
Copy an existing repository |
git status |
See what has changed |
git add |
Stage changes for the next commit |
git commit |
Save staged changes to history |
git diff |
Show line-by-line changes |
git log |
Browse commit history |
git show |
Inspect one commit |
git blame |
See who last changed each line |
git branch |
List, create, rename, delete branches |
git switch / git checkout |
Move between branches |
git restore |
Discard or unstage file changes |
git merge |
Combine branches |
git rebase |
Replay commits onto another base |
git cherry-pick |
Copy specific commits |
git remote |
Manage remote repositories |
git fetch |
Download remote changes without merging |
git pull |
Download and integrate remote changes |
git push |
Upload local commits |
git stash |
Set aside work in progress |
git reset |
Move a branch back, unstage changes |
git revert |
Undo a commit safely with a new commit |
git reflog |
Recover lost commits |
git clean |
Remove untracked files |
git tag |
Mark releases |
git bisect |
Find the commit that introduced a bug |
git worktree |
Work on several branches at once |
Learning these commands well covers the vast majority of what you'll do with Git. The rest you can look up with git help <command> when you need it, and git reflog is there to rescue you when an experiment goes wrong.