rm Git Command Guide
The git rm command removes files from the working tree and/or the index (staging area). It can remove files completely from Git tracking or just unstage them while keeping the working tree copy.
git rm Syntax:
Section titled “git rm Syntax:”git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]Removal Options:
Section titled “Removal Options:”| Option | Description |
|---|---|
-f, --force | Override safety checks, remove modified files |
-n, --dry-run | Show what would be removed without doing it |
-r | Allow recursive removal of directories |
--cached | Remove from index only, keep working tree file |
Output Control:
Section titled “Output Control:”| Option | Description |
|---|---|
--ignore-unmatch | Exit successfully if no files match |
-q, --quiet | Suppress output messages |
--pathspec-from-file=<file> | Read pathspecs from file |
--pathspec-file-nul | Use NUL character as path separator |
Parameters:
Section titled “Parameters:”| Parameter | Description |
|---|---|
<pathspec> | Files/directories to remove (globbing supported) |
Understanding File Removal:
Section titled “Understanding File Removal:”Removal Modes:
Section titled “Removal Modes:”File Removal Types:├── Complete Removal: Remove from working tree AND index├── Index-Only Removal: Remove from index, keep working tree├── Recursive Removal: Remove directories and contents├── Forced Removal: Remove modified/staged files
Safety Checks:├── File must match HEAD version (unless -f used)├── No staged changes allowed (unless -f used)├── Sparse checkout patterns respected└── Only Git-tracked files can be removedPath Specifications:
Section titled “Path Specifications:”Pathspec Patterns:├── file.txt # Single file├── *.txt # All .txt files├── dir/ # Directory (requires -r)├── dir/*.js # JS files in directory├── **/*.log # Log files recursively
Globbing Behavior:├── Matches across directory boundaries├── d* vs d/* have different meanings├── Hidden files need explicit specification└── Untracked files are ignoredRemoval Process:
Section titled “Removal Process:”Removal Workflow:1. Validate pathspecs match Git-tracked files2. Check safety conditions (unless -f)3. Remove from index (always)4. Remove from working tree (unless --cached)5. Stage the removal for commit6. Update Git's internal stateBasic File Removal:
Section titled “Basic File Removal:”Remove Single Files:
Section titled “Remove Single Files:”# Remove a single filegit rm file.txt
# Remove multiple filesgit rm file1.txt file2.txt file3.txt
# Remove with confirmationgit rm -n file.txt # Dry run firstgit rm file.txt # Then removeRemove Directories:
Section titled “Remove Directories:”# Remove directory recursivelygit rm -r directory/
# Remove multiple directoriesgit rm -r dir1/ dir2/
# Remove directory contents onlygit rm directory/* # Keeps directory itselfRemove from Index Only:
Section titled “Remove from Index Only:”# Unstage file but keep in working treegit rm --cached file.txt
# Unstage entire directorygit rm --cached -r directory/
# Unstage all files matching patterngit rm --cached *.logAdvanced Removal Scenarios:
Section titled “Advanced Removal Scenarios:”Force Removal of Modified Files:
Section titled “Force Removal of Modified Files:”# Remove modified filegit rm -f modified-file.txt
# Remove staged but modified filegit add file.txt # Stage changes# Modify file.txt againgit rm -f file.txt # Force remove despite staged changes
# Remove files that differ from HEADgit rm -f file-with-changes.txtPattern-Based Removal:
Section titled “Pattern-Based Removal:”# Remove all log filesgit rm *.log
# Remove files recursively by patterngit rm "**/*.tmp"
# Remove files in specific directoriesgit rm "src/**/*.bak"
# Remove files matching multiple patternsgit rm *.txt *.md *.htmlBatch Removal with Pathspecs:
Section titled “Batch Removal with Pathspecs:”# Remove files listed in a fileecho "file1.txt" > to-remove.txtecho "file2.txt" >> to-remove.txtgit rm --pathspec-from-file=to-remove.txt
# Remove files with null separatorsprintf "file1.txt\0file2.txt\0" | git rm --pathspec-from-file=- --pathspec-file-nul
# Remove files from find commandfind . -name "*.tmp" -print0 | git rm --pathspec-from-file=- --pathspec-file-nulSelective Directory Removal:
Section titled “Selective Directory Removal:”# Remove directory but keep specific filesgit rm -r directory/# This removes everything in directory/
# Remove all except specific files (requires manual approach)git rm directory/file1.txt directory/file2.txt# Keep directory/file3.txtConfiguration and Best Practices:
Section titled “Configuration and Best Practices:”Git Configuration for rm:
Section titled “Git Configuration for rm:”# Configure rm behaviorgit config core.sparseCheckout true # Enable sparse checkout
# Configure safety checksgit config core.trustctime false # Don't trust file timestamps
# Configure pathspec handlinggit config core.quotePath true # Quote paths with special charactersSafe Removal Practices:
Section titled “Safe Removal Practices:”# Always check what will be removedgit rm -n <pathspec> # Dry run first
# Backup before mass removalgit branch backup-before-rm
# Verify files are trackedgit ls-files <pathspec> # Check what's tracked
# Use git status to confirm changesgit status # After removalRecovery from Accidental Removal:
Section titled “Recovery from Accidental Removal:”# Recover accidentally removed filesgit checkout HEAD -- <removed-file> # Restore from HEADgit reset HEAD <removed-file> # Unstage removalgit checkout <removed-file> # Restore working tree
# Recover directorygit checkout HEAD -- <directory>/Integration with Development Workflows:
Section titled “Integration with Development Workflows:”Clean Up Workflow:
Section titled “Clean Up Workflow:”#!/bin/bash# Repository cleanup workflow
cleanup_repository() { echo "Cleaning up repository..."
# Remove build artifacts git rm -f --ignore-unmatch *.o *.exe *.dll 2>/dev/null || true
# Remove temporary files git rm -f --ignore-unmatch *.tmp *.temp 2>/dev/null || true
# Remove log files git rm -f --ignore-unmatch *.log 2>/dev/null || true
# Remove IDE files git rm -f --ignore-unmatch .vscode/settings.json 2>/dev/null || true git rm -f --ignore-unmatch *.swp *.swo 2>/dev/null || true
echo "Cleanup complete. Review changes with: git status"}
cleanup_repositorySelective Staging Workflow:
Section titled “Selective Staging Workflow:”# Use rm --cached for selective stagingselective_stage() { local file="$1"
# Stage everything git add .
# Unstage the specific file (keeps changes) git rm --cached "$file"
echo "File $file unstaged but changes preserved" echo "Use: git add $file # to stage later" echo "Or: git checkout $file # to discard changes"}
selective_stage "config/secrets.txt"Repository Restructuring:
Section titled “Repository Restructuring:”# Restructure repository with rmrestructure_repo() { echo "Restructuring repository..."
# Move files to new structure mkdir -p new-structure/ git mv old-file.txt new-structure/
# Remove old directories git rm -r old-directory/
# Clean up empty directories find . -type d -empty -delete 2>/dev/null || true
echo "Repository restructured"}
restructure_repoTroubleshooting Common Issues:
Section titled “Troubleshooting Common Issues:”Cannot Remove Modified Files:
Section titled “Cannot Remove Modified Files:”# Handle modified file removalgit status # Check modified files
# Option 1: Commit changes firstgit add modified-file.txtgit commit -m "Update file before removal"
# Option 2: Force removal (loses changes)git rm -f modified-file.txt
# Option 3: Stash changes, remove, then apply stashgit stash push modified-file.txtgit rm modified-file.txtgit stash pop # May cause conflictsPathspec Issues:
Section titled “Pathspec Issues:”# Fix pathspec problemsgit rm "file with spaces.txt" # Quote paths with spaces
# Use -- to separate paths from optionsgit rm -- -file.txt # Remove file named "-file.txt"
# Handle globbing issuesgit rm "*.txt" # Remove all .txt filesgit rm "dir/*.txt" # Remove .txt files in dir/Directory Removal Issues:
Section titled “Directory Removal Issues:”# Handle directory removalgit rm directory/ # Fails without -r
# Remove directory recursivelygit rm -r directory/
# Remove directory contents but keep directorygit rm directory/* # Directory remains emptySparse Checkout Conflicts:
Section titled “Sparse Checkout Conflicts:”# Handle sparse checkout issuesgit sparse-checkout list # Check patterns
# Remove files outside sparse patternsgit rm --ignore-unmatch outside-file.txt
# Disable sparse checkout temporarilygit sparse-checkout disablegit rm problematic-file.txtgit sparse-checkout reapplyRecovery from Mistakes:
Section titled “Recovery from Mistakes:”# Recover from accidental removalgit reflog # Find last good state
# Restore from refloggit reset --hard HEAD@{1} # Go back one step
# Restore specific filegit checkout HEAD@{1} -- accidentally-removed.txt
# Unstage removalgit reset HEAD accidentally-removed.txtPerformance Issues with Large Removals:
Section titled “Performance Issues with Large Removals:”# Handle large file removals efficientlylarge_removal() { local pattern="$1"
echo "Removing files matching: $pattern"
# Use find for large operations find . -name "$pattern" -type f | head -100 | while read -r file; do git rm "$file" 2>/dev/null || true done
# Commit in batches git commit -m "Remove batch of $pattern files"}
large_removal "*.log"Real-World Usage Examples:
Section titled “Real-World Usage Examples:”Repository Cleanup Scripts:
Section titled “Repository Cleanup Scripts:”#!/bin/bash# Comprehensive repository cleanup
cleanup_repo() { echo "Starting repository cleanup..."
# Remove common build artifacts artifacts=("*.o" "*.exe" "*.dll" "*.so" "*.dylib" "*.class" "*.jar") for pattern in "${artifacts[@]}"; do git rm -f --ignore-unmatch "$pattern" 2>/dev/null || true done
# Remove temporary files temp_files=("*.tmp" "*.temp" "*~" "*.swp" "*.swo" ".DS_Store") for pattern in "${temp_files[@]}"; do git rm -f --ignore-unmatch "$pattern" 2>/dev/null || true done
# Remove log files git rm -f --ignore-unmatch "*.log" "logs/*.log" 2>/dev/null || true
# Remove IDE files ide_files=(".vscode/" ".idea/" "*.sublime-*" ".atom/") for dir in "${ide_files[@]}"; do git rm -r -f --ignore-unmatch "$dir" 2>/dev/null || true done
# Remove OS-specific files os_files=("Thumbs.db" "Desktop.ini" ".AppleDouble/") for file in "${os_files[@]}"; do git rm -f --ignore-unmatch "$file" 2>/dev/null || true done
echo "Cleanup complete. Run: git status"}
cleanup_repoSelective File Management:
Section titled “Selective File Management:”# Manage sensitive filesmanage_sensitive_files() { echo "Managing sensitive files..."
# Remove sensitive files from tracking sensitive_files=("config/secrets.json" "keys/private.pem" "*.key")
for file in "${sensitive_files[@]}"; do if git ls-files "$file" | grep -q .; then echo "Removing sensitive file: $file" git rm -f "$file"
# Add to .gitignore if not already there if ! grep -q "^$(basename "$file")$" .gitignore 2>/dev/null; then echo "$(basename "$file")" >> .gitignore git add .gitignore fi fi done
echo "Sensitive files removed and .gitignore updated"}
manage_sensitive_filesAutomated File Organization:
Section titled “Automated File Organization:”# Organize files by typeorganize_by_type() { echo "Organizing files by type..."
# Create type directories mkdir -p docs/ scripts/ images/ data/
# Move files to appropriate directories git mv *.md docs/ 2>/dev/null || true git mv *.sh scripts/ 2>/dev/null || true git mv *.png *.jpg *.gif images/ 2>/dev/null || true git mv *.json *.csv *.xml data/ 2>/dev/null || true
# Remove empty directories find . -type d -empty -delete 2>/dev/null || true
echo "Files organized by type"}
organize_by_typeGit Hook Integration:
Section titled “Git Hook Integration:”# Pre-commit hook for file validationcat > .git/hooks/pre-commit << 'EOF'#!/bin/bash# Validate files before commit
# Remove unwanted filesunwanted_patterns=("*.log" "*.tmp" "*~" ".DS_Store")
for pattern in "${unwanted_patterns[@]}"; do if git ls-files "$pattern" | grep -q .; then echo "Removing unwanted files: $pattern" git rm -f --ignore-unmatch "$pattern" fidone
# Check file sizesgit ls-files | while read -r file; do size=$(wc -c < "$file") if [ "$size" -gt 10485760 ]; then # 10MB echo "File too large: $file (${size} bytes)" echo "Consider using Git LFS for large files" exit 1 fidone
echo "✓ Pre-commit validation passed"EOF
chmod +x .git/hooks/pre-commitRepository Migration Cleanup:
Section titled “Repository Migration Cleanup:”# Clean up during repository migrationmigration_cleanup() { local source_scm="$1"
echo "Cleaning up repository migrated from $source_scm..."
case "$source_scm" in "svn") # Remove SVN metadata find . -name ".svn" -type d -exec git rm -r {} + 2>/dev/null || true git rm -f --ignore-unmatch .git/svn/ 2>/dev/null || true ;;
"hg") # Remove Mercurial metadata git rm -f --ignore-unmatch .hg* 2>/dev/null || true git rm -f --ignore-unmatch .hg/ 2>/dev/null || true ;;
"cvs") # Remove CVS metadata find . -name "CVS" -type d -exec git rm -r {} + 2>/dev/null || true git rm -f --ignore-unmatch .cvsignore 2>/dev/null || true ;; esac
# Remove common migration artifacts git rm -f --ignore-unmatch *.orig *.rej 2>/dev/null || true
echo "Migration cleanup complete"}
migration_cleanup "svn"Batch File Operations:
Section titled “Batch File Operations:”# Batch remove files based on criteriabatch_remove() { local criteria="$1"
echo "Batch removing files by criteria: $criteria"
case "$criteria" in "old") # Remove files not modified in 6 months find . -type f -mtime +180 | while read -r file; do if git ls-files "$file" | grep -q .; then git rm "$file" 2>/dev/null || true fi done ;;
"large") # Remove files larger than 1MB git ls-files | while read -r file; do if [ -f "$file" ] && [ "$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file")" -gt 1048576 ]; then git rm "$file" fi done ;;
"unused") # Remove files not referenced in code # This is complex and would require language-specific analysis echo "Unused file detection requires manual analysis" ;; esac
echo "Batch removal complete"}
batch_remove "large"What’s the difference between git rm and rm?
Section titled “What’s the difference between git rm and rm?”git rm removes files from Git tracking and working tree; rm only removes from filesystem. git rm stages the removal for commit.
How do I remove a file from Git but keep it locally?
Section titled “How do I remove a file from Git but keep it locally?”Use git rm —cached
Can git rm remove directories?
Section titled “Can git rm remove directories?”Yes, use git rm -r
What happens if I try to remove a modified file?
Section titled “What happens if I try to remove a modified file?”Git prevents removal unless you use -f. The file must match the HEAD version or you must force removal.
How do I remove files matching a pattern?
Section titled “How do I remove files matching a pattern?”Use globbing: git rm *.txt removes all .txt files. Use quotes for complex patterns.
Can I undo a git rm?
Section titled “Can I undo a git rm?”Yes, git reset HEAD
What’s the difference between git rm and git mv?
Section titled “What’s the difference between git rm and git mv?”git rm removes files; git mv moves/renames files while preserving Git history.
How do I remove files from the repository but keep them in .gitignore?
Section titled “How do I remove files from the repository but keep them in .gitignore?”Remove with git rm, then add to .gitignore to prevent future tracking.
Can git rm work with untracked files?
Section titled “Can git rm work with untracked files?”No, git rm only works with tracked files. Use regular rm for untracked files.
How do I remove a file from all commits in history?
Section titled “How do I remove a file from all commits in history?”Use git filter-branch or git filter-repo to rewrite history. git rm only affects the current state.
What’s the —ignore-unmatch option for?
Section titled “What’s the —ignore-unmatch option for?”Makes git rm exit successfully even if no files match the pathspec, useful in scripts.
Can git rm remove staged changes?
Section titled “Can git rm remove staged changes?”No, git rm removes files from tracking. Use git reset to unstage changes.
How do I remove files listed in a file?
Section titled “How do I remove files listed in a file?”Use —pathspec-from-file=
What’s the safest way to remove many files?
Section titled “What’s the safest way to remove many files?”Use -n for dry run first, then remove. Consider doing it in batches for large operations.
Can git rm work with sparse checkouts?
Section titled “Can git rm work with sparse checkouts?”Yes, but it only removes paths within the sparse checkout patterns.
How do I remove files that were accidentally added?
Section titled “How do I remove files that were accidentally added?”Use git rm —cached to unstage them, then add proper ignore rules.
Applications of the git rm command
Section titled “Applications of the git rm command”- File Cleanup: Remove unwanted files from repository tracking
- Repository Restructuring: Reorganize file structure and remove old directories
- Security Management: Remove sensitive files and update ignore rules
- Build Artifact Removal: Clean up generated files and build outputs
- Migration Cleanup: Remove old SCM metadata during repository migration
- Selective Staging: Unstage files while preserving working tree changes