Git Commands Every Developer Should Know
Git is the backbone of modern software development. Yet many developers only scratch the surface, sticking to add, commit, and push. Let’s change that. Here are the Git commands and workflows that will make you faster, safer, and more confident.
The Basics, Done Right
Write Better Commit Messages
Before we dive into commands, let’s talk commits. Good commit messages are a gift to your future self and teammates.
# ❌ Vague and unhelpful
git commit -m "fixed stuff"
# ✅ Clear and descriptive
git commit -m "fix: resolve null pointer exception in user authentication"
Consider using Conventional Commits: feat:, fix:, docs:, refactor:, test:, etc.
Stage Interactively
Don’t just git add . everything. Use interactive staging to craft clean, logical commits:
# Stage specific hunks within a file
git add -p
# This prompts you for each change:
# y - stage this hunk
# n - skip this hunk
# s - split into smaller hunks
# e - manually edit the hunk
Undoing Mistakes
We all make mistakes. Git makes it easy to recover.
Undo Your Last Commit (Keep Changes)
# Undo commit but keep changes staged
git reset --soft HEAD~1
# Undo commit and unstage changes (but keep files)
git reset HEAD~1
# ⚠️ Undo commit and discard all changes (dangerous!)
git reset --hard HEAD~1
Fix Your Last Commit Message
git commit --amend -m "New, better commit message"
Accidentally Staged a File?
# Unstage a specific file
git restore --staged filename.js
# Unstage everything
git restore --staged .
Discard Local Changes
# Discard changes in a specific file
git restore filename.js
# Discard all local changes (careful!)
git restore .
Branching Like a Pro
Create and Switch in One Command
# Old way (two commands)
git branch feature/new-login
git checkout feature/new-login
# New way (one command)
git switch -c feature/new-login
See All Branches (Local and Remote)
git branch -a
Delete Branches Safely
# Delete local branch (only if merged)
git branch -d feature/old-branch
# Force delete local branch
git branch -D feature/old-branch
# Delete remote branch
git push origin --delete feature/old-branch
Clean Up Stale Remote Branches
# Remove references to deleted remote branches
git fetch --prune
The Power of Stash
Stash lets you temporarily shelve changes without committing.
# Stash current changes
git stash
# Stash with a descriptive message
git stash push -m "WIP: halfway through refactoring auth"
# List all stashes
git stash list
# Apply most recent stash (keeps it in stash list)
git stash apply
# Apply and remove from stash list
git stash pop
# Apply a specific stash
git stash apply stash@{2}
# Drop a specific stash
git stash drop stash@{0}
Rebase: Cleaner History
Rebasing rewrites history to create a linear commit timeline. Use it to keep your feature branch up to date.
# Rebase your feature branch onto main
git checkout feature/my-feature
git rebase main
# Interactive rebase to squash/edit last 3 commits
git rebase -i HEAD~3
Interactive Rebase Commands
When you run git rebase -i, you’ll see options like:
pick— keep the commit as-issquash— combine with previous commitreword— change the commit messageedit— pause to amend the commitdrop— remove the commit entirely
Pro tip: Squash your WIP commits before merging a PR:
# Squash all commits on your branch into one
git rebase -i main
# Then change all but the first "pick" to "squash"
Finding Things
Search Commit History
# Find commits containing a specific message
git log --grep="authentication"
# Find commits that changed a specific file
git log -- path/to/file.js
# Find who changed a specific line
git blame path/to/file.js
Find When a Bug Was Introduced
# Binary search through commits
git bisect start
git bisect bad # Current commit is broken
git bisect good abc123 # This old commit was working
# Git will checkout commits for you to test
# After testing each:
git bisect good # or
git bisect bad
# When done:
git bisect reset
Working with Remotes
View Remote URLs
git remote -v
Add Multiple Remotes
# Add upstream for a forked repo
git remote add upstream https://github.com/original/repo.git
# Fetch from upstream
git fetch upstream
# Merge upstream changes into your branch
git merge upstream/main
Push a New Branch
# Push and set upstream tracking
git push -u origin feature/my-feature
Cherry-Pick: Selective Commits
Apply specific commits from another branch:
# Apply a single commit to current branch
git cherry-pick abc123
# Apply multiple commits
git cherry-pick abc123 def456
# Cherry-pick without committing (just stage changes)
git cherry-pick --no-commit abc123
Useful Aliases
Add these to your ~/.gitconfig:
[alias]
co = checkout
br = branch
ci = commit
st = status
unstage = reset HEAD --
last = log -1 HEAD
visual = log --oneline --graph --decorate --all
amend = commit --amend --no-edit
Now you can use git visual for a beautiful branch graph or git amend to quickly add to your last commit.
The Golden Rules
- Commit often, push regularly — Small commits are easier to review and revert
- Never rebase shared branches — Only rebase your own feature branches
- Write meaningful messages — Your future self will thank you
- Use branches liberally — They’re cheap and keep work isolated
- Review before pushing —
git diff --stagedis your friend
Git has a learning curve, but mastering it pays dividends every day. What’s your favorite Git trick? Drop it in the comments!