Git Command Reference
Learn how every Git command works with clear explanations and real-world examples. From basic commits to advanced branching — this guide covers it all.
Getting Started
4 commands
git initCreate a new Git repository
Creates a .git subdirectory that initializes the repository metadata structure — this is the first command you run to start tracking changes in a project. Running git init in an existing directory does not overwrite anything; it is safe to re-run. The generated .git folder stores all commit objects, refs, configuration, and hooks. Use git init --bare to create a server-side repository without a working directory, and git init --template to specify a custom template directory for your hooks and config files. This command only creates the local repository — you still need git remote add to connect it to a remote server.
Example
git init my-project
cd my-project
# .git folder is created automaticallygit cloneCopy an existing repository to your local machine
Downloads the entire repository history and all files from a remote URL, creating a local working directory with the remote automatically configured as 'origin'. The command supports multiple transport protocols: HTTPS (git clone https://github.com/user/repo.git), SSH (git clone git@github.com:user/repo.git), and the Git protocol. Use --depth=1 for a shallow clone that downloads only the latest commit — useful for CI pipelines or large repositories where full history is unnecessary. Use --recurse-submodules to also clone any submodules. Use --branch to clone a specific branch instead of the default HEAD.
Example
git clone https://github.com/user/repo.git
cd repo
git remote -v # shows 'origin' -> https://github.com/user/repo.gitgit configSet user identity and preferences
Stores configuration values at three levels: system (/etc/gitconfig), global (~/.gitconfig or ~/.config/git/config), and local (.git/config in the current repository). Each level overrides the previous. You must set your user.name and user.email before making your first commit — these are attached to every commit and are visible in the repository history. Use git config --global to apply settings across all repositories, git config --local (default) for per-project settings, and git config --system for machine-wide defaults. Common configurations include aliases (git config --global alias.co checkout), default branch name (init.defaultBranch main), and editor (core.editor "code --wait"). View all settings with git config --list.
Example
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
# Now every new repo defaults to 'main' instead of 'master'git helpDisplay help and documentation for Git commands
Opens the manual page for any Git command, providing detailed documentation including all flags, options, and usage examples. Run without arguments to see a list of common Git commands grouped by category. Use git help -a to list every available Git command (including plumbing commands), and git help -g to list guides about specific topics like gitignore, workflows, or revisions. Each man page includes the command synopsis, description, options, configuration, and often examples. For a quick reference in the terminal, use git <command> -h instead — this prints a concise usage summary without opening the pager.
Example
git help commit
# Opens the full manual page for git-commit
# Try 'git help -g' for guides
# Try 'git commit -h' for quick helpWorking with Changes
4 commands
git statusShow the current state of the working tree and staging area
Compares the working directory, staging area (index), and the most recent commit to show exactly what is tracked, modified, staged, or untracked. Files appear in three sections: 'Changes to be committed' (staged), 'Changes not staged for commit' (modified but not staged), and 'Untracked files' (new files Git does not know about). Use git status -s (short format) for a concise two-column output ideal for scripting. Use git status -b to always show branch information. Run this command frequently — it is the safest way to understand your repository state before committing, merging, or switching branches. Unlike git diff, it does not show the actual content changes, only the file names and their status.
Example
git status
# On branch main
# Changes not staged for commit:
# modified: src/index.ts
# Untracked files:
# new-feature.tsgit addStage changes — prepare them for the next commit
Moves changes from the working directory into the staging area (also called the index). Only changes that have been staged will be included in the next git commit. Use git add <file> to stage a single file, git add . to stage all changes in the current directory (including new files), or git add -p to stage interactively — this shows each hunk of changes and lets you decide whether to stage it, a powerful way to create clean, focused commits. Use git add -A to stage all changes across the entire repository (not just the current directory). Staging is what makes Git different from older version control systems — it gives you fine-grained control over what goes into each commit without needing to commit everything at once.
Example
git add src/index.ts # stage a single file
git add -p # stage interactively, hunk by hunk
git add . # stage all changes in current dirgit commitRecord staged changes as a permanent snapshot in history
Takes all currently staged changes and creates a permanent snapshot with a unique SHA-1 hash, author metadata, timestamp, and commit message. A well-written commit message follows the conventional format: a short summary line (50 chars or fewer), a blank line, then a longer body explaining what and why. Use git commit -m "message" for a quick inline message, or just git commit to open your configured editor for a detailed message. Use git commit --amend to modify the most recent commit (message, content, or both) — useful for fixing typos or forgetting to stage a file. Use git commit -a to automatically stage all tracked files before committing, bypassing the separate git add step. Every commit is immutable — once created, its history should not be rewritten on shared branches.
Example
git add .
git commit -m "Fix login validation error"
# Creates commit abc1234 with author, date, and messagegit diffView the exact changes between commits, branches, or the working tree
Compares different states in the repository and shows the line-by-line differences. Lines starting with + are additions (shown in green), lines starting with - are deletions (shown in red). By default, git diff compares the working directory against the staging area. Use git diff --staged (or --cached) to see what is staged versus the last commit. Use git diff <branch1> <branch2> to compare two branches, or git diff <commit1> <commit2> to compare specific commits. Add --stat for a summary of changed files and line counts, --name-only to show only file names, or --color-words for a word-level (instead of line-level) diff. For complex merges, git diff --ours, --theirs, and --base help identify conflicting changes during merge conflicts.
Example
git diff # unstaged changes vs staging
git diff --staged # staged vs last commit
git diff main feature-login # compare two branchesBranching & Merging
4 commands
git branchList, create, rename, or delete branches
A branch is a lightweight, movable pointer to a specific commit. Use git branch without arguments to list all local branches — the current branch is highlighted with an asterisk. Create a new branch with git branch <name>, which creates a pointer at the current commit without switching to it. Use git branch -d <name> to delete a merged branch safely, or git branch -D to force-delete an unmerged branch. Rename a branch with git branch -m <old> <new>. List remote branches with git branch -r, and all branches (local + remote) with git branch -a. The git branch -vv command shows which remote branch each local branch is tracking. Branch names should be descriptive and use hyphens as separators — like feature-login or hotfix-security-patch.
Example
git branch feature-login # create branch at current commit
git branch -d feature-login # delete after merging
git branch -a # list all local and remote branchesgit checkout / switchSwitch between branches or restore working tree files
Changes your current HEAD to point to a different branch or commit, updating the working directory to match. Git checkout is the traditional Swiss Army knife command — it can switch branches (git checkout main), create and switch branches (git checkout -b feature-login), and restore files from previous states (git checkout HEAD -- file.ts). In modern Git (2.23+), the command has been split: git switch handles branch switching with a cleaner interface (git switch other-branch, git switch -c new-branch), and git restore handles file restoration. Use git checkout -b <branch> <start-point> to create a branch from a specific commit or tag. Git prevents switching if you have uncommitted changes that would conflict with the target branch — use git stash to temporarily save them.
Example
git checkout main # switch to existing branch
git checkout -b fix-bug # create and switch to new branch
git switch -c hotfix # modern way (Git 2.23+): create + switchgit mergeCombine changes from one branch into your current branch
Takes the commits from a source branch and integrates them into your current branch. When the target branch has not diverged, Git performs a fast-forward merge — it simply moves the branch pointer forward. When branches have diverged, Git creates a merge commit that has two parents, preserving the full history of both branches. If conflicts occur (changes overlap in the same lines), Git pauses with the conflicting files marked. Use git merge --abort to cancel a conflicted merge and return to the pre-merge state. Use git merge --no-ff to force a merge commit even when fast-forward is possible — useful for preserving feature branch context. Use git merge --squash to combine all source branch commits into a single commit on the target branch. Always merge on the receiving branch (e.g., checkout main, then merge feature-login).
Example
git checkout main
git merge feature-login
# If conflicts: resolve them, then:
git add .
git commitgit rebaseReapply commits from your current branch onto another base
Rewrites commit history by taking commits from your branch and replaying them one by one on top of another branch. The result is a linear history — it looks like all work was done sequentially on the same branch. Use git rebase main while on a feature branch to incorporate the latest main changes without creating a merge commit. Use git rebase -i (interactive rebase) to squash, reorder, edit, or drop commits — a powerful tool for cleaning up history before sharing it. Use git rebase --onto to move a range of commits to a completely different parent. The golden rule of rebasing: never rebase commits that have been pushed to a shared branch or that others have based work on. Rebase rewrites commit hashes, so force-pushing a rebased branch disrupts collaborators.
Example
git checkout feature-login
git rebase main
# Replays feature commits on top of main
# For interactive: git rebase -i HEAD~3
# To abort a bad rebase: git rebase --abortInspecting History
5 commands
git logDisplay the commit history with detailed information
Shows commits in reverse chronological order (newest first) with their hash, author, date, and commit message. Git log is incredibly customizable: use git log --oneline for a compact single-line-per-commit format, git log --graph to visualize branch topology with ASCII art, git log -p to show the actual diff of each commit, and git log --stat for summary statistics. Filter history with git log --author="name" (by author), git log --since="2 weeks ago" (by date), git log --grep="bug" (by commit message), or git log -S"functionName" (by code changes that introduced or removed a string). Combine flags freely — git log --oneline --graph --all is a common daily-driver command to see the full repository state.
Example
git log --oneline -5 # last 5 commits, one line each
git log --oneline --graph --all # full branch topology
git log --author="Jane" --since="2026-01-01"git showView the full details of any Git object
Displays the complete content of a Git object — most commonly a commit. For a commit, git show shows the diff (similar to git log -p) plus the commit metadata. For tags, it shows the tag message and the referenced commit. For trees and blobs, it shows directory contents or file contents respectively. By default, git show shows HEAD. Specify any reference: git show main, git show v1.0.0, git show abc1234 (partial hash), or git show HEAD~3 (3 commits before HEAD). Use git show --name-only to show only file names, or git show --stat for a compact summary. This command is invaluable for quickly inspecting a specific commit during code review or debugging without digging through the full log.
Example
git show HEAD # show details of latest commit
git show HEAD~2 # show the commit two before HEAD
git show --stat abc1234 # summary of a specific commitgit blameFind out who last modified every line of a file
Annotates each line of a file with the commit hash, author name, and timestamp of the most recent modification. This is the go-to command when you need to understand why a particular line of code exists — it tells you who wrote it, when, and in which commit. Use git blame -L 10,20 file.ts to limit output to a specific line range, or git blame -w to ignore whitespace changes. Use git blame -C to detect lines that were copied from other files (even within different files in the same commit). Combined with git show <hash>, you can trace any line of code back to its original context, commit message, and related changes. This is especially useful during debugging, code review, and refactoring legacy code.
Example
git blame src/index.ts # annotate every line
git blame -L 15,30 src/app.ts # lines 15-30 only
git blame -w -C src/index.ts # ignore whitespace, detect moved linesgit reflogShow the reference log — your safety net for lost commits
Records every movement of HEAD — every checkout, commit, reset, rebase, and merge. When you accidentally lose commits (from a hard reset, rebase gone wrong, or deleted branch), the reflog is your recovery tool. Each entry shows the operation, the previous position, and how HEAD moved. Use git reflog to find the commit hash of a lost state, then git checkout <hash> or git branch <name> <hash> to recover it. The reflog is local — it is not shared with remotes and is not backed up. Entries expire after 90 days (for reachable commits) or 30 days (for unreachable). Use git reflog show <branch-name> to see the reflog for a specific branch. The reflog is why Git is hard to permanently lose data from.
Example
git reflog
# abc1234 HEAD@{0}: commit: Fix login bug
# def5678 HEAD@{1}: reset: moving to HEAD~1
# Recover: git branch recovered-branch abc1234git shortlogSummarize commit history grouped by author
Groups commits by author name and displays the commit count and message for each author. This is the standard command for generating changelogs and release notes. Use git shortlog -sn for a summary with commit counts only, sorted by number of commits (descending). Use git shortlog -e to include email addresses, and git shortlog --since="2026-01-01" to filter by date range. For release notes, use git shortlog <previous-tag>..HEAD to see all commits since the last release. Use git shortlog --no-merges to exclude merge commits from the summary. This command is commonly used in release automation scripts to generate human-readable changelogs.
Example
git shortlog -sn # count of commits per author
git shortlog -sn v1.0.0..HEAD # changes since v1.0.0
git shortlog -e # include email addressesRemote Repositories
4 commands
git remoteManage connections to remote repositories
Remotes are shorthand names for URLs to hosted repositories. The default remote after cloning is 'origin', which points to the URL you cloned from. Use git remote -v to list all remotes with their fetch and push URLs (they can be different). Use git remote add <name> <url> to connect a new remote, git remote remove <name> to delete one, and git remote rename <old> <new> to rename. Use git remote set-url <name> <new-url> to change a remote's URL without removing and re-adding it. Use git remote show <name> to see detailed information about a remote's branches, tracking relationships, and whether it is reachable. Multiple remotes are common when working with forks — origin points to your fork, upstream points to the original repository.
Example
git remote -v
# origin https://github.com/user/repo.git (fetch)
# origin https://github.com/user/repo.git (push)
git remote add upstream https://github.com/original/repo.gitgit pushUpload local commits to a remote repository
Sends committed changes from your local repository to a remote, making them available to collaborators. The basic syntax is git push <remote> <branch>, which pushes the specified branch to the matching branch on the remote. If the remote has commits you do not have locally, Git rejects the push — you must pull or fetch first. Use git push -u origin main to set the upstream tracking relationship, which lets you use just git push thereafter. Use git push --force (or -f) to overwrite the remote history — dangerous and should only be used on private or feature branches after rebasing. Use git push --dry-run to see what would be pushed without actually doing it. Use git push origin --delete <branch> to delete a remote branch. Never force-push to shared branches like main.
Example
git push origin main # push main branch
git push -u origin feature-login # push and set upstream
git push origin --delete old-branch # delete remote branchgit pullFetch remote changes and merge them into your current branch
Combines two operations: git fetch (downloads remote data) followed by git merge (integrates it into your current branch). This is the primary command for keeping your local branch up to date with the remote. Use git pull --rebase instead of a regular pull to rebase your local commits on top of the fetched changes — this creates a linear history instead of a merge commit. Use git pull --ff-only to fail if a fast-forward merge is not possible, which is a safe way to avoid accidental merge commits. Configure the default pull behavior with git config --global pull.rebase true (to always rebase). Before pulling, ensure your working directory is clean — use git stash or commit any in-progress work first.
Example
git pull origin main # fetch + merge
git pull --rebase origin main # fetch + rebase (linear history)
git config --global pull.rebase true # make rebase the defaultgit fetchDownload remote data without changing your working directory
Downloads commits, branches, and tags from a remote repository but does not modify your working directory or current branch. This makes it safer than git pull — you can review changes before integrating them. After fetching, you can inspect the remote branches with git log origin/main, diff with git diff main origin/main, or merge with git merge origin/main. Use git fetch --all to fetch from all configured remotes at once. Use git fetch --prune to remove local references to remote branches that no longer exist on the remote. Use git fetch origin to fetch all branches from origin, or git fetch origin main to fetch only the main branch. Fetching is the safest first step before deciding how to integrate remote changes.
Example
git fetch origin # fetch all branches from origin
git fetch --prune # fetch and remove stale remote refs
# Then: git log origin/main to see what was fetchedStashing & Cleaning
2 commands
git stashTemporarily shelve changes so you can work on something else
Saves your modified tracked files onto a stack of temporary snapshots, reverting your working directory to the last committed state. This is useful when you need to switch branches urgently but are in the middle of unfinished work. Use git stash pop to reapply the most recent stash and remove it from the stack, or git stash apply to reapply it without removing it (useful for applying the same stash to multiple branches). Use git stash list to view all stashes, git stash show -p to see the diff of a stash, and git stash drop to remove a specific stash. Use git stash -u (or --include-untracked) to also stash untracked files, and git stash -a (or --all) to stash everything including ignored files. Use git stash branch <name> to create a new branch from a stash — helpful when you realize you are on the wrong branch.
Example
git stash # save current changes
git checkout other-branch # work on something else
git checkout main
git stash pop # restore changes and remove from stackgit cleanRemove untracked files from the working directory
Deletes files that are not tracked by Git — typically build artifacts, logs, or generated files that are not in your .gitignore. This is a destructive command, so always preview first with git clean -n (or --dry-run), which shows what would be deleted without actually removing anything. Use git clean -f to force removal of files, git clean -fd to also remove untracked directories, and git clean -fx to remove ignored files (those matching .gitignore) as well. For maximum cleaning, git clean -fdx removes untracked files, directories, and ignored files — useful for wiping a build directory before a fresh build. Combine with git reset --hard for a complete reset to the last committed state.
Example
git clean -n # preview what will be removed
git clean -fd # remove untracked files and directories
git clean -fdx # remove everything not trackedTagging & Releases
2 commands
git tagMark specific commits as named releases
Tags are named references to specific commits, typically used to mark release versions (v1.0.0, v2.3.1-beta). There are two types: lightweight tags (just a name pointing to a commit) and annotated tags (stored as full objects with a message, author, and date). Use git tag -a v1.0.0 -m "Release 1.0.0" to create an annotated tag — recommended for releases because they include metadata. List tags with git tag (all), git tag -l "v1.*" (by pattern), or git tag -n (with annotation messages). Push tags to a remote with git push origin v1.0.0 or git push origin --tags (all tags). Delete a local tag with git tag -d v1.0.0 and a remote tag with git push origin :refs/tags/v1.0.0. Tags are not automatically included in git push — you must push them explicitly.
Example
git tag -a v1.0.0 -m "Initial public release"
git push origin v1.0.0
git tag -n # list tags with annotationsgit describeGenerate a human-readable name for the current commit
Produces a string that combines the nearest annotated tag, the number of commits since that tag, and the abbreviated commit hash — for example, v1.0.0-5-gabc1234. This is the standard command for generating version strings in build systems and release artifacts. The format breaks down as: the closest tag name (v1.0.0), the number of additional commits since that tag (5), and the abbreviated commit hash prefixed with 'g' (gabc1234). Use git describe --tags to also consider lightweight tags, git describe --always to always show a result even without any tags, and git describe --dirty to append '-dirty' if the working directory has uncommitted changes. Many CI/CD pipelines use this command to embed version information into compiled binaries.
Example
git describe --tags
# v1.0.0-5-gabc1234 (5 commits after v1.0.0, hash abc1234)
git describe --dirty
# v1.0.0-dirty (uncommitted changes exist)Undoing Changes
3 commands
git resetMove the current branch pointer backward, discarding or unstaging commits
Moves the current branch pointer to a previous commit, effectively undoing commits. The three modes control what happens to your working directory and staging area. git reset --soft HEAD~1 moves the branch pointer back but leaves all changes staged — useful for amending or squashing commits. git reset --mixed HEAD~1 (default) moves the pointer and unstages changes — files remain modified in your working directory. git reset --hard HEAD~1 moves the pointer, unstages, and discards all changes — files revert exactly to the target commit. Use git reset <file> to unstage a specific file without affecting other files. Never use --hard on commits you have not backed up, and never reset commits that have been pushed to a shared branch — use git revert instead.
Example
git reset --soft HEAD~1 # undo commit, keep changes staged
git reset --mixed HEAD~1 # undo commit, unstage (default)
git reset --hard HEAD~1 # undo commit, discard everythinggit revertCreate a new commit that safely undoes a previous commit
Creates a brand new commit that inverses all the changes from a target commit, effectively undoing it without rewriting history. This is the safe undo command for commits that have already been pushed to shared branches. Unlike git reset, revert does not move branch pointers — it adds a new commit on top, so the existing history is preserved. Use git revert HEAD to undo the most recent commit, git revert HEAD~3 to revert the commit three steps back, or git revert <commit-hash> to target a specific commit. If the revert causes conflicts, resolve them normally and git revert --continue. Use git revert --no-commit to stage the inverse changes without automatically committing — useful for reverting multiple commits in a single commit. Revert is the default strategy for undoing changes in collaborative workflows.
Example
git revert HEAD # undo the latest commit safely
git revert abc1234 # undo a specific commit
git revert HEAD~3..HEAD # revert a range of commitsgit restoreRestore working tree files or staged changes to a previous state
A modern command (introduced in Git 2.23) for restoring files to a known state, replacing the confusing dual use of git checkout. Use git restore <file> to revert a file in your working directory back to the last committed state — discarding uncommitted changes. Use git restore --staged <file> to unstage a file (the inverse of git add) without changing the working directory. Use git restore --source=HEAD~1 <file> to restore a file to how it looked two commits ago. Use git restore . to restore all files in the current directory. Unlike git reset, restore operates at the file level and does not move branch pointers. Unlike git checkout, its behavior is predictable and focused — it always restores files, never switches branches.
Example
git restore src/index.ts # discard unstaged changes in one file
git restore --staged src/index.ts # unstage a file (undo git add)
git restore --source=HEAD~1 . # restore all files to how they were 2 commits agoReady to try these commands?
Open your terminal and start practicing. Every example on this page is ready to copy and run.