Git
assume-unchanged
skip-worktree
version control
git commands

Git - Difference Between 'assume-unchanged' and 'skip-worktree'

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

assume-unchanged and skip-worktree are two Git index bits that look similar but solve different problems. Both are local-only settings, neither replaces .gitignore, and using the wrong one can make a repository feel inconsistent.

What assume-unchanged Means

assume-unchanged is mainly a performance hint. It tells Git to stop checking a tracked file for working-tree modifications unless Git has another reason to inspect it.

bash
git update-index --assume-unchanged path/to/file

This bit was designed for large repositories on slow filesystems where repeatedly scanning unchanged files was expensive. It does not mean “ignore my edits forever.” If Git must refresh the index, merge changes, or otherwise revisit the file, your local modifications can still become visible.

To clear the bit:

bash
git update-index --no-assume-unchanged path/to/file

What skip-worktree Means

skip-worktree tells Git to avoid updating the working copy of that tracked file and to treat the working-tree version as something the user does not want Git to touch casually.

bash
git update-index --skip-worktree path/to/file

This is more closely associated with local customization of tracked files, such as machine-specific config that exists in the repository but should not be rewritten on every branch switch or merge.

To clear it:

bash
git update-index --no-skip-worktree path/to/file

In practice, skip-worktree is the stronger and more semantically meaningful flag when you are trying to preserve a local variation of a tracked file.

The Important Difference

The shortest useful distinction is:

  • 'assume-unchanged: “Git, please do less checking.”'
  • 'skip-worktree: “Git, please leave my working copy of this tracked file alone.”'

That is why assume-unchanged is a poor tool for local config hacks. It was not designed as an ignore mechanism. If the file changes upstream, Git may still need your attention, and the behavior can be surprising.

By contrast, skip-worktree is what sparse and partial working-copy workflows conceptually align with. It expresses that the working tree version should be treated as intentionally detached from routine index updates.

How to Inspect These Flags

You can list tracked files and inspect their flags with git ls-files -v.

bash
git ls-files -v | grep '^h\|^S'

In this output:

  • lowercase h commonly indicates assume-unchanged
  • uppercase S indicates skip-worktree

That makes it easier to debug a repository where git status is not behaving the way you expect.

What You Should Use Instead Most of the Time

If the real problem is “this file should not be tracked for anyone,” use .gitignore. If the real problem is “we need a template committed, but each developer needs a local version,” the better pattern is usually:

  • commit config.example.json
  • ignore config.json
  • copy the example locally

That approach is more transparent than setting local index bits that other contributors cannot see.

bash
cp config.example.json config.json

Index flags are niche tools. Shared repository conventions should not depend on every contributor remembering to set them manually.

Common Pitfalls

The most common mistake is using assume-unchanged to hide local edits in a config file. That can work temporarily, but it is brittle and confusing during branch changes, rebases, or merges.

Another mistake is forgetting that both flags are local. They are not committed, so teammates do not inherit them. If a workflow depends on them, the workflow is fragile.

Developers also sometimes assume these flags prevent a file from being committed. They do not create a security boundary. If you stage changes explicitly or clear the bits, the file can still be committed.

Finally, if a branch update changes a skip-worktree file, Git may still surface a conflict because the repository state genuinely changed. The bit is not a promise that Git will never care about the file again.

Summary

  • 'assume-unchanged is a performance hint, not a true local-ignore feature.'
  • 'skip-worktree is closer to “keep my local tracked version alone.”'
  • Neither flag replaces .gitignore or a proper config-template workflow.
  • Both settings are local to your repository and are not shared by commits.
  • Use these flags sparingly, and prefer explicit repository conventions when possible.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.