Skip to content

Reference

Git commands, with examples

The 55 Git commands that cover almost all everyday work, grouped by what you are trying to do. Each one has a plain-English explanation, commands you can copy, the flags worth knowing, and a warning wherever a command can lose work or rewrite history other people depend on.

Git itself does not run on this page — these are commands to type in your own terminal. New to version control? The Git and GitHub concept guide explains the ideas underneath them first, and the Linux commands reference covers the rest of the terminal.

Setup and configuration

Tell Git who you are once per machine, then either start a new repository or copy an existing one.

git config --global user.name "Your Name"

Records the name and email address that Git attaches to every commit you make.

Set both values once per computer before your first commit, otherwise Git either guesses from your system account or stops and asks you to set them. Use the same email as your hosting account if you want commits linked to your profile there. Leaving out --global stores the value for the current repository only, which is a simple way to keep work and personal identities separate.

Shell
git config --global user.name "Ada Lovelace"

Set your display name for every repository on this machine.

Shell
git config --global user.email "ada@example.com"

Set the email address recorded on your commits.

Shell
git config user.email "ada@work.example.com"

Use a different email in the current repository only.

Shell
git config user.name

Print the name Git will actually use in this repository.

--global
Write to your personal config file, which applies to all your repositories.
--local
Write to this repository's .git/config file; this is already the default when setting a value.

git config --global init.defaultBranch main

Chooses the name of the first branch in repositories you create from now on.

Without this setting the starting branch name depends on your Git version, with older releases using master, so setting it explicitly keeps new repositories consistent across machines. It has no effect on repositories that already exist. The setting has been available since Git 2.28.

Shell
git config --global init.defaultBranch main

Start every new repository on a branch called main.

Shell
git config --global --get init.defaultBranch

Check the value currently in effect.

Shell
git config --list --show-origin

List every setting Git can see and the file each one comes from.

git init

Turns the current folder into a new, empty Git repository.

It creates a hidden .git folder that will hold all history and settings, while your existing files stay where they are and remain untracked until you add and commit them. Running it again inside an existing repository is harmless and does not erase anything.

Shell
git init

Start tracking the folder you are in.

Shell
git init my-project

Create the my-project folder if needed and set up a repository inside it.

Shell
git init -b main

Name the first branch main for this repository, whatever your global setting says.

-b <name>
Pick the name of the initial branch for this repository.
--bare
Create a repository with no working files, typically used as a central copy that others push to.

git clone <url>

Downloads a complete copy of an existing repository, history included, into a new folder.

Cloning also sets up a remote named origin that points back at the source and checks out its default branch, so you can start working straight away. A shallow clone made with --depth is faster for large projects, but log, blame, and similar commands can only see the commits you actually downloaded.

Shell
git clone https://github.com/example/project.git

Copy the repository into a folder named project.

Shell
git clone https://github.com/example/project.git my-copy

Choose the folder name yourself.

Shell
git clone --depth 1 https://github.com/example/project.git

Download only the latest snapshot instead of the full history.

Shell
git clone -b develop https://github.com/example/project.git

Check out the develop branch rather than the default one.

--depth <n>
Fetch only the most recent n commits.
-b <branch>
Check out this branch once the clone finishes.
--recurse-submodules
Also clone and check out any submodules the project depends on.

Staging and committing

Git records work in two steps: you stage the changes you want, then commit them as a single snapshot. These commands inspect, stage, and record those changes.

git status

Reports which files are modified, staged, or untracked, and which branch you are on.

It changes nothing, so it is safe to run before and after any other command to confirm what happened. In the middle of a merge, rebase, or cherry-pick it also explains the current state and how to continue or back out.

Shell
git status

Full report with hints about what to do next.

Shell
git status -s

One line per file with short status codes.

Shell
git status -sb

Short format plus the branch name and how far ahead or behind its upstream it is.

-s
Short output where the left column is the staged state and the right column is the working copy.
-b
Include branch and tracking details, mainly useful alongside -s.
--ignored
Also list files that .gitignore is hiding.

git add <path>

Stages changes so that they will be part of the next commit.

Staging copies a file's content as it is right now, so if you edit the file again afterwards, those newer edits stay unstaged until you add it again. Adding a folder stages everything inside it, including new and deleted files.

Shell
git add index.html

Stage a single file.

Shell
git add src/

Stage every change under the src folder.

Shell
git add .

Stage all changes in the current folder and below.

Shell
git add -A

Stage every change in the whole repository, no matter which folder you are in.

