Summit Themes
Blog

23 GitHub commands every developer should know

Git ships with hundreds of subcommands, but most developers run on a core set of maybe fifteen. This list covers those fifteen — plus eight that most people know exist but rarely touch, and which are genuinely worth learning. Every command here is real, ships with Git, and does exactly what it says.

The commands are grouped by phase of work. Skip to whichever section applies to where you are right now.

Setup and configuration

1. git config

Before anything else, tell Git who you are. The --global flag writes to your home directory so you only do this once per machine.

git config --global user.name "Your Name"
git config --global user.email "[email protected]"
git config --global core.editor "code --wait"
git config --global init.defaultBranch main

Run git config --list at any time to see all active settings and where they come from (system, global, or local to the repo).

2. git init

Creates a new repository in the current directory. Run it once, then never again for that project.

git init
git init my-project   # creates the folder too

3. git clone

Copies a remote repository to your machine, including the full history. The second argument sets the local folder name.

git clone https://github.com/user/repo.git
git clone https://github.com/user/repo.git my-local-name

Daily workflow

4. git status

The command you run more than any other. It shows which files are modified, staged, or untracked. Run it constantly — before staging, before committing, before pushing.

git status
git status -s   # short format, one line per file

5. git add

Stages changes for the next commit. Prefer staging specific files over git add . — it forces you to review what you're committing and avoids accidentally including .env files or build artifacts.

git add src/index.js         # one file
git add src/                 # everything in a directory
git add -p                   # interactive: stage hunks, not whole files

The -p (patch) flag is underused and worth memorising. It lets you stage part of a file — useful when one file contains two unrelated changes you want to split across commits.

6. git commit

Saves your staged changes as a snapshot with a message. Write the message in the imperative mood and keep the subject line under 72 characters.

git commit -m "Add contact form validation"
git commit                   # opens your configured editor for a longer message

7. git push and git pull

Send your commits to the remote, or fetch and merge changes from it. The first push from a new branch needs -u to set the upstream tracking reference.

git push -u origin main      # first push from this branch
git push                     # subsequent pushes
git pull                     # fetch + merge in one step

If you prefer to rebase rather than merge when pulling, git pull --rebase keeps the history linear. You can make this the default with git config --global pull.rebase true.

Branching

8. git branch

Lists, creates, renames, and deletes branches.

git branch                   # list local branches
git branch -a                # list local and remote
git branch feature/login     # create a branch (does not switch to it)
git branch -d feature/login  # delete (safe: refuses if unmerged)
git branch -D feature/login  # force delete

9. git switch

git switch was added in Git 2.23 (2019) to replace the branch-switching behaviour of git checkout, which also handles file restoration — two very different things under one command. Prefer git switch for branches going forward.

git switch main
git switch -c feature/login  # create and switch in one step

10. git merge

Integrates changes from another branch into the current one. By default it creates a merge commit, which preserves history. Use --no-ff explicitly if you always want a merge commit even when fast-forward is possible.

git switch main
git merge feature/login

11. git rebase

Replays your commits on top of another branch, producing a linear history. Use it for cleaning up a feature branch before merging — but never rebase commits that have already been pushed to a shared branch.

git switch feature/login
git rebase main

Inspecting history

12. git log

Shows the commit history. The raw output is verbose; the one-line variant and graph flag are far more useful day-to-day.

git log --oneline --graph --all

This gives you an ASCII diagram of every branch and merge. Worth aliasing: git config --global alias.lg "log --oneline --graph --all".

13. git diff

Shows what changed. Without arguments it shows unstaged changes. With --staged it shows what will go into the next commit.

git diff             # unstaged changes
git diff --staged    # staged changes (what you're about to commit)
git diff main..feature/login  # between two branches

14. git show

Shows the diff and metadata for a specific commit.

git show HEAD             # the last commit
git show a3f2c1b          # a specific commit by hash

Undoing things

15. git restore

