Skip to main content

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 init

Create 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 automatically
git clone

Copy 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.git
git config

Set 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 help

Display 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 help

Working with Changes

4 commands

git status

Show 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.ts
git add

Stage 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 dir
git commit

Record 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 message
git diff

View 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 branches

Branching & Merging

4 commands

git branch

List, 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 branches
git checkout / switch

Switch 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 + switch
git merge

Combine 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 commit
git rebase

Reapply 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 --abort

Inspecting History

5 commands

git log

Display 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 show

View 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 commit
git blame

Find 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 lines
git reflog

Show 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 abc1234
git shortlog

Summarize 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 addresses

Remote Repositories

4 commands

git remote

Manage 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.git
git push

Upload 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 branch
git pull

Fetch 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 default
git fetch

Download 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 fetched

Stashing & Cleaning

2 commands

git stash

Temporarily 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 stack
git clean

Remove 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 tracked

Tagging & Releases

2 commands

git tag

Mark 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 annotations
git describe

Generate 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 reset

Move 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 everything
git revert

Create 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 commits
git restore

Restore 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 ago

Ready to try these commands?

Open your terminal and start practicing. Every example on this page is ready to copy and run.