-A
Stage new, modified, and deleted files across the entire working tree.
-u
Stage changes and deletions to files Git already tracks, but skip new files.
-n
Dry run that lists what would be staged without staging it.

git add -p

Steps through your changes chunk by chunk so you can stage only some of them.

Reach for it when one file holds two unrelated edits that belong in separate commits. At each prompt, y stages the chunk, n skips it, s splits it into smaller pieces, e lets you edit the lines by hand, q stops, and ? lists every choice. Brand-new files are not offered until Git knows about them, which you can arrange with git add -N first.

Shell
git add -p

Review every changed tracked file one chunk at a time.

Shell
git add -p src/app.ts

Limit the review to one file.

Shell
git add -N notes.md

Mark a new file as intended for adding so git add -p can stage parts of it.

git diff

Shows the line-by-line edits in your working files that are not staged yet.

Plain git diff compares your files with the staging area, so a change drops out of this output as soon as you stage it, which can look as though it vanished. Use git diff --staged to see staged changes, or git diff HEAD to see staged and unstaged together.

Shell
git diff

Unstaged changes across all tracked files.

Shell
git diff README.md

Unstaged changes in one file.

Shell
git diff HEAD

Everything that differs from the last commit.

Shell
git diff main..feature

Differences between the tips of two branches.

--stat
Summarise as a list of files with counts of changed lines.
--name-only
List just the names of the changed files.
-w
Ignore differences that are only whitespace.
--word-diff
Mark changed words inside a line instead of whole lines.

git diff --staged

Shows the changes you have staged, which is exactly what your next commit will contain.

Run it right before committing to confirm nothing unexpected is included. The option --cached means the same thing and appears in older guides.

Shell
git diff --staged

Review everything staged for the next commit.

Shell
git diff --staged --stat

Only the staged file names and line counts.

Shell
git diff --cached src/app.ts

Staged changes for one file, using the equivalent --cached spelling.

git commit -m "message"

Saves the staged changes as a new commit, labelled with a message describing them.

Only staged changes go in; anything you edited but did not add is left out. If you leave off -m, Git opens your editor so you can write a longer message, with a short summary on the first line and a blank line before any further explanation.

Shell
git commit -m "Fix broken link in footer"

Commit the staged changes with a one-line message.

Shell
git commit

Open your editor to write a longer message.

Shell
git commit -am "Update pricing page copy"

Stage edits to already tracked files and commit them in one step.

-m <message>
Use this text as the message; repeating -m adds extra paragraphs.
-a
Stage changes to tracked files before committing; new files are not included.
-v
Show the diff in the editor while you write the message.

git commit --amend

Replaces your latest commit with a new one that includes any staged changes and, if you like, a new message.

Useful for fixing a typo in the last message or adding a file you forgot to stage. Although it feels like editing, Git actually builds a brand-new commit with a different ID and drops the old one from your branch.

Careful: Amending rewrites the last commit. If it has already been pushed, anyone who pulled it now has a commit your branch no longer contains, and publishing the fix requires a force push. Only amend commits that exist solely on your machine.

Shell
git commit --amend -m "Fix broken link in footer"

Rewrite the message of the last commit.

Shell
git commit --amend --no-edit

Fold newly staged changes into the last commit and keep its message.

--no-edit
Keep the existing commit message unchanged.
--reset-author
Record yourself as the author and refresh the timestamp.

git restore <file>

Discards uncommitted edits to a file and puts back its last staged or committed version.

Git 2.23 introduced restore so that recovering files and switching branches would no longer share one command; it replaces git checkout -- <file>. With --source you can bring back a file's content from any commit without moving your branch.

Careful: Edits that were never staged or committed exist only in your file, so once restore overwrites them Git has no copy to bring back.

Shell
git restore src/app.ts

Throw away unstaged edits to one file.

Shell
git restore .

Throw away all unstaged edits in the current folder and below.

Shell
git restore --source=HEAD~2 src/app.ts

Bring the file back to how it looked two commits ago.

Shell
git restore -p src/app.ts

Choose which chunks to discard.

--source=<commit>
Take the content from this commit instead of the staging area.
--staged
Unstage the file rather than touching your working copy (see the Undo section).
-p
Pick the chunks to restore one at a time.

git rm <file>

Deletes a file from your working folder and stages the deletion.

It does the same as deleting the file yourself and then staging that change, and it refuses to remove a file that has uncommitted modifications. With --cached, Git stops tracking the file but leaves it on disk, which suits an accidentally committed .env file; add it to .gitignore too, and remember it still exists in earlier commits.

