This error occurs on macOS when Git tries to modify files that are locked by a Time Machine local snapshot. APFS snapshots create read-only copies of your filesystem, and Git cannot unlink or overwrite files protected by these snapshots. The solution involves deleting old local snapshots or waiting for Time Machine to release them.
The "unable to unlink: Read-only file system (Time Machine snapshot)" error is a macOS-specific issue that occurs when Git attempts to delete or overwrite files that are part of an APFS local snapshot created by Time Machine. When Time Machine creates backups on macOS, it doesn't just back up to your external drive or network location. It also creates **local snapshots** on your Mac's internal drive. These snapshots are read-only copies of your filesystem at a point in time, stored using APFS's efficient snapshot capability. While these snapshots are largely transparent during normal use, they can interfere with certain operations that need to modify files. Git operations like `checkout`, `reset`, `pull`, and `merge` often need to delete existing files before creating new versions. When a file is part of an active local snapshot, the filesystem prevents Git from unlinking (deleting) it because doing so would corrupt the snapshot. The result is this cryptic error message. This error typically occurs after: - A Time Machine backup has recently run or is currently running - Your disk is low on space, causing macOS to retain snapshots longer - You haven't connected your backup drive in a while, causing local snapshots to accumulate - Operations that touch many files that existed when the snapshot was created
First, check if Time Machine is currently running a backup. An in-progress backup may be holding locks on files.
Check backup status from menu bar:
1. Click the Time Machine icon in the menu bar
2. Look for "Backing Up..." or a progress indicator
3. If a backup is running, wait for it to complete
Check via terminal:
# Check if Time Machine backup is in progress
tmutil statusIf a backup is running, you can either:
- Wait for it to complete (recommended)
- Stop the backup (if urgent): tmutil stopbackup
After the backup completes, retry your Git operation - it may work without further action.
View all local snapshots on your Mac to understand what's holding the files:
# List all local snapshots
tmutil listlocalsnapshots /
# You'll see output like:
# com.apple.TimeMachine.2024-01-15-093042.local
# com.apple.TimeMachine.2024-01-15-120000.local
# com.apple.TimeMachine.2024-01-16-093042.localLocal snapshots are named with timestamps. Recent snapshots (within the last few hours or days) are normal. If you have many old snapshots, they may be accumulating because:
- Your backup drive hasn't been connected
- Time Machine is paused
- Disk space issues are affecting cleanup
Note the timestamps - you'll need them if you decide to delete specific snapshots.
Remove old local snapshots to release the file locks. Only delete snapshots you no longer need - they provide rollback capability even without your backup drive.
Delete a specific snapshot:
# Delete a specific snapshot by timestamp
sudo tmutil deletelocalsnapshots 2024-01-15-093042Delete all local snapshots (use with caution):
# Delete all local snapshots from the root volume
sudo tmutil deletelocalsnapshots /Delete snapshots older than a certain date:
# List snapshots and delete old ones manually
tmutil listlocalsnapshots / | while read snapshot; do
# Extract date portion and compare
echo "Snapshot: $snapshot"
doneAfter deleting snapshots, retry your Git operation:
git checkout <branch>
# or whatever command was failingIf deleting snapshots doesn't help or you want a cleaner approach, use the thinlocalsnapshots command to let macOS intelligently remove snapshots:
# Thin local snapshots, reclaiming up to 10GB
# The number is in bytes
sudo tmutil thinlocalsnapshots / 10000000000 4
# The '4' at the end is the urgency level (1-4)
# 4 = most aggressive, deletes more snapshotsThis approach is safer than manually deleting all snapshots because macOS will prioritize removing older or less critical snapshots while potentially keeping recent ones.
You can also thin to a specific amount of free space:
# Free up space until you have 50GB free
# Adjust the byte count as needed
sudo tmutil thinlocalsnapshots / 50000000000 4Connecting your backup drive and completing a backup can help macOS clean up local snapshots:
1. Connect your Time Machine backup drive
2. Start a backup:
- Click Time Machine in the menu bar > "Back Up Now"
- Or via terminal: tmutil startbackup
3. Wait for the backup to complete
When Time Machine successfully backs up to an external drive, it often clears local snapshots that are now redundant. This can release the file locks causing your Git errors.
# Start backup from terminal
tmutil startbackup
# Wait for completion
tmutil status
# When done, retry Git
git pull origin mainIf you use Time Machine over network (NAS, Time Capsule), ensure the network location is accessible.
If the error persists and you need to complete your Git work urgently, temporarily disable Time Machine:
Via System Settings (macOS Ventura+):
1. Open System Settings
2. Go to General > Time Machine
3. Toggle off Time Machine or click "Options" and pause backups
Via System Preferences (older macOS):
1. Open System Preferences > Time Machine
2. Toggle the switch to Off
Via terminal:
# Disable Time Machine
sudo tmutil disable
# Perform your Git operations
git checkout feature-branch
git pull origin main
# Re-enable Time Machine when done
sudo tmutil enableImportant: Remember to re-enable Time Machine after completing your Git operations. Running without backups is risky.
After clearing snapshots, you may need to reset Git's state before retrying:
# Clean up any partial state from the failed operation
git reset --hard HEAD
# Clean untracked files if needed (careful - this deletes untracked files!)
git clean -fd
# Now retry your operation
git checkout main
git pull origin mainIf you were in the middle of a merge or rebase:
# Abort the in-progress operation
git merge --abort
# or
git rebase --abort
# Then retry
git pull origin mainIf the error mentioned specific files, you can try removing them manually first:
# If Git said it couldn't unlink 'src/file.js'
rm -f src/file.js
# Then retry the Git command
git checkout mainLow disk space can prevent macOS from automatically pruning local snapshots. Check your available space:
# Check disk usage
df -h /
# See what's using space
sudo du -sh /* 2>/dev/null | sort -hFree up disk space:
1. Empty the Trash
2. Clear Downloads folder
3. Remove old iOS backups: ~/Library/Application Support/MobileSync/Backup/
4. Clear Xcode derived data: rm -rf ~/Library/Developer/Xcode/DerivedData/*
5. Use "Manage Storage" in System Settings > General > Storage
After freeing space, macOS should automatically prune old local snapshots. You can also trigger this with:
# Encourage macOS to clean up
sudo tmutil thinlocalsnapshots / 1000000000 4Understanding APFS Snapshots and Time Machine:
macOS's APFS (Apple File System) has native support for copy-on-write snapshots. Unlike traditional backups that copy files, APFS snapshots simply mark the current state of the filesystem and preserve any blocks that would be modified afterward. This is extremely space-efficient but creates read-only "frozen" versions of files.
Time Machine leverages this in two ways:
1. Full backups to external/network drives
2. Local snapshots on your internal drive for quick recovery
Local snapshots provide a safety net even when your backup drive isn't connected. You can recover files from "Entering Time Machine" even without the external drive.
Why Git Hits This Issue:
Git operations often need to replace files atomically:
1. Delete the old file (unlink)
2. Write the new content
3. Or rename a temp file over the existing one
When a file is part of an APFS snapshot, the filesystem cannot allow the unlink because it would make the snapshot inconsistent. The file's blocks must remain readable for the snapshot. This is a filesystem-level protection, not a Git bug.
How macOS Normally Handles This:
Normally, APFS handles this transparently through copy-on-write:
1. Old file blocks stay allocated for the snapshot
2. New file gets new blocks
3. Current filesystem sees new file
4. Snapshot sees old file blocks
The error occurs when something prevents this normal operation, often due to:
- File handle conflicts
- Metadata inconsistencies
- Space constraints preventing new block allocation
Preventing Future Occurrences:
1. Regular backups: Connect your backup drive regularly so local snapshots get consolidated
2. Adequate disk space: Keep at least 10-15% of your disk free
3. Exclude build directories: Consider excluding frequently-changing directories from Time Machine:
sudo tmutil addexclusion ~/projects/myrepo/node_modules
sudo tmutil addexclusion ~/projects/myrepo/.git4. SSD health: Degraded SSDs can exhibit strange snapshot behavior
Excluding Git Repositories from Time Machine:
If you frequently hit this issue, consider excluding your entire development directory:
# Exclude a specific directory from Time Machine
sudo tmutil addexclusion ~/Development
# Or exclude just the .git directories
find ~/Development -name ".git" -type d -exec sudo tmutil addexclusion {} \;Caution: Excluding development directories means they won't be backed up by Time Machine. Ensure you have other backup strategies (GitHub, GitLab, etc.) for your code.
Alternative: Use a Separate Volume:
For development work, some users create a separate APFS volume that isn't included in Time Machine backups:
1. Open Disk Utility
2. Select your container/drive
3. Click + to add an APFS Volume
4. Name it "Development" or similar
5. Exclude this volume from Time Machine
This keeps your development work on a snapshot-free volume while maintaining Time Machine backups for everything else.
APFS Snapshot Inspection:
For advanced troubleshooting, you can inspect APFS snapshots directly:
# List all APFS snapshots (not just Time Machine)
diskutil apfs listSnapshots /
# See detailed snapshot information
mount
# Look for entries like: /dev/disk1s1s1 on / (apfs, sealed, local, read-only, journaled)Recovery Options:
If Git corrupts your working directory during these errors, you have options:
1. Re-clone the repository - safest approach
2. Restore from Time Machine - ironic but effective
3. Git reflog - recover commits: git reflog
4. Git fsck - check repository integrity: git fsck --full
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server
fatal: unable to access: Proxy auto-configuration failed
How to fix 'Proxy auto-configuration failed' in Git
fatal: unable to access: Authentication failed (proxy requires basic auth)
How to fix 'Authentication failed (proxy requires basic auth)' in Git
fatal: unable to access: no_proxy configuration not working
How to fix 'no_proxy configuration not working' in Git
fatal: unable to read tree object in treeless clone
How to fix 'unable to read tree object in treeless clone' in Git