Remove tracked files safely with git rm
You will remove a tracked file from both your working tree and Git's index, or remove it from the index while leaving the file on disk. Allow about ten minutes for a single file and a little longer for a directory or a recovery check. These commands are ordinary user commands. You normally do not need sudo, and using it can leave the repository owned by root.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Check the repository and the target
Run this from the repository that contains the file. The installed command on this machine is Git 2.43.0, from the Ubuntu git-man package version 1:2.43.0-1ubuntu7.3. The guide follows that local manual page, including its index and sparse-checkout behaviour.
$ git --version
git version 2.43.0
$ git status --short
$ git ls-files -- path/to/old-config.ini
path/to/old-config.ini
The second command should show the path if Git tracks it. An empty result means that git rm is probably the wrong tool, because it removes paths known to Git. Read the status before acting so that an existing staged change or an unrelated dirty file does not surprise you.
Checkpoint
You have confirmed the repository, the exact tracked path and the change you intend to make.
2. Preview the removal
Use --dry-run before a removal that matters. It reports the paths that would be removed without changing the index or working tree.
$ git rm --dry-run -- path/to/old-config.ini
rm 'path/to/old-config.ini'
The -- separates options from pathspecs. Keep it when a filename could begin with a hyphen, or simply use it as a clear boundary in scripts. The output is a plan, not proof that the command will still succeed later: another process or an earlier command can change the repository between the preview and the real operation.
3. Remove one file from disk and the index
Once the preview is correct, run the same command without --dry-run:
$ git rm -- path/to/old-config.ini
rm 'path/to/old-config.ini'
$ git status --short
D path/to/old-config.ini
This stages the deletion and removes the working-tree file. It is not a commit. The deletion remains local until you commit it, so check the staged diff before sharing or merging the change:
$ git diff --cached --stat
path/to/old-config.ini | 12 ------------
1 file changed, 12 deletions(-)
$ git diff --cached -- path/to/old-config.ini
Warning
Do not treat a successful git rm as a backup. A file removed from the working tree is not recoverable from an uncommitted working copy. If the content existed in a previous commit, Git can usually restore it, but verify that history contains the version you need before committing anything irreversible.
4. Keep the file locally but stop tracking it
For a local configuration file that should remain on this machine, use --cached:
$ git rm --cached -- config/local.ini
rm 'config/local.ini'
$ test -f config/local.ini && echo 'file remains on disk'
file remains on disk
$ git status --short
D config/local.ini
?? config/local.ini
The staged deletion tells the next commit to remove the file from the repository. The untracked entry shows that the working copy still exists. Add a suitable pattern to .gitignore before committing if this is a generated or machine-specific file. Do not add real passwords, tokens or private keys to an ignore file as a substitute for rotating a secret that was already committed.
--cached can also remove a modified path from the index when the staged content matches either the branch tip or the working file. For other changes, Git refuses by default so that you do not silently discard staged work.
5. Remove a directory or a selected group
A leading directory name needs -r. Preview first, especially if the directory contains more than the files you meant to delete:
$ git rm -r --dry-run -- docs/generated
rm 'docs/generated/index.html'
rm 'docs/generated/version.txt'
$ git rm -r -- docs/generated
Pathspec matching is performed by Git when the pattern is quoted. This can include matching files below nested directories. For example, the quoted pattern below selects tracked text files below Documentation:
$ git rm --dry-run -- 'Documentation/*.txt'
Quoting is a useful distraction trap here. An unquoted * may be expanded by the shell first, changing what Git receives. A pattern such as 'd*' can also match a directory named d2, whereas 'd/*' describes paths below d. Use --pathspec-from-file for a long list, and add --pathspec-file-nul when the list is NUL-separated or contains newlines and quotes that must be treated literally.
6. Handle modified files deliberately
By default, git rm refuses a file whose working-tree or staged content has changed from the branch tip. That refusal protects edits:
$ git rm -- path/to/edited-file
error: the following file has local modifications:
path/to/edited-file
First decide whether those edits are needed. Save them in a commit or a patch if they matter. If deletion is definitely intended, -f or --force overrides the up-to-date check and removes the file. Preview with the same force option first:
$ git rm --dry-run --force -- path/to/edited-file
rm 'path/to/edited-file'
$ git rm --force -- path/to/edited-file
Warning
Force is destructive to the uncommitted working copy. It is not an elevated-privilege operation, and it does not make the discarded content recoverable by itself.
7. Undo before committing
If you remove a file and change your mind before committing, restore both the index and working tree from the current HEAD:
$ git restore --source=HEAD --staged --worktree -- path/to/old-config.ini
$ git status --short
$ test -f path/to/old-config.ini && echo restored
restored
For a --cached removal where you want to keep the local file and only undo the staged deletion, restore the index without touching the working tree:
$ git restore --source=HEAD --staged -- config/local.ini
$ git status --short
M config/local.ini
Check the output carefully. If the path was already modified before the removal, restoring from HEAD may replace that working copy. A committed deletion needs a different recovery step, such as restoring the path from the commit that still contains it, then reviewing and committing that restoration.
8. Deal with missing files and submodules
If a tracked file was already deleted with ordinary rm, git rm is not required. git add -u or git commit -a can record such removals in their broader workflows. If you want to remove only disappeared paths from the index while leaving other dirty work alone, inspect the deleted-path list first rather than applying a broad command.
A submodule has extra history and metadata. The manual distinguishes removing a submodule with git rm from removing only its local checkout with git submodule deinit. Use the latter when the repository should remain configured and only the checkout should disappear. Never delete a submodule's internal .git directory casually, because an older layout can contain the submodule's history.
Done means
- The target path was confirmed with
git ls-filesand previewed with--dry-run. - You chose between deleting the working copy and using
--cachedto keep it. - Directory removals used
-r, and pathspecs were quoted where Git should expand them. - Modified files were saved or explicitly reviewed before any use of
--force. git diff --cachedshows only the intended deletion, and the change has not been committed until recovery is no longer needed.