Shell
git rm old-script.js

Delete the file and stage the removal.

Shell
git rm --cached .env

Stop tracking the file but keep it on disk.

Shell
git rm -r build/

Remove a whole folder.

--cached
Remove the file from the staging area only.
-r
Allow removing folders and everything inside them.
-n
List what would be removed without removing it.

git mv <old> <new>

Renames or moves a tracked file and stages that change in one step.

Git does not store renames directly; it works them out later by comparing file contents, so moving a file some other way and staging both sides ends up the same. It is also the straightforward way to change only the capitalisation of a filename on case-insensitive file systems such as the Windows and macOS defaults.

Shell
git mv utils.js helpers.js

Rename a file.

Shell
git mv helpers.js src/lib/

Move a file into another folder.

Shell
git mv readme.md README.md

Change only the letter case of a filename.

-n
Show what would be moved without moving anything.

Branching and merging

A branch is a lightweight, movable name for a line of commits. These commands create branches, move between them, and bring their work together.

git branch

Lists your local branches and marks the one you currently have checked out.

Add -a to include remote-tracking branches, which reflect the remote as of your last fetch rather than its live state. The same command renames branches with -m.

Shell
git branch

Local branches, with the current one starred.

Shell
git branch -a

Local and remote-tracking branches together.

Shell
git branch -vv

Show each branch's latest commit, its upstream, and whether it is ahead or behind.

Shell
git branch --merged main

List branches whose commits are all already in main.

-a
Include remote-tracking branches.
-vv
Add the last commit, upstream branch, and ahead/behind counts.
-m <old> <new>
Rename a branch.
--merged / --no-merged
Show only branches that are, or are not, merged into the given commit.

git branch <name>

Creates a new branch at the current commit without switching to it.

You remain on your current branch afterwards, which is easy to forget if you commit straight away. To create a branch and move onto it together, use git switch -c instead. Naming a commit, tag, or branch after the new name starts the branch from there.

Shell
git branch feature/login

Create a branch at the current commit.

Shell
git branch hotfix v1.2.0

Start a branch from a tag.

Shell
git branch experiment a1b2c3d

Start a branch from a specific commit.

git branch -d <name>

Deletes a local branch, but only when its work is already merged.

Git checks that the branch is merged into its upstream, or into your current branch if it has no upstream, and refuses otherwise, which protects commits that exist nowhere else. It never touches the copy of the branch on a remote, and you cannot delete the branch you are currently on.

Shell
git branch -d feature/login

Remove a finished branch.

Shell
git branch -d feature/login feature/signup

Remove several merged branches at once.

git branch -D <name>

Deletes a local branch even when its commits are not merged anywhere.

It is shorthand for --delete --force and skips the merge check that -d performs. Use it for abandoned experiments you are certain you no longer need.

Careful: Commits that lived only on that branch stop being reachable from any branch. If you had them checked out recently, git reflog can usually help you find and restore them, but they vanish from normal history and are eventually cleaned up for good.

Shell
git branch -D spike/old-idea

Delete an unmerged branch.

git switch <branch>

Moves you onto another existing branch and updates your files to match it.

Uncommitted changes come along when they do not clash with the target branch; if they would be overwritten, Git refuses, so commit or stash first. When a branch exists only on the remote, switching to its name creates a local branch that tracks it, as long as exactly one remote has a branch by that name.

Shell
git switch main

Move to the main branch.

Shell
git switch -

Jump back to the branch you were on before.

Shell
git switch --detach v1.0.0

Look at a tagged release without being on any branch.

-c <new-branch>
Create the branch first, then switch to it.
--detach
Check out a commit or tag directly instead of a branch.

git switch -c <new-branch>

Creates a new branch and switches to it in a single step.

The branch starts at your current commit unless you give a different starting point. Uncommitted changes move across with you, which helps when you realise halfway through an edit that the work deserves its own branch. The older equivalent is git checkout -b.

Shell
git switch -c feature/search

Create a branch and move onto it.

Shell
git switch -c hotfix origin/main

Start the new branch from the remote's copy of main.

git checkout <branch>

Switches branches or restores files, handling both jobs that newer Git splits between switch and restore.

Because one command covered unrelated tasks, Git 2.23 added git switch for branches and git restore for files; checkout still works and is common in older tutorials and scripts. Given a commit ID it puts you in detached HEAD mode, where new commits belong to no branch until you create one.

