15 Git Commands Every Developer Should Know (And Actually Use)
Git is not optional. If you cannot control your code history, you are not a professional developer.
Most developers learned Git by copying commands from Stack Overflow and calling it a day. They know enough to push and pull without breaking things most of the time, but that is not the same as actually knowing Git.
Git is the backbone of every professional software project. If you cannot use it confidently, you are a liability to your team. Hiring managers can smell that. Senior engineers know it the moment they see your commit history, with messages like "stuff" and "fix" and 47 changes crammed into one commit.
This list covers the 15 Git commands every developer needs to know. Not just the basics every beginner tutorial covers, but the ones that separate developers who fumble through version control from developers who own it. Each command is real, practical, and comes with the opinionated context that most tutorials leave out.
If you treat Git like a magic upload button, this list will change how you work. If you already know the basics and want to fill in the gaps, pay close attention to the later commands. That is where most developers stop growing.
1. git init
Every repository starts here. Running git init in a directory tells Git to start tracking changes in that folder. It creates a hidden .git folder that contains your entire project history, every commit, every branch, every reference.
The command:
git initOnce initialized, configure who you are:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"Skip that configuration step and Git will tag your commits with wrong or empty information. In a professional environment, showing up with anonymous commits looks sloppy at best and suspicious at worst.
You use git init when starting a fresh project from scratch. If you are joining an existing project, you use git clone instead. The important thing to understand is that git init is entirely local. Nothing goes to GitHub, GitLab, or anywhere else until you explicitly tell it to. That distinction matters when something goes wrong and you need to know whether your work exists only on your machine.
2. git clone
When you join a project that already exists, git clone is how you get it onto your machine. One command downloads the entire repository, including all branches, the complete commit history, and all files.
git clone https://github.com/user/repo.gitWhat most developers miss: git clone also sets up the remote connection automatically. The original repository gets added as origin, so you can push and pull without any extra configuration. You can also clone into a specific folder name:
git clone https://github.com/user/repo.git my-projectFor private repositories using SSH:
git clone git@github.com:user/repo.gitIf you are working on any real team, you are starting with git clone, not git init. Get comfortable with SSH-based cloning too. HTTPS works but requires credential management. SSH is cleaner for daily use once your key is set up.
3. git status
This is your constant sanity check. Run it whenever you want to know what is going on in your working directory. It shows you what files have changed, what is staged for the next commit, and what Git does not know about yet.
git statusSenior developers run this constantly. Junior developers skip it and then wonder why their commit contains files they did not mean to include, or why they accidentally committed a .env file with real credentials in it.
The output tells you three things every time:
- Changes staged for commit (in the holding area, ready to commit)
- Changes not staged (modified but not yet added to staging)
- Untracked files (Git does not know these exist yet)
None of that is complicated. But ignoring it regularly is how you end up in situations that take an hour to untangle. Make git status a reflex. Run it before staging, before committing, before pushing, and whenever you feel disoriented about the state of your code.
4. git add
Before Git saves your changes, you tell it what to include. git add moves files from your working directory to the staging area, the holding zone for your next commit.
Stage a specific file:
git add filename.jsStage everything in the current directory:
git add .Stage specific chunks within a file interactively:
git add -p filename.jsThat last option (-p, patch mode) is something most developers never use but should. It walks you through every change chunk by chunk and lets you decide what to include. This is how you write clean, focused commits instead of dumping 30 unrelated changes into one massive blob.
The staging area exists for a reason. It gives you a deliberate moment between making changes and recording them permanently. Developers who use git add . for everything and never look at what they are staging end up with messy histories that are impossible to read. Be intentional about what you stage.
5. git commit
A commit is a permanent snapshot of your code at a specific point in time. Every commit needs a message describing what changed and why.
git commit -m "Add user authentication endpoint"The quality of your commit messages matters more than most developers realize. When something breaks in production at 2 AM, your teammates and future you will be reading through the commit history trying to find what changed. "Fixed stuff" is not useful. "Fix null pointer exception in user login when email field is empty" saves everyone time.
If you committed too soon or need to fix the last commit message:
git commit --amendOnly amend commits you have not pushed yet. Amending rewrites history, and rewriting history that others have already pulled creates problems that take time to resolve.
The rule for structuring commits: one logical change per commit. Not one file, not one hour of work, not one ticket. One cohesive change with a clear purpose. Teams that enforce this have codebases that are far easier to maintain and debug. Teams that ignore it end up with a history that reads like a crime scene.
6. git push and git pull
These two commands sync your local repository with the remote. They are the simplest commands on this list and also the ones developers most often misuse.
Push your local commits to the remote:
git push origin branch-namePull the latest changes from the remote into your local branch:
git pull origin branch-namegit pull is actually two operations combined: git fetch downloads the remote changes, and git merge integrates them. Some developers prefer to use these separately so they can see what is coming before merging it into their branch. Either approach works. The important thing is understanding that git pull does more than just download.
Basic rule: pull before you push. Nothing is more annoying than trying to push and finding out your teammates pushed ahead of you. Pull, resolve any conflicts, then push. If you make this a habit, you will spend almost no time dealing with rejected pushes.
7. git branch
Branches let you work on features or bug fixes in isolation without touching the main codebase. Every meaningful change should happen on its own branch. That is not optional on professional teams.
List all local branches:
git branchCreate a new branch:
git branch feature/user-loginDelete a branch after it has been merged:
git branch -d feature/user-loginForce delete an unmerged branch (use with intention):
git branch -D feature/user-loginProfessional developers work on branches. They never commit directly to main. If you are still making all your changes on main, you are working like a junior developer regardless of your title or years of experience. Branches are cheap in Git. Creating one takes milliseconds. There is no excuse for not using them.
Good branch naming conventions matter too. feature/user-login, fix/payment-null-error, and chore/update-dependencies tell everyone what the branch is for before they even look at it.
8. git checkout / git switch
To move between branches, use git switch (the newer, cleaner command introduced in Git 2.23) or git checkout (the older command that still works everywhere).
Switch to an existing branch:
git switch branch-nameOr with the legacy command:
git checkout branch-nameCreate a new branch and switch to it immediately:
git switch -c feature/new-featureOr:
git checkout -b feature/new-featuregit switch was introduced to separate branch navigation from file restoration, two things git checkout handled confusingly. If you are starting fresh, use git switch. If your team uses git checkout, there is no urgent reason to switch. Either works fine.
The version that matters most in daily work: git switch -c or git checkout -b. Create the branch and move to it in one command. Doing it in two steps is just extra typing.
9. git merge
When your feature branch is ready, you merge it back into the main branch. Switch to the branch you are merging into first, then merge your feature branch:
git switch main
git merge feature/user-loginWhen Git can automatically combine the changes, the merge completes cleanly. When two branches modified the same lines of code, you get a merge conflict. Git marks the conflicts in the affected files with conflict markers and you resolve them manually.
Merge conflicts scare junior developers. They should not. A conflict is just Git saying two changes happened in the same place and it needs you to decide which one wins. Read both versions, pick the right outcome, use git add to mark the conflict resolved, and commit.
The --no-ff flag forces a merge commit even when a fast-forward merge is possible:
git merge --no-ff feature/user-loginThis preserves the fact that a feature branch existed. Whether to use it depends on your team's conventions. If you care about seeing branch structure in your history, use it. If you prefer a clean linear history, skip it and use rebase instead.
10. git rebase
Rebase is the command junior developers avoid because it feels dangerous. That avoidance is a mistake that limits their effectiveness on real teams.
git rebase moves your commits on top of another branch. Instead of creating a merge commit, it replays your branch's commits starting from the current tip of the target branch. The result is a linear history, far easier to read than a tangle of merge commits.
Rebase your feature branch onto main:
git switch feature/user-login
git rebase mainThe rule that every tutorial mentions and not every developer follows: never rebase commits that have already been pushed to a shared remote branch. Rebasing rewrites history. If others have pulled those commits, you will create a mess that is painful to clean up.
Interactive rebase is where the real power lives:
git rebase -i HEAD~3This opens an editor showing the last 3 commits and lets you edit, squash, reorder, rename, or drop them before pushing. It is how you clean up a messy series of work-in-progress commits into one polished commit before opening a pull request. Teams that review code appreciate this. Make it a habit.
11. git stash
You are halfway through a feature and someone says there is a critical production bug that needs fixing right now. You cannot commit half-done code. git stash saves your work-in-progress and clears your working directory so you can switch contexts without losing anything.
Stash your current changes:
git stashList all stashes:
git stash listApply the most recent stash and remove it from the list:
git stash popApply a specific stash without removing it:
git stash apply stash@{2}Save a stash with a descriptive message so you know what it is later:
git stash push -m "half-done user auth feature"Use git stash pop when you want to restore and remove. Use git stash apply when you need to apply the same changes to multiple branches. One thing developers frequently forget: stash also saves untracked files if you use the -u flag. Without it, new files that are not yet tracked by Git will not be stashed and will remain in your working directory when you switch branches.
12. git log
git log shows you the commit history. Most developers run it with no arguments, get a wall of text, scroll for five seconds, then give up. There are much better ways to use it.
One-line summary per commit:
git log --onelineGraph view showing all branches and merges:
git log --oneline --graph --allShow commits by a specific author:
git log --author="Jane Doe"Show commits that touched a specific file:
git log -- filename.jsShow commits from the last week:
git log --since="1 week ago"Reading your Git log is a professional skill. When you join a new team and need to get up to speed on a codebase quickly, git log --oneline --graph --all gives you a bird's-eye view of the project's structure and recent history. You can see how branches relate, when features were merged, and who has been active. Use it on day one at every new job.
13. git diff
Before you stage or commit anything, use git diff to see exactly what changed. This is your last chance to catch a stray debugging statement, a hardcoded secret, or a change you did not mean to include.
Show unstaged changes:
git diffShow staged changes (what is about to be committed):
git diff --stagedCompare two branches:
git diff main feature/user-loginCompare two specific commits:
git diff abc1234 def5678Developers who skip git diff and go straight to committing are the same developers who push console.log statements to production, accidentally commit API keys, and include broken experiments in their pull requests. The whole point of the staging area is to give you a deliberate review step. git diff --staged makes that review actually useful.
Make it part of your commit ritual: git diff --staged before every commit, every time. It takes 30 seconds and saves significant embarrassment.
14. git reset and git revert
Sometimes you need to undo something. The right tool depends on whether the commit has already been pushed to a shared branch.
Unstage a file but keep the changes in your working directory:
git reset HEAD filename.jsUndo the last commit but keep the changes:
git reset --soft HEAD~1Undo the last commit and discard the changes permanently:
git reset --hard HEAD~1For commits already pushed to a shared branch, use git revert instead. It creates a new commit that undoes the changes, preserving history rather than rewriting it:
git revert abc1234The rule is straightforward: git reset for local, unpushed history you want to rewrite. git revert for shared history you need to correct without rewriting. Apply the wrong one and you will have a very uncomfortable conversation with your team.
One warning worth repeating: never run git reset --hard without being certain you want to permanently discard those changes. Git does not ask for confirmation. The changes are gone. This is one of the few Git operations that can cause real data loss.
15. git cherry-pick
git cherry-pick lets you take a specific commit from one branch and apply it to another. You use this when you want one particular fix or change without merging the entire branch.
git cherry-pick abc1234A common scenario: you fixed a critical bug on your feature branch and the team needs that fix on the main release branch immediately, but the feature itself is not ready to ship. Cherry-pick the fix commit onto main, and the feature stays on its branch until it is ready.
Cherry-pick multiple commits:
git cherry-pick abc1234 def5678Cherry-pick a range of commits:
git cherry-pick abc1234..def5678Use cherry-pick sparingly and deliberately. It is powerful for the specific scenarios where it fits, but overusing it creates a history full of duplicate commits scattered across branches, which makes code archaeology confusing later. When you do use it, document why in your commit message or pull request description so future developers understand the context.
Bonus: git blame
Despite the name, this command is not about finding someone to blame. It shows you who last modified each line of a file and which commit that change came from.
git blame filename.jsYou use this when you are trying to understand code you did not write. Who wrote this line? When? What was the commit that introduced it? git blame points you to the commit hash, and git show commit-hash shows you the full context including the commit message explaining why the change was made.
A cleaner version that ignores whitespace and shows short hashes:
git blame -w -s filename.jsMost code editors have inline Git blame built in. VS Code has the GitLens extension. JetBrains IDEs show it natively. Whether you use the command line or a GUI, the habit of checking who changed something and why transforms you from someone who guesses at intent to someone who understands context. That is a significant difference when debugging complex systems or joining a new codebase.
Git is a deep tool. These 15 commands cover the vast majority of what you will use in daily professional work. Master them not just in theory but in practice. Run them. Break things in a test repository. The developers who know Git cold are the ones who stay calm when things go sideways on the team. That composure is worth more than most people realize.


