I’ve performed some behavior testing on assume-unchanged and skip-worktree flags and here are the findings:

Operation

File with assume-unchanged flag

File with skip-worktree flag

Comments

# File is changed both in local# repository and upstreamgit pull

Git wouldn’t overwrite local file. Instead it would output conflicts and advices how to resolve them.

Git wouldn’t overwrite local file. Instead it would output conflicts and advices how to resolve them.

Git preserves local changes anyway. Thus you wouldn’t accidently lose any data that you marked with any of the flags.

# File is changed both in local# repository and upstream,# trying to pull anywaygit stashgit pull

Discards all local changes without any possibility to restore them. The effect is like ‘git reset --hard’. ‘git pull’ call will succeed.

Stash wouldn’t work on skip-worktree files. ‘git pull’ will fail with the same error as above. Developer is forced to manually reset skip-worktree flag to be able to stash and complete the failing pull.

Using skip-worktree results in some extra manual work but at least you wouldn’t lose any data if you had any local changes.

# No local changes,# upstream file changedgit pull

Content is updated, flag is lost. ‘git ls-files -v’ would show that flag is modified to H (from h).

Content is updated, flag is preserved. ‘git ls-files -v' would show the same S flag as before the pull.

Both flags wouldn’t prevent you from getting upstream changes. Git detects that you broke assume-unchanged promise and choses to reflect the reality by resetting the flag.

# With local file changedgit reset --hard

File content is reverted.Flag is reset to H (from h).

File content is intact.Flag remains the same.

Git doesn’t touch skip-worktree file and reflects reality (the file promised to be unchanged actually was changed) for assume-unchanged file.

I haven’t looked into the performance boost yet.

ANALYSISIt looks like skip-worktree is trying very hard to preserve your local data. But it doesn’t prevent you to get upstream changes if it is safe. Plus git doesn’t reset the flag on pull. But ignoring the ‘reset --hard' command could become a nasty surprise for a developer.Assume-unchanged flag could be lost on the pull operation and the local changes inside such files doesn’t seem to be important to git.

Actually neither of the flags is intuitive enough. Assume-unchanged assumes that a developer shouldn’t change a file. If a file was changed – than that change is not important. This flag is meant for improving performance for not-changing folders like SDKs. But if the promise is broken and a file is actually changed, git reverts the flag to reflect the reality. Probably it’s ok to have some inconsistent flags in generally not-meant-to-be-changed folders. On the other hand skip-worktree is useful when you instruct git not to touch a specific file ever. That is useful for an already tracked config file. Upstream main repository hosts some production-ready config but you would like to change some settings in the config to be able to do some local testing. And you don’t want to accidentally check the changes in such file to affect the production config. In that case skip-worktree makes perfect scene.