Careful: When you pass a file path, as in git checkout -- file, it overwrites your uncommitted edits to that file without asking, and those edits cannot be recovered.

Shell
git checkout main

Switch branches, like git switch main.

Shell
git checkout -b feature/search

Create and switch to a branch, like git switch -c.

Shell
git checkout -- src/app.ts

Discard edits to a file, like git restore.

Shell
git checkout a1b2c3d

Inspect an old commit in detached HEAD mode.

git merge <branch>

Brings the commits from another branch into the branch you are on.

If your branch has not moved since the other one split off, Git just slides your branch forward (a fast-forward); otherwise it creates a merge commit with two parents. When both sides changed the same lines it stops with conflicts, which you fix, stage, and finish with git commit or git merge --continue.

Shell
git merge feature/search

Merge feature/search into the current branch.

Shell
git merge --no-ff feature/search

Always create a merge commit, even when a fast-forward is possible.

Shell
git merge --abort

Abandon a conflicted merge and return to where you started.

--no-ff
Record a merge commit even if a fast-forward would work.
--ff-only
Refuse to merge unless it can be a fast-forward.
--squash
Stage the combined changes without creating a merge commit, leaving you to commit them as one.
--abort
Cancel a merge that stopped because of conflicts.

git rebase <base>

Replays your branch's commits on top of another commit so that history forms a straight line.

Reach for it to bring a feature branch up to date with main without adding a merge commit. Every replayed commit receives a new ID. The interactive form, git rebase -i, lets you reorder, reword, squash, or drop commits along the way.

Careful: Rebasing replaces commits with rewritten copies. Do not rebase commits other people have already pulled, such as a shared main or a branch teammates are building on, because their history will no longer match yours and they will have to untangle duplicate commits. Keep it to commits only you have, or agree on it with your team before force-pushing.

Shell
git rebase main

Move the current branch's commits onto the tip of main.

Shell
git rebase -i HEAD~3

Reword, squash, reorder, or drop the last three commits.

Shell
git rebase --continue

Carry on after fixing and staging a conflict.

Shell
git rebase --abort

Stop and put the branch back exactly as it was.

-i
Open a to-do list in your editor to pick, reword, squash, fixup, or drop each commit.
--onto <newbase>
Move a range of commits onto a different base than the one they grew from.
--autosquash
Place commits made with git commit --fixup next to the commits they correct.
--skip
Leave out the commit that is causing a conflict and continue.

git cherry-pick <commit>

Copies the changes from one or more existing commits onto the current branch as new commits.

Handy for carrying a single bug fix over to a release branch without merging everything else. The copy gets its own ID and has no link to the original, so merging both branches later can still produce conflicts if the same lines changed again afterwards.

Shell
git cherry-pick a1b2c3d

Apply one commit to the current branch.

Shell
git cherry-pick -x a1b2c3d

Note the original commit ID in the new commit's message.

Shell
git cherry-pick a1b2c3d~1..e4f5a6b

Apply every commit from a1b2c3d through e4f5a6b, including both ends.

Shell
git cherry-pick --abort

Cancel a cherry-pick that stopped on a conflict.

-x
Add a line to the message naming the commit it was copied from.
-n
Apply the changes to your files and staging area without committing.
--continue
Resume after resolving a conflict.

Working with remotes

A remote is a named connection to another copy of the repository, usually on a hosting service. These commands move commits between your machine and that copy.

git remote -v

Lists the remotes this repository knows about, with the URLs used to fetch from and push to each.

A freshly cloned repository has a single remote named origin. Checking this list is the quickest way to see whether you are connecting over HTTPS or SSH, or to catch a mistyped URL when a push or fetch fails.

Shell
git remote -v

Show every remote and its URLs.

Shell
git remote show origin

Detailed view of one remote, including which branches track it.

Shell
git remote set-url origin git@github.com:example/project.git

Point origin at a new address, for example to switch to SSH.

git remote add <name> <url>

Registers a new remote under a short name so you can fetch from it or push to it.

You need it when a project began with git init and now has to be published, or when you forked a project and want to follow the original. Adding a remote only saves the name and address; nothing is downloaded until you fetch.

Shell
git remote add origin https://github.com/example/project.git

Connect a new local repository to a hosting service.

Shell
git remote add upstream https://github.com/original/project.git

Keep track of the project you forked from.

Shell
git remote remove upstream

Forget a remote along with its remote-tracking branches.

-f
Fetch from the new remote immediately after adding it.

git fetch

Downloads new commits, branches, and tags from a remote without changing your own branches or files.

