GitWorktree.org logoGitWorktree.org

skip-worktree vs assume-unchanged

Note: These are flags for git update-index, not subcommands of git worktree. Despite the name, --skip-worktree has nothing to do with the git worktree command. Both flags tell Git to ignore local changes to a tracked file, but they serve different purposes.

What Is skip-worktree?

The --skip-worktreeflag tells Git: “I have intentionally modified this tracked file locally, and I want you to ignore my changes.” Git will not show the file as modified in git status, will not stage it with git add, and will not overwrite your local version during a checkout or merge unless there is a conflict.

This flag is designed for files that developers need to modify locally but should never commit — for example, a configuration file with local database credentials or machine-specific paths.

Setting skip-worktree
# Mark a file so Git ignores your local changes
git update-index --skip-worktree config/database.yml

# The file is still tracked, but your local edits are invisible to Git
git status
# nothing to commit, working tree clean

What Is assume-unchanged?

The --assume-unchangedflag tells Git: “This file is unlikely to change, so don’t bother checking it.” It was originally designed as a performance optimization for large repositories where stat-ing every file on disk was slow. Git skips the file during status checks, making git status faster.

Unlike --skip-worktree, Git may still reset the flag automatically during certain operations like git pull or git checkout if the file changes upstream.

Setting assume-unchanged
# Tell Git not to check this file for changes
git update-index --assume-unchanged path/to/large-file.bin

# Git now skips the file during status checks
git status
# nothing to commit, working tree clean

Comparison Table

Aspect--skip-worktree--assume-unchanged
Intended purposeKeep local modifications to a tracked file without committing themPerformance optimization — skip stat calls on files that rarely change
Survives git pull?Yes — Git preserves your local version unless there is an upstream conflictNot guaranteed — Git may unset the flag and overwrite the file
Survives git checkout?Yes, unless the file has upstream changesMay be reset by Git
PrecedenceHigher — if both flags are set, skip-worktree takes priorityLower
Common use caseLocal config files, environment-specific settingsLarge files in a repo that rarely change (SDKs, vendored deps)

How to Set and Unset Each Flag

skip-worktree
# Set the flag
git update-index --skip-worktree <file>

# Unset the flag
git update-index --no-skip-worktree <file>

# List all files with skip-worktree set
git ls-files -v | grep '^S'
assume-unchanged
# Set the flag
git update-index --assume-unchanged <file>

# Unset the flag
git update-index --no-assume-unchanged <file>

# List all files with assume-unchanged set
git ls-files -v | grep '^h'

In the output of git ls-files -v, a lowercase letter in the first column means the flag is set. S indicates skip-worktree, and h (lowercase H) indicates assume-unchanged.

Common Use Cases

Local Config Overrides

A common scenario: your project has a config/settings.yml file checked into the repo with default values. Each developer needs to override certain values locally (database host, API keys, etc.) without those changes showing up in git status.

# Edit the config file with your local values
vim config/settings.yml

# Tell Git to ignore your local changes
git update-index --skip-worktree config/settings.yml

# Now git status is clean, and your local config stays put
git status
# nothing to commit, working tree clean

# If you later want to commit changes to this file:
git update-index --no-skip-worktree config/settings.yml
git add config/settings.yml
git commit -m "Update default settings"

Which Should You Use?

In almost all cases, use --skip-worktree. It was designed for the use case most developers actually have: keeping local modifications to tracked files. The --assume-unchanged flag is a performance hint that Git can override at any time, which makes it unreliable for hiding local changes.

Use --assume-unchanged only if you are dealing with a genuinely large repository and need to speed up git status by skipping stat calls on files you know have not changed.

A better long-term solution for local config overrides is to use a pattern like config.yml (tracked) + config.local.yml (in .gitignore), so you never need index flags at all.

Related Pages