Also added in Git 2.23, git restore handles the file-restoration side of what git checkout used to do. It discards working-directory changes or unstages a file.

git restore src/index.js          # discard unstaged changes to a file
git restore --staged src/index.js # unstage a file (keeps your edits)

16. git reset

Moves the branch pointer and optionally changes the staging area or working directory. The three modes matter a lot:

git reset --soft HEAD~1   # undo the last commit, keep changes staged
git reset --mixed HEAD~1  # undo the last commit, unstage changes (default)
git reset --hard HEAD~1   # undo the last commit and discard all changes

--hard is destructive. Use it deliberately. Like rebase, avoid resetting commits already pushed to a shared remote.

17. git revert

The safe alternative to reset for shared history. Instead of removing a commit, it creates a new commit that undoes the changes. Safe to push.

git revert a3f2c1b

The underused ones (worth learning)

18. git stash

Saves your current working-directory state to a temporary stack so you can switch context without committing half-finished work. git stash pop restores it.

git stash                        # push current changes onto the stash
git stash push -m "wip: login"   # with a descriptive label
git stash list                   # see all stashes
git stash pop                    # restore the most recent stash and remove it
git stash apply stash@{1}        # restore a specific stash, keep it in the list

19. git cherry-pick

Copies a single commit from anywhere in history and applies it to the current branch. Useful when a bug fix lives on a feature branch and you need it on main now, without merging the whole branch.

git cherry-pick a3f2c1b

20. git reflog

The escape hatch. Git's reflog records every time HEAD moves — including resets, rebases, and branch deletions. If you reset --hard and immediately regret it, reflog is how you get your work back.

git reflog
# output shows HEAD@{0}, HEAD@{1}, HEAD@{2}, ...
git reset --hard HEAD@{2}   # go back to where HEAD was two moves ago

21. git bisect

Uses binary search to find exactly which commit introduced a bug. You tell it a known-good commit and a known-bad commit, then answer good or bad for each commit it checks out — it narrows down to the culprit in log₂(n) steps.

git bisect start
git bisect bad                # current commit is bad
git bisect good v1.0.0        # this tag was known-good
# Git checks out a midpoint commit — test it, then:
git bisect good               # or: git bisect bad
# repeat until Git identifies the first bad commit
git bisect reset              # return to HEAD when done

On a repo with 1,000 commits between good and bad, bisect finds the offender in at most 10 steps.

22. git worktree

Lets you check out a second branch into a separate directory without cloning the repo again. Both directories share the same object store, so no disk duplication.

git worktree add ../hotfix-branch hotfix/urgent-fix
# work in ../hotfix-branch, then:
git worktree remove ../hotfix-branch

This is the right tool when you need to make an urgent fix without stashing your current in-progress work. It is especially handy when your working tree has many uncommitted changes you do not want to disturb.

23. git blame

Shows, line by line, which commit last changed each line in a file and who made that commit. Useful for understanding why a line of code looks the way it does.

git blame src/index.js
git blame -L 40,60 src/index.js   # only lines 40 to 60

Most editors (VS Code, Neovim with a plugin, JetBrains IDEs) surface git blame inline, but knowing the command is useful for terminal work and for piping into scripts.

Aliases worth setting up

A few config aliases that condense the commands you type most often:

git config --global alias.st "status -s"
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.sw "switch"
git config --global alias.co "checkout"

Quick reference

  • Setup: git config, git init, git clone
  • Daily: git status, git add, git commit, git push, git pull
  • Branching: git branch, git switch, git merge, git rebase
  • History: git log, git diff, git show
  • Undoing: git restore, git reset, git revert
  • Advanced: git stash, git cherry-pick, git reflog, git bisect, git worktree, git blame

The best way to actually learn these is not to read a list but to reach for the real command the next time the situation arises. Save git reflog for when you break something. Use git bisect the next time a regression appears and you cannot pinpoint when it arrived. Run git add -p the next time one file has two unrelated changes in it. The commands become intuitive quickly once you have a concrete reason to use them.