Afterwards, remote-tracking branches such as origin/main show what the remote looks like, and you decide separately whether to merge or rebase. Since it leaves your branches and working files alone, you can run it whenever you like.

Shell
git fetch

Update from the default remote, usually origin.

Shell
git fetch --all

Update from every configured remote.

Shell
git fetch --prune

Also drop remote-tracking branches that were deleted on the remote.

Shell
git log --oneline main..origin/main

List the fetched commits that your main does not have yet.

--all
Fetch from all remotes.
--prune
Remove remote-tracking branches whose branch no longer exists on the remote.
--tags
Fetch every tag, not only those attached to fetched commits.

git pull

Fetches the upstream branch and then folds its new commits into your current branch.

It is a fetch followed by a merge, or by a rebase if you have configured that. When you and the remote both have new commits and you have not said which approach you prefer, recent Git versions stop and ask you to choose, either with a flag or by setting pull.rebase.

Shell
git pull

Update the current branch from its upstream.

Shell
git pull origin main

Pull a named branch from a named remote.

Shell
git pull --ff-only

Update only if no merge is needed, and stop otherwise.

--rebase
Replay your local commits on top of the fetched ones instead of merging.
--ff-only
Only fast-forward; fail if the histories have diverged.
--no-rebase
Merge, even if pull.rebase is set.

git pull --rebase

Fetches remote changes and replays your unpushed local commits on top of them instead of creating a merge commit.

It keeps history in a straight line when you and someone else both committed to the same branch. Only your local commits that have not been pushed get rewritten, so it is safe in everyday use; if a conflict appears, resolve it, stage the file, and run git rebase --continue.

Shell
git pull --rebase

Update the current branch by rebasing local commits.

Shell
git config --global pull.rebase true

Make every plain git pull rebase by default.

Shell
git pull --rebase --autostash

Set uncommitted edits aside, pull, then put the edits back.

git push

Uploads commits from your current branch to its matching branch on the remote.

Git rejects the push if the remote has commits you do not have, so that nothing there is overwritten; pull or fetch and integrate, then push again. Without arguments it sends the current branch to its upstream, which you set once with -u.

Shell
git push

Push the current branch to its upstream.

Shell
git push origin main

Push main to origin explicitly.

Shell
git push --dry-run

Show what would be sent without sending it.

-u
Record the remote branch as this branch's upstream.
--tags
Also push all local tags.
--dry-run
Report what would happen without pushing anything.

git push -u origin <branch>

Publishes a new branch to the remote and remembers that remote branch as its upstream.

Once the upstream is set, plain git push and git pull on that branch know where to go, and git status can report whether you are ahead or behind. To skip this step for every new branch, set push.autoSetupRemote to true.

Shell
git push -u origin feature/search

Publish a new branch and set its upstream.

Shell
git push -u origin HEAD

The same, without typing the branch name.

Shell
git config --global push.autoSetupRemote true

Let a plain git push create the upstream automatically.

git push --force-with-lease

Overwrites the remote branch with your local version, but only if the remote still points where you last saw it.

After a rebase or amend on a branch you already pushed, a normal push is rejected and some form of forced push is needed. Plain --force replaces the remote branch no matter what is there, whereas --force-with-lease first checks that nobody has pushed since your last fetch and refuses if they have.

Careful: It still rewrites history on the remote, so anyone who pulled the old commits has to reconcile their copy. The check compares against your remote-tracking branch, so if a fetch (including an automatic one run by an editor) updated it without you looking at the new commits, the lease passes and those commits are overwritten anyway; adding --force-if-includes closes that gap. Avoid forced pushes to shared branches such as main.

Shell
git push --force-with-lease

Update your own rebased branch on the remote.

Shell
git push --force-with-lease --force-if-includes

Also confirm you have actually integrated the remote commits you fetched.

--force-if-includes
Only allow the forced push if the remote's latest commit has at some point been part of your local branch.

Inspecting history

Every commit stays in the repository, so you can find out what changed, who changed it, and why. The commands here read history rather than change it.

git log

Lists the commits reachable from your current branch, newest first.

The default view prints the full ID, author, date, and message of every commit, which gets long quickly; press q to leave the pager. Adding --oneline and --graph turns it into a compact picture of how branches split and merge, and filters narrow it down by author, date, or content.

Shell
git log --oneline --graph --all

Compact diagram of every branch and merge.

Shell
git log -n 5

Only the five most recent commits.

Shell
git log --author="Ada" --since="2 weeks ago"

