The Git commands developers use day to day, grouped by task. Each entry says what the command does and when to reach for it. Angle brackets mark placeholders. Commands that rewrite history or discard work are flagged, because those are the ones that cost time when misused.
Setup and configuration
git config --global user.name "Ada Lovelace"Set the name recorded in your commits. Use --global once per machine, or omit it to set per repository.git config --global user.email [email protected]Set the email recorded in commits. GitHub links commits to accounts by this address.git config --global init.defaultBranch mainName the initial branch main in new repositories.git config --global pull.rebase trueMake git pull rebase local commits on top of the remote instead of creating merge commits.git config --list --show-originShow every setting and which file it comes from.
Creating and cloning
git initCreate an empty repository in the current directory.git clone <url>Copy a remote repository, including its full history, into a new directory.git clone --depth 1 <url>Shallow clone with only the latest commit. Faster for CI; history is unavailable.git clone -b <branch> <url>Clone and check out a specific branch.
Everyday work
git statusShow changed, staged and untracked files, and the current branch.git status -sbShort form with branch and ahead/behind counts.git add <path>Stage a file or directory for the next commit.git add -pStage interactively, hunk by hunk. The best way to make focused commits.git add -AStage everything: new, modified and deleted files.git commit -m "message"Record the staged changes with a message.git commit -am "message"Stage all modified tracked files and commit. Does not add new files.git commit --amendReplace the last commit with the staged changes and an edited message. Do not amend commits that are already pushed and shared.git commit --amend --no-editAdd staged changes to the last commit, keeping its message.git diffShow unstaged changes in the working tree.git diff --stagedShow what is staged for the next commit.git diff main..featureCompare two branches.git diff --statSummary of changed files and line counts.git rm <path>Delete a file and stage the deletion.git rm --cached <path>Stop tracking a file but keep it on disk. Then add it to .gitignore.git mv <old> <new>Rename or move a file and stage the change.
Branches
git branchList local branches; the current one is marked with *.git branch -aList local and remote-tracking branches.git branch <name>Create a branch at the current commit without switching to it.git switch <branch>Switch to an existing branch. The modern replacement for git checkout <branch>.git switch -c <name>Create a branch and switch to it.git switch -Return to the previously checked-out branch.git branch -d <name>Delete a branch that has been merged. Use -D to force-delete an unmerged one.git branch -m <new-name>Rename the current branch.git branch --set-upstream-to=origin/<branch>Link the current branch to a remote branch for pull and push.git branch --mergedList branches already merged into the current one; safe to delete.
Remotes: fetch, pull, push
git remote -vList remotes and their URLs.git remote add origin <url>Add a remote named origin.git fetchDownload new commits and branches from the remote without changing your working tree.git fetch --pruneFetch and delete remote-tracking branches that no longer exist on the remote.git pullFetch, then merge (or rebase, if configured) the remote branch into the current one.git pull --rebaseFetch and replay your local commits on top of the remote branch. Keeps history linear.git pushUpload the current branch to its upstream.git push -u origin <branch>Push a new branch and set it as upstream so later pushes need no arguments.git push --force-with-leaseForce-push, but refuse if someone else pushed in the meantime. Always prefer this over --force.git push origin --delete <branch>Delete a branch on the remote.git push --tagsPush all local tags.
Merging and rebasing
git merge <branch>Merge a branch into the current one. Creates a merge commit unless fast-forward is possible.git merge --no-ff <branch>Always create a merge commit, even when fast-forward is possible, to keep the branch visible in history.git merge --abortAbandon a merge with conflicts and return to the pre-merge state.git rebase mainReplay the current branch’s commits on top of main. Rewrites commit IDs; do not rebase commits others have based work on.git rebase -i HEAD~5Interactive rebase of the last five commits: reorder, squash, edit, drop.git rebase --continueContinue after resolving conflicts during a rebase.git rebase --abortCancel the rebase and restore the branch.git cherry-pick <commit>Apply the changes of one commit onto the current branch as a new commit.
Undoing things
git restore <path>Discard unstaged changes in a file, restoring it from the index. Irreversible.git restore --staged <path>Unstage a file, keeping the changes in the working tree.git restore --source=HEAD~2 <path>Restore a file as it was two commits ago.git reset --soft HEAD~1Undo the last commit but keep its changes staged.git reset HEAD~1Undo the last commit and unstage its changes (mixed reset, the default).git reset --hard HEAD~1Undo the last commit and discard its changes entirely. Irreversible for uncommitted work.git reset --hard origin/mainMake the current branch identical to the remote branch, discarding local commits and changes.git revert <commit>Create a new commit that undoes the changes of a previous one. Safe on shared branches. See git reset vs revert.git clean -fdDelete untracked files and directories. Run git clean -n first to preview.git reflogShow where HEAD has pointed recently. The way back after a bad reset or rebase: git reset --hard HEAD@{2}.
Stashing
git stashSave uncommitted changes (staged and unstaged tracked files) and clean the working tree.git stash -uStash untracked files too.git stash push -m "wip: login form"Stash with a description.git stash listList stashes.git stash popReapply the latest stash and remove it from the list.git stash apply stash@{2}Reapply a specific stash and keep it.git stash drop stash@{0}Delete a stash.
History and inspection
git log --oneline --graph --allCompact history of every branch as a graph.git log -p <path>History of a file with the diff of each commit.git log --author="Ada" --since="2 weeks ago"Filter commits by author and date.git log -S "functionName"Find commits that added or removed a string (pickaxe search).git show <commit>Show a commit’s message and diff.git show <commit>:<path>Print a file as it was at a commit.git blame <path>Show which commit last changed each line.git bisect start; git bisect bad; git bisect good <commit>Binary-search history for the commit that introduced a bug. Git checks out midpoints; mark each good or bad.git shortlog -snCommit counts per author.
Tags
git tagList tags.git tag -a v1.4.0 -m "Release 1.4.0"Create an annotated tag (with author, date and message). Use annotated tags for releases.git tag v1.4.0 <commit>Tag an older commit (lightweight tag).git push origin v1.4.0Push one tag.git tag -d v1.4.0Delete a local tag.
Submodules and worktrees
git submodule add <url> <path>Add another repository at a path, pinned to a commit.git submodule update --init --recursiveFetch and check out all submodules after cloning.git worktree add ../hotfix hotfix-branchCheck out a second branch in a separate directory without a second clone.git worktree listList worktrees.
Three mental models that make the rest make sense
Three places for changes
Every change moves through the working tree (files on disk), the index or staging area (what the next commit will contain), and the repository (commits). git add moves working tree → index; git commit moves index → repository; git restore and git reset move things back. Most confusion about “where did my change go” is resolved by asking which of the three places it is in.
Branches are pointers
A branch is a movable name for a commit. Committing moves the current branch forward. HEAD is a pointer to the current branch. Deleting a branch deletes a label, not commits; the commits remain reachable through git reflog for weeks, which is why almost nothing in Git is truly lost.
Rewriting history is fine until it is shared
commit --amend, rebase and reset create new commits and abandon old ones. On a branch only you have, that is tidy. On a branch others have pulled, it forces everyone to reconcile two histories. The rule: rewrite freely before pushing; after pushing a shared branch, add commits (revert, merges) rather than rewriting. See git reset vs git revert.
A typical feature workflow
git switch main && git pull --rebase
git switch -c feature/search-filters
# … edit, then stage selectively
git add -p
git commit -m "Add category filter to search"
git push -u origin feature/search-filters
# after review, keep the branch current
git fetch && git rebase origin/main
git push --force-with-lease
Getting out of trouble
| Situation | Fix |
|---|---|
| Committed to the wrong branch | git branch correct-branch then git reset --hard HEAD~1 on the wrong one (if not pushed), or git cherry-pick the commit onto the right branch and revert it on the wrong one. |
| Need to undo a pushed commit | git revert <commit> and push. Never reset a shared branch. |
| Lost commits after a reset or rebase | git reflog, find the entry, git reset --hard HEAD@{n} or git branch rescue <sha>. |
| Merge conflict | Edit the files to remove <<<<<<< markers, git add them, then git commit (merge) or git rebase --continue. Or abort with --abort. |
| Accidentally committed a secret | Rotate the secret first; it is compromised regardless. Then remove it from history with git filter-repo and force-push. |
| Detached HEAD | You checked out a commit, not a branch. git switch -c new-branch to keep work, or git switch main to leave. |
Commands and options are as documented in the official Git reference; behaviour described here matches Git 2.23 and later, which introduced switch and restore.