Using Git “skip-worktree” option is the recommended approach when you want files TRACKED by Git, but want LOCAL CHANGES IGNORED, and is more appropriate than .gitignore. However, if files are modified by other users, Git Pull can be problematic and requires elaborate handling.
1. Problem
If you have a config file like web.config that needs to be TRACKED by Git, but want LOCAL CHANGES IGNORED, that situation cannot be solved with .gitignore. We show alternative ways to achieve that.
For more discussion on methods to ignore files in Git, see [1].
The skip-worktree
option is a less-known Git option. This method is planned to be applied to files that you want TRACKED, LOCAL CHANGES IGNORED. This is the recommended alternative to .gitignore method.
But, the problem is, the option skip-worktree
still requires careful management of the situation in Git. If the original file is modified elsewhere, an attempt to execute Git Pull
can lead to an error and to the Pull being refused. Careful manual management/resolution of the situation is needed.
2. Usage of skip-worktree from the Command Line
Here are the commands you will need for this method:
To ignore local changes to tracked files:
git update-index --skip-worktree [<file>...]
To track local changes again:
git update-index --no-skip-worktree [<file>...]
To list all files marked with skip-worktree
:
git ls-files -v | grep ^S
3. Problematic Situation with Option “skip-worktree”
Let us explain how a problematic situation is generated. Let us assume we have two users, each with its own repository. Let us focus on some file config.txt. Initially, all repos have the same version of the file.
Then, User1
on his system decides to modify the config.txt but does not want changes committed, so it marks it with the option skip-worktree
.
Then, User2
on his system modifies config.txt as a regular part of his work.
Then, User2
commits his work and Pushes changes to the Remote Repo.
Now, we have a problem when User1
wants to Pull
from Remote Repo.
The problem is that Pull
is refused with error. File config.txt cannot be modified. Even worse, we have now two versions of file config.txt, version A1
and A2
.
The error generated by Pull
will be similar to:
error:
Your local changes to the following files would be overwritten by merge:
Folder1/config.txt
Please commit your changes or stash them before you merge.
Aborting
4. Understanding the Problem
The problem is that on “Repo Local 1”, we have config.txt version A1, which is modified and protected by the flag skip-worktree
. Git cannot touch that file. User1
wanted to have the local version A1
of config.txt, but now the global version has changed to A2
.
If the user just releases a flag skip-worktree
(git update-index --no-skip-worktree config.txt), file config.txt Ver A1
will just appear UNSTAGED
and UNCOMMITTED
in “Repo Local 1”.
User1
now definitely needs to merge versions A1
and A2
, just the question is if he wants to commit changes from his version A1
to the “Remote Repo”.
5. Problem Resolution
5.1. Variant 1: Commit local changes
If User1
decides he actually wants to commit his changes ver A1
to “Remote Repo”, he releases the flag skip-worktree
. Since file config.txt ver A1
is not committed, Git Pull will still not work. User1
decides to commit the file config.txt to “Repo Local 1”. User1
does Pull
again, then automatically or manually merges config.txt into version A12
. Then it commits file A12 into “Repo Local 1”. And then does Push
to the “Remote Repo”.
Now “Remote Repo” has version A12
, and User1
also in “Repo Local 1” has version A12
.
Steps for User1
are:
- Release flag
skip-worktree
on config.txt ver A1
in “Repo Local 1”
(git update-index --no-skip-worktree config.txt) - Commit file config.txt ver
A1
to “Repo Local 1” - Pull
- Resolve file merge (resulting in file config.txt ver
A12
) - Push (file config.txt ver
A12
to “Remote Repo”)
5.2. Variant 2: Stash Local Changes
If User1
decides he does not want to commit his changes to “Remote Repo”, he releases the flag skip-worktree
. Since file config.txt ver A1
is not committed, Git Pull will still not work. User1
decides to stash the file config.txt. User1
does Pull
again and gets into “Repo Local 1” file config.txt ver A2
. Then User1
applies file from stash to “Local Repo 1”. Git will do an automatic or manual merge. User1
manually merges the new file into version A12
. Then, User1
applies flag skip-worktree
to file A12.
Now “Remote Repo” has version A2
, and User1
in “Repo Local 1” has version A12
.
Steps for User1
are:
- Release flag
skip-worktree
on config.txt ver A1
in “Repo Local 1”
(git update-index --no-skip-worktree config.txt) - Stash file config.txt ver
A1
- Pull
- Apply stash to “Repo Local 1”
- Resolve file merge (resulting in file config.txt ver
A12
) - Set flag
skip-worktree
on config.txt ver A12
in “Repo Local 1”
(git update-index --skip-worktree config.txt)
6. Conclusion
The Git option skip-worktree
is the recommended way of dealing with situations when you have config files like web.config that you need to locally change. But, sometimes situations can become quite complicated, like in the above problem when the same file gets modified elsewhere and then the Git Pull is not working.
Nothing is easy with Git. I use the popular Git GUI SourceTree, but still, without a good understanding of what are you doing, the tool itself will not solve the problem.
7. References
8. History
- 10th July, 2023: Initial version