Git assume-unchanged vs. skip-worktree: How to Safely Ignore Local Config Files

Git tutorial - IT technology blog
Git tutorial - IT technology blog

Quick Start: 3-Minute Fix

It’s 2 AM, and the staging server loses its database connection right after pulling a new build. You urgently need to modify the connection string in config/database.json to bring the system back up. However, you don’t want to accidentally commit these credentials to the repo, nor can you add it to .gitignore since Git is already tracking the file.

The safest and most reliable solution is to use the skip-worktree flag:

# 1. Tell Git to ignore all local changes to database.json
git update-index --skip-worktree config/database.json

# 2. Verify - the file disappears from the modified list
git status

# 3. When you need to track it again (to pull new code or commit changes)
git update-index --no-skip-worktree config/database.json

If you only want to speed up command execution locally and are certain the remote will never modify the file, assume-unchanged is an alternative:

# Ignore checking for file changes
git update-index --assume-unchanged config/database.json

# Resume normal tracking
git update-index --no-assume-unchanged config/database.json

Under the Hood: Don’t Let Appearances Fool You

After running either command, both flags make modified files disappear from git status. The core difference lies in how Git handles conflicts incoming from the remote repository.

1. assume-unchanged: I/O Optimization for Massive Repos

This feature was designed for massive monolithic repositories containing hundreds of thousands of files (such as Chromium or the Linux kernel). Constantly calling stat() on every single file creates severe disk I/O bottlenecks. Enabling this flag is essentially a promise: “I will never modify this file, so Git shouldn’t waste time scanning the disk.”

The risk arises when you actually modify the file:

  • Git skips checking it, so it won’t warn you during commits.
  • When you run git pull and the remote has a commit modifying that exact file, Git will automatically reset the flag or overwrite it, completely wiping out your local tweaks.

2. skip-worktree: A Shield for Local Configs

The --skip-worktree flag is purpose-built for keeping local configuration changes intact. It sends a clear message: “I have modified this file locally, but keep the repository version intact and never push my changes.”

  • When git pull encounters a conflict with the remote, Git proactively halts the process and throws an error instead of silently overwriting your changes.
  • Standard git merge or git rebase operations will not automatically unset this flag.

Quick Comparison

Criteria assume-unchanged skip-worktree
Primary Purpose Reduce disk I/O on large repos Protect local modifications
Behavior during git pull conflicts Flag easily reset and contents overwritten Aborts pull with an error to protect the file
Suitable Files Static SDKs, heavy vendor libraries Config files, credentials, environment settings

Managing Ignored Files

After a few weeks of setting flags, it’s easy to forget which files you’ve hidden. Use the git ls-files -v command to inspect the actual index status of your repository.

Filter Files by Flag

# List files with skip-worktree enabled (uppercase S)
git ls-files -v | grep '^S'

# List files with assume-unchanged enabled (lowercase h)
git ls-files -v | grep '^h'

Meaning of the leading characters:

  • S: File has skip-worktree enabled.
  • h: File has assume-unchanged enabled.
  • H: Normal, fully tracked file.

Time-Saving Aliases

Typing lengthy commands repeatedly wastes time. You should add these three handy aliases to your ~/.gitconfig file:

git config --global alias.ignore-local "update-index --skip-worktree"
git config --global alias.unignore-local "update-index --no-skip-worktree"
git config --global alias.ignored-locals "!git ls-files -v | grep '^S'"

Whenever needed, simply run the shorter commands:

git ignore-local config/database.json
git ignored-locals

3 Crucial Tips for Production Workflows

  1. Always prefer skip-worktree for config files: Never use assume-unchanged for credentials or connection strings. A careless git checkout could wipe out configurations you spent hours setting up.
  2. Unset the flag before updating code: When Git blocks a pull due to conflicts on a skip-worktree file, run git unignore-local <file>, stash your changes, complete the pull, then re-apply your changes and re-enable the flag.
  3. Separating environment variables remains the best long-term practice: Git index flags are only temporary workarounds for debugging or hotfixing. In the long run, your project should maintain a clean separation between a tracked .env.example and a local, gitignored .env file.
Share: