The dangerous commands list
Advanced Git CLI
Why this matters
Git is far safer than its reputation, and the list of genuinely destructive commands is short enough to memorise. Everything not on this list is recoverable through the reflog (lesson 12.1). Knowing the seven means you can use the rest of Git without hesitating.
The two questions
Before any command on this page:
- Is there uncommitted work?
git statusanswers it. If yes, commit or stash first; most of the damage on this page is to work Git never recorded. - Has this been pushed? If yes, anything that rewrites history affects other people, and
git revertis the alternative.
The list
1. git reset --hard
Takes: every uncommitted change in tracked files, staged or not. Also moves the branch.
Recovery: the commits are in the reflog; the uncommitted changes are gone.
Make it safe: git status first. git stash -u if anything is unfinished. Or use git reset --keep, which refuses when it would overwrite local changes.
2. git checkout -- <file> and git restore <file>
Takes: your edits to that file, permanently.
Recovery: none in Git. Your editor's local history may have it: VS Code's Timeline and IntelliJ's Local History both record saves independently of Git.
Make it safe: run git diff <file> first and read what you are about to discard.
3. git clean -fd
Takes: untracked files and directories, permanently. Git never had them, so nothing knows they existed.
Recovery: none.
Make it safe: always run git clean -nd first, which lists exactly what would be removed and deletes nothing. Note that -x additionally removes ignored files, which is how people delete their .env and their virtual environment in one command.
4. git push --force
Takes: whatever was on the remote branch, including commits colleagues pushed while you were working.
Recovery: from the other person's reflog, plus a conversation.
Make it safe: use --force-with-lease, which refuses when the remote has moved (lesson 12.8), and never force a shared or protected branch.
5. git rebase on a shared branch
Takes: nothing directly, but it replaces every commit with a new one, so anyone else's clone no longer matches. The damage arrives later, as everyone's confusing merges.
Recovery: git rebase --abort before it finishes; after pushing, it is a team-wide reconciliation.
Make it safe: rebase only branches nobody else has checked out. Rebasing your own feature branch onto an updated main is normal and encouraged.
6. git branch -D
Takes: the branch name, even when the branch holds commits that are not merged anywhere. The lowercase -d refuses in that case, which is why it exists.
Recovery: the reflog, or the hash Git prints as it deletes.
Make it safe: use -d and only reach for -D when Git has refused and you have understood why.
7. git filter-repo and friends
Takes: rewrites every commit in the repository, changing all their hashes. It is the right tool for removing a leaked secret from history (lesson 8.7) and a catastrophe when used casually.
Recovery: from a backup clone, if you made one.
Make it safe: never do it alone. It is a planned operation with the whole team, everyone re-clones afterwards, and the leaked credential is rotated regardless.
What is not dangerous
Worth stating, because fear of Git usually attaches to the wrong commands:
| Command | Why it is safe |
|---|---|
git status, git log, git diff, git show |
They only read |
git add |
Reversible with git restore --staged |
git commit |
Reversible; the reflog remembers it either way |
git fetch |
Downloads; changes nothing you are working on |
git switch |
Refuses when it would lose changes |
git merge |
Abortable with --abort |
git revert |
Adds a commit; removes nothing |
git stash |
Keeps your work; pop brings it back |
The habits that replace caution
- Commit early. A commit is the moment work becomes recoverable, and it is the single most effective protection on this page.
git statusbefore anything with a flag in it.- Read the dry run.
git clean -ndexists for exactly this. - Prefer the safe spelling:
-dover-D,--force-with-leaseover--force,restore --stagedoverrestore. - Push your branch. Work that exists in two places is not lost by any command on this page.
How to do it
The three checks, in the order you would use them:
$ git status
$ git clean -nd
$ git diff <file>Each of them is free and takes a second, and between them they prevent every irreversible outcome on this page.
VS Code confirms before Discard Changes and before Discard All Changes, and force push is disabled until you turn it on in settings. The Timeline view is the last line of defence for uncommitted work, because it records file saves independently of Git.
Local History on a file or directory is IntelliJ's equivalent, and it is more thorough: right-click → Local History → Show History shows every save with a diff, whether or not Git ever saw it. IntelliJ also confirms destructive Git actions and offers a Keep mode on reset.
The platform protects the shared branches: protected branches refuse force pushes and deletions, and only Maintainers and Owners can change those settings (lesson 9.5). Nothing protects your local clone, which is where every command on this page runs.
The same protections through rulesets: Block force pushes and Restrict deletions (lesson 10.5).
Common mistakes
-fbefore-n. The dry run is the whole point ofgit clean.-xongit clean, which adds ignored files: exactly the ones that are hard to recreate.--forcetyped from muscle memory.-Dbecause-drefused. The refusal was information.- Assuming the reflog covers uncommitted work. It covers commits.
- Running a rewriting command on a branch someone else has.
Try it yourself
Goal: see the dry run save you, without losing anything.
- In your practice repository, create two untracked files:
scratch.txtand a foldertmp/with a file in it. - Run
git clean -ndand read the list. Nothing has been deleted. - Run
git clean -fdand confirm both are gone, and thatgit statusshows nothing about them. - Now create a
.envfile, add it to.gitignore, and rungit clean -ndagain: it is not listed. - Run
git clean -ndxand see it appear. Do not run the-fversion.
Expected result: you have seen exactly what -n, -d and -x each contribute, on files that do not matter.
Show solution
Step 5 is the one to remember. -x is the difference between "remove junk" and "remove my local configuration", and the only way to tell them apart in advance is the dry run. Every dangerous command on this page has an equivalent way to look before acting.