Filter by author and date.

Shell
git log -S "fetchUser" --oneline

Find commits that added or removed a piece of code.

--oneline
One line per commit: short ID and the message's first line.
--graph
Draw lines beside the commits showing branches and merges.
--all
Include every branch, remote-tracking branch, and tag, not just the current branch.
-n <number>
Show at most this many commits.

git log -p

Shows commit history together with the full set of changes each commit made.

Reading the actual edits next to each message helps when messages are vague. Pair it with -n or a file path to keep the output manageable, or use --stat for a lighter list of the files each commit touched.

Shell
git log -p -n 3

The last three commits with their diffs.

Shell
git log -p src/app.ts

Every recorded change to one file.

Shell
git log --stat

Changed files and line counts for each commit.

git log -- <path>

Limits history to the commits that touched a particular file or folder.

The double dash tells Git that what follows is a path rather than a branch name, which matters when the two share a name. By default the history stops at a rename; add --follow to trace a single file back through its earlier names.

Shell
git log -- src/app.ts

Commits that changed this file.

Shell
git log --oneline -- docs/

Compact list of commits touching anything in docs.

Shell
git log --follow -- src/lib/helpers.ts

Keep following the file through renames.

--follow
Continue past renames; works with one file at a time.

git show <commit>

Displays one commit's message, author, date, and the changes it introduced.

Without an argument it shows the latest commit on your branch. It also works on tags, and the commit:path form prints a file exactly as it was in that commit without touching your working copy.

Shell
git show

Inspect the most recent commit.

Shell
git show a1b2c3d

Inspect a specific commit.

Shell
git show HEAD~2:src/app.ts

Print the file as it was two commits ago.

Shell
git show v1.0.0

Show a tag along with the commit it marks.

--stat
List changed files and line counts instead of the full diff.
--name-only
List only the names of changed files.

git blame <file>

Labels each line of a file with the commit, author, and date of the change that last touched it.

Treat it as a way to find context, such as the commit message behind a puzzling line, rather than a way to assign fault. The most recent change to a line is often just reformatting or moved code, and options like -w and -C help you look past those to where the code really came from.

Shell
git blame src/app.ts

Annotate the whole file.

Shell
git blame -L 40,60 src/app.ts

Annotate only lines 40 to 60.

Shell
git blame -w -C src/app.ts

Ignore whitespace-only edits and detect lines copied from other files.

-L <start>,<end>
Restrict the output to a range of lines.
-w
Ignore changes that only affect whitespace.
-C
Detect lines that were moved or copied from other files changed in the same commit.
--ignore-rev <commit>
Skip over a specific commit, such as a bulk reformat.

git reflog

Lists every recent position of HEAD, including commits that no longer appear on any branch.

When a reset, rebase, amend, or deleted branch seems to have lost commits, the reflog almost always still points to them, making it the closest thing Git has to a general undo. It is stored only on your machine, old entries are pruned after a while (by default 90 days, or 30 for commits no longer on any branch), and it cannot recover changes that were never committed.

Shell
git reflog

Show where HEAD has been, most recent first.

Shell
git branch rescue "HEAD@{2}"

Recover an earlier state as a new branch; the quotes stop shells like PowerShell misreading the braces.

Shell
git reset --hard "HEAD@{1}"

Move the current branch back to where it was before the last change (uncommitted edits are discarded).

Shell
git reflog show feature/search

History of where one branch has pointed.

Undoing changes

The right way to undo depends on whether the work is committed and whether anyone else already has it. Use revert for shared commits, and keep reset and clean for work that exists only on your machine.

git revert <commit>

Creates a new commit that applies the exact opposite of an earlier commit.

Because it adds to history instead of removing anything, revert is the safe way to back out a change that is already on a shared branch. Reverting a merge commit needs -m to say which parent represents the main line.

Shell
git revert a1b2c3d

Undo one commit by adding a new commit.

Shell
git revert --no-edit HEAD

Undo the latest commit and accept the generated message.

Shell
git revert -m 1 f00ba12

Undo a merge, keeping the first parent's side.

Shell
git revert -n a1b2c3d e4f5a6b

Stage the reversal of two commits without committing yet.

--no-edit
Use the generated message without opening an editor.
-n
Apply the reverse changes but leave the commit to you.
-m <parent-number>
Choose which parent counts as the main line when reverting a merge.

git reset --soft HEAD~1

Moves the current branch back to an earlier commit while keeping all of the undone changes staged.

