This warning occurs when Git tries to remove a directory during operations like checkout, pull, or submodule updates, but .DS_Store or other macOS-generated files prevent deletion. The operation typically succeeds despite the warning.
The "warning: unable to rmdir: Directory not empty" error indicates that Git attempted to remove a directory but couldn't because it contains files that Git doesn't track. On macOS, this is most commonly caused by .DS_Store files, which are automatically created by Finder to store custom folder attributes like icon positions and view settings. When you switch branches, pull changes, or update submodules, Git may need to remove directories that don't exist in the target branch or commit. However, Git only manages tracked files. If a directory contains untracked files like .DS_Store, Thumbs.db (Windows), or Desktop.ini (Windows), Git cannot safely delete the directory without potentially losing those files. This warning is non-fatal in most cases - your Git operation typically completes successfully. The warning simply informs you that Git left certain directories in place because they weren't empty. However, these leftover directories can sometimes cause confusion or accumulate over time. The issue is particularly common on macOS because Finder aggressively creates .DS_Store files whenever you browse folders, even repository directories. Many developers working on cross-platform projects encounter this warning regularly.
Before taking action, note that this warning is typically non-fatal. Your Git operation most likely completed successfully despite the warning.
Check if your operation succeeded:
# Verify you're on the expected branch
git branch
# Check repository status
git statusIf everything looks correct, the warning is purely informational. Git is telling you it couldn't clean up certain directories because they contain files Git doesn't manage.
The warning becomes problematic only when:
- Leftover directories cause build issues or confusion
- You're dealing with submodule directory conflicts
- The same warnings appear repeatedly and clutter your terminal
If .DS_Store files are causing the issue, remove them from your working directory:
Find and remove all .DS_Store files recursively:
find . -name ".DS_Store" -type f -deleteVerify they're gone:
find . -name ".DS_Store"If .DS_Store files were previously committed, remove them from Git tracking:
# Remove from Git but keep local file
git rm --cached .DS_Store
# Remove all .DS_Store files recursively from Git
find . -name ".DS_Store" -print0 | xargs -0 git rm --cached --ignore-unmatchThen commit the removal:
git commit -m "Remove .DS_Store files from repository"Prevent .DS_Store files from ever being tracked in this repository:
Add to project .gitignore:
echo ".DS_Store" >> .gitignore
echo "**/.DS_Store" >> .gitignore
git add .gitignore
git commit -m "Ignore .DS_Store files"Or create/update a global gitignore for all repositories:
# Create or append to global gitignore
echo ".DS_Store" >> ~/.gitignore_global
echo "**/.DS_Store" >> ~/.gitignore_global
echo "._.DS_Store" >> ~/.gitignore_global
echo "**/._.DS_Store" >> ~/.gitignore_global
# Configure Git to use this global gitignore
git config --global core.excludesfile ~/.gitignore_globalComprehensive macOS-specific global gitignore:
cat >> ~/.gitignore_global << 'EOF'
# macOS system files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
.AppleDouble
.LSOverride
Icon
# Thumbnails
._*
EOFApplications with open file handles can prevent directory removal. Close these before Git operations:
Common culprits:
- Text editors (VS Code, Sublime, Atom, Vim)
- IDEs (Xcode, IntelliJ, WebStorm)
- File managers (Finder windows open in the repo)
- Terminal sessions in the affected directories
- File watchers (webpack dev server, nodemon, etc.)
- Build tools (running compilers, test watchers)
On macOS, find processes using files in a directory:
# Check what's using files in the problematic directory
lsof +D /path/to/directory
# Or for a specific file
lsof /path/to/specific/fileKill a specific process if needed:
# Find process ID
lsof +D /path/to/directory | awk 'NR>1 {print $2}' | sort -u
# Kill process (replace PID with actual process ID)
kill -9 PIDAfter closing applications, retry your Git operation.
For persistent issues, force the checkout and clean untracked files:
Force checkout to ignore working directory conflicts:
git checkout --force <branch-name>Clean untracked files and directories:
# Preview what will be removed (dry run)
git clean -fd --dry-run
# Actually remove untracked files and directories
git clean -fdNuclear option - clean everything including ignored files:
# Preview first!
git clean -fdx --dry-run
# Remove all untracked files including .gitignore matches
git clean -fdxWarning: git clean -fdx removes everything not tracked by Git, including build outputs, dependencies (node_modules), and IDE settings. Use with caution.
If the warning involves submodules, use recursive submodule handling:
Checkout with submodule recursion:
git checkout --recurse-submodules <branch-name>Configure Git to always recurse into submodules (Git 2.14+):
# Global setting
git config --global submodule.recurse true
# Or per-repository
git config --local submodule.recurse trueUpdate submodules properly:
git submodule update --init --recursiveIf submodule directory has leftover .git folder:
# Check if directory has embedded .git
ls -la path/to/submodule/.git
# If you want to remove the submodule completely
git submodule deinit -f path/to/submodule
rm -rf .git/modules/path/to/submodule
rm -rf path/to/submoduleReset submodule to clean state:
# Inside the submodule directory
cd path/to/submodule
git checkout .
git clean -fd
cd ..If other solutions don't work, manually remove the offending directories:
Identify and remove the directory:
# Check what's in the directory Git couldn't remove
ls -la path/to/problematic/directory
# Remove the directory and contents
rm -rf path/to/problematic/directory
# Retry your Git operation
git checkout <branch-name>For multiple directories:
# Find all .DS_Store files and their parent dirs
find . -name ".DS_Store" -exec dirname {} \; | sort -u
# Remove .DS_Store from each
find . -name ".DS_Store" -type f -deleteHandle permission issues:
# If you get "Permission denied"
sudo rm -rf path/to/problematic/directoryThen verify with git status:
git statusmacOS can be configured to not create .DS_Store files on network volumes and external drives:
Disable .DS_Store on network volumes:
defaults write com.apple.desktopservices DSDontWriteNetworkStores trueDisable .DS_Store on USB drives:
defaults write com.apple.desktopservices DSDontWriteUSBStores trueApply changes:
# Restart Finder
killall FinderNote: These settings only affect network volumes and USB drives, not local drives. There's no supported way to completely disable .DS_Store creation on local drives without third-party tools.
To verify settings:
defaults read com.apple.desktopservices DSDontWriteNetworkStores
defaults read com.apple.desktopservices DSDontWriteUSBStoresThese commands return "1" if disabled, or an error if not set (defaults to enabled).
Understanding .DS_Store files:
.DS_Store (Desktop Services Store) is a proprietary file format created by macOS Finder. It stores custom attributes of folders, such as:
- Icon positions
- Background images
- View options (icon view, list view, column view)
- Window position and size
- Folder-specific settings
These files are created automatically whenever you open a folder in Finder, which is why they appear so frequently in Git repositories.
Cross-platform team considerations:
If your team includes Windows, Linux, and macOS users, consider a comprehensive .gitignore:
# macOS
.DS_Store
.DS_Store?
._*
.AppleDouble
.LSOverride
.Spotlight-V100
.Trashes
# Windows
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
Desktop.ini
# Linux
*~
.directoryUsing git-filter-repo to purge .DS_Store from history:
If .DS_Store files were committed throughout your repository history:
# Install git-filter-repo
pip install git-filter-repo
# Remove .DS_Store from all commits
git filter-repo --invert-paths --path '.DS_Store' --path-glob '**/.DS_Store'Warning: This rewrites repository history. Only do this on repositories that haven't been shared, or coordinate with all collaborators.
Git clean.requireForce setting:
By default, Git requires -f flag for clean operations. You can change this:
# Check current setting
git config --get clean.requireForce
# Disable force requirement (use cautiously)
git config --global clean.requireForce falseHandling stubborn files on macOS:
If files are truly locked:
# Check file flags
ls -lO@e problematic_file
# Remove immutable flag if set
chflags nouchg problematic_file
# Clear all extended attributes
xattr -c problematic_fileIDE-specific solutions:
For VS Code, add to settings.json:
{
"files.exclude": {
"**/.DS_Store": true
}
}For JetBrains IDEs (IntelliJ, WebStorm), add to File > Settings > Editor > File Types > Ignored Files:
.DS_StoreGit sparse-checkout for large repositories:
If you're working with large repositories and want to avoid entire directories:
git sparse-checkout init --cone
git sparse-checkout set dir1 dir2This prevents Git from checking out directories you don't need, reducing the chance of conflicts with system-generated files.
warning: BOM detected in file, this may cause issues
UTF-8 Byte Order Mark (BOM) detected in file
fatal: Server does not support --shallow-exclude
Server does not support --shallow-exclude
warning: filtering out blobs larger than limit
Git partial clone filtering large blobs warning
fatal: Server does not support --shallow-since
Server does not support --shallow-since in Git
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server