It removes the commit and nothing else, so your files and staging area stay exactly as they were and you can recommit with a new message or combine several recent commits into one. If those commits were already pushed, use git revert instead.

Shell
git reset --soft HEAD~1

Undo the last commit and keep its changes staged.

Shell
git reset --soft HEAD~3

Turn the last three commits into staged changes, ready to commit as one.

git reset HEAD~1

Moves the current branch back and unstages the undone changes, leaving them in your working files.

This is the --mixed mode, which is the default, so the flag is normally left out. It suits undoing a commit when you want to stage its changes again in a different arrangement. Run without a commit, git reset simply unstages everything and changes no files.

Shell
git reset HEAD~1

Undo the last commit; its changes stay in your files, unstaged.

Shell
git reset --mixed a1b2c3d

Move the branch back to a specific commit.

Shell
git reset

Unstage everything without touching any files.

git reset --hard <commit>

Moves the current branch to a commit and makes the staging area and tracked files match it exactly.

It is the fastest way to throw everything away and return to a known state, such as matching the remote after a failed experiment. Untracked files are left alone; git clean handles those.

Careful: Uncommitted changes to tracked files are overwritten, and edits that were never staged are gone for good. Commits you reset past can usually be recovered through git reflog for a while, but uncommitted work cannot. Check git status and consider git stash before running it.

Shell
git reset --hard HEAD

Discard every uncommitted change to tracked files.

Shell
git reset --hard origin/main

Make the current branch identical to the remote's main as of your last fetch.

git restore --staged <file>

Takes a file's changes out of the staging area while keeping the edits in your working copy.

This is the safe way to take back a git add before you commit, since your files are not modified. Older versions of Git suggested git reset HEAD <file> for the same job, and that still works.

Shell
git restore --staged src/app.ts

Unstage one file.

Shell
git restore --staged .

Unstage everything.

Shell
git restore --staged -p src/app.ts

Unstage only some chunks of a file.

git clean -n

Lists the untracked files that git clean would delete, without deleting anything.

Always preview first, because clean removes files Git has never stored, so there is no history to restore them from. Use the same extra flags in the preview that you plan to use for the real run.

Shell
git clean -n

Preview untracked files that would be removed.

Shell
git clean -nd

Preview untracked files and folders.

Shell
git clean -ndX

Preview only files matched by .gitignore, such as build output.

-d
Include untracked folders.
-x
Also include files that .gitignore would normally protect.
-X
Include only ignored files.

git clean -fd

Permanently deletes untracked files and folders from your working tree.

By default Git will not delete anything unless you pass -f, a guard controlled by the clean.requireForce setting. Use it to clear out generated files or leftovers after switching branches, once a dry run has shown exactly what will go.

Careful: The deleted files were never in Git, so no Git command can bring them back, and they do not go to the recycle bin or trash. Adding -x also wipes ignored files such as .env and local configuration. Run git clean -n with the same flags first.

Shell
git clean -fd

Delete untracked files and folders.

Shell
git clean -fdx

Also delete ignored files, leaving only what Git tracks.

-f
Required before anything is actually deleted.
-d
Include untracked folders.
-x
Also delete ignored files.
-i
Choose what to delete from an interactive menu.

Stashing work

The stash is a local shelf for unfinished changes, so you can switch tasks with a clean working tree and pick the work up later. Stashes are not sent anywhere when you push.

git stash

Shelves your uncommitted changes to tracked files and returns the working tree to the last commit.

Both staged and unstaged edits are saved, but untracked files stay behind unless you add -u. It is shorthand for git stash push, and when you bring the work back, Git does not try to restore which changes were staged unless you pass --index.

Shell
git stash

Shelve all changes to tracked files.

Shell
git stash -u

Include untracked files as well.

-u
Also stash untracked files.
-a
Also stash untracked and ignored files.

git stash push -m "message"

Shelves changes with a description so you can tell your stashes apart later.

Without a message each entry is labelled only with the branch and the commit it was based on, which gets confusing once there are several. The push form also accepts file paths, so you can stash some files and leave the rest in place.

Shell
git stash push -m "half-done search filters"

Stash everything under a descriptive label.

Shell
git stash push -m "styles only" -- src/app/globals.css

Stash one file and leave other changes alone.

Shell
git stash push --staged -m "ready parts"

Stash only what is currently staged.

Shell
git stash push -p

Choose which chunks to stash.

-m <message>
Attach a description to the stash.
--staged
Stash only staged changes.
-p
Pick individual chunks interactively.
-u
Include untracked files.

git stash list

Shows every saved stash, newest first, each with a reference such as stash@{0}.

stash@{0} is always the most recent entry, and the numbers shift as stashes are added or removed. Use git stash show to look inside one before restoring it. In PowerShell, wrap references like stash@{1} in quotes so the braces are passed to Git intact.

Shell
git stash list

List all stashes.

Shell
git stash show "stash@{1}"

Summary of the files changed in the second stash.

Shell
git stash show -p "stash@{1}"

Full diff of that stash.

git stash pop

Reapplies the latest stash, or one you name, and removes it from the stash list.

If applying it causes a conflict, Git keeps the stash so nothing is lost, and you drop it yourself once the conflict is resolved. Pop is the usual choice when you are simply resuming the shelved work.

Shell
git stash pop

Restore and remove the latest stash.

Shell
git stash pop "stash@{2}"

Restore and remove a specific stash.

Shell
git stash pop --index

Also restore which changes were staged.

--index
Try to restore the staged state as well as the file changes.

git stash apply

Reapplies a stash to your working tree but keeps it in the stash list.

Pick apply over pop when you want the same changes on more than one branch, or when you would like the stash kept as a backup until you are happy with the result. Remove it afterwards with git stash drop.

Shell
git stash apply

Apply the latest stash and keep it.

Shell
git stash apply "stash@{1}"

Apply a specific stash.

Shell
git stash branch fix-from-stash "stash@{1}"

Create a branch at the commit the stash was based on, apply it there, and drop it if that succeeds.

git stash drop

Deletes one stash entry, the most recent one unless you name another.

Use it to tidy up after an apply, or after resolving a conflicted pop. To remove every stash at once, run git stash clear.

Careful: A dropped stash disappears from the list. Git prints its commit ID as it drops it, and until garbage collection runs you can still reapply that ID with git stash apply, but there is no simple listing to find it again later, so treat dropping and clearing as permanent.

Shell
git stash drop

Delete the latest stash.

Shell
git stash drop "stash@{2}"

Delete a specific stash.

Shell
git stash clear

Delete all stashes.

Tags

A tag gives a fixed, readable name to one commit, usually to mark a release. Unlike a branch, a tag stays where it is when new commits are added.

git tag

Lists the tags in the repository.

With no arguments it only lists; give it a name and it creates a tag instead. Tags are sorted by name, so v1.10.0 appears before v1.9.0 unless you ask for version-aware sorting.

Shell
git tag

List all tags.

Shell
git tag -l "v2.*"

List tags that match a pattern.

Shell
git tag --sort=-version:refname

Highest version numbers first.

Shell
git tag -n

Show each tag with the first line of its message.

-l <pattern>
Only list tags matching the pattern.
--sort=<key>
Change the order, for example by version number or date.
-d <tag>
Delete a local tag; the remote copy is not affected.

git tag <name>

Creates a lightweight tag, which is simply a name pointing at a commit.

Lightweight tags store no author, date, or message, so they work better as private bookmarks than as public release markers. Without a commit argument the tag goes on your current commit.

Shell
git tag before-refactor

Bookmark the current commit.

Shell
git tag v0.9-test a1b2c3d

Tag an older commit.

git tag -a <name> -m "message"

Creates an annotated tag that records who made it, when, and a message, along with the commit it marks.

Annotated tags are stored as full objects in the repository, which makes them the better fit for releases, and they are the kind git describe looks for by default. They can also be signed with -s so others can verify who created them.

Shell
git tag -a v1.2.0 -m "Release 1.2.0"

Tag the current commit as a release.

Shell
git tag -a v1.1.1 -m "Patch release" a1b2c3d

Tag an earlier commit.

Shell
git show v1.2.0

See the tag's details and the commit it marks.

-a
Create an annotated tag.
-m <message>
Give the message inline instead of opening an editor.
-s
Create a signed annotated tag using your configured signing key.

git push origin <tag>

Uploads tags to a remote, which an ordinary git push does not do.

Tags stay on your machine until you push them explicitly. The --follow-tags option is a tidy middle ground that sends annotated tags pointing at the commits you are pushing, without publishing every lightweight bookmark.

Shell
git push origin v1.2.0

Push a single tag.

Shell
git push origin --tags

Push every local tag.

Shell
git push --follow-tags

Push commits together with the annotated tags that point at them.

Shell
git config --global push.followTags true

Make --follow-tags the default for every push.

--tags
Push all local tags.
--follow-tags
Push annotated tags that point at commits included in this push.