Git – “skip-worktree”与 Pull 的问题
使用 Git “skip-worktree” 选项可能会导致 Git Pull 出现问题。
1. 问题
如果您有一个像 web.config 这样的配置文件,它需要被 Git 跟踪,但您希望忽略本地的更改,这种情况无法通过 .gitignore 解决。我们将展示实现此目标的替代方法。
有关在 Git 中忽略文件的更多方法,请参阅 [1]。
skip-worktree
选项是一个不太为人所知的 Git 选项。此方法旨在应用于您希望跟踪、忽略本地更改的文件。这是 .gitignore 方法的推荐替代方案。
但是,问题在于,skip-worktree
选项仍然需要 Git 对情况进行仔细管理。如果在其他地方修改了原始文件,尝试执行 Git Pull
可能会导致错误,并拒绝 Pull。需要仔细的手动管理/解决情况。
2. 从命令行使用 skip-worktree
以下是您需要的命令
忽略已跟踪文件的本地更改
git update-index --skip-worktree [<file>...]
重新跟踪本地更改
git update-index --no-skip-worktree [<file>...]
列出所有标记为 skip-worktree
的文件
git ls-files -v | grep ^S
3. “skip-worktree” 选项的问题情况
让我们解释一下问题情况是如何生成的。假设我们有两个用户,每个用户都有自己的仓库。让我们关注一个文件 config.txt。最初,所有仓库的文件版本都相同。
然后,User1
在他的系统上决定修改 config.txt,但不想提交更改,因此他使用 skip-worktree
选项对其进行标记。
然后,User2
在他的系统上作为其正常工作的一部分修改了 config.txt。
然后,User2
提交了他的工作并将更改推送到远程仓库。
现在,当 User1
想要从远程仓库 Pull
时,我们就遇到了问题。
问题在于 Pull
被拒绝并出现错误。文件 config.txt 无法修改。更糟糕的是,我们现在有两个版本的 config.txt 文件,版本 A1
和 A2
。
Pull
生成的错误将类似于
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. 理解问题
问题在于,“本地仓库 1”上的 config.txt 版本为 A1,该文件已被修改并通过 skip-worktree
标志进行保护。Git 无法触及该文件。User1
希望拥有 config.txt 的本地版本 A1
,但现在全局版本已更改为 A2
。
如果用户仅解除 skip-worktree
标志(git update-index --no-skip-worktree config.txt),文件 config.txt Ver A1
将仅显示为“本地仓库 1”中的 UNSTAGED
和 UNCOMMITTED
。
User1
现在肯定需要合并版本 A1
和 A2
,问题在于他是否希望将他的版本 A1
的更改提交到“远程仓库”。
5. 问题解决
5.1. 变体 1:提交本地更改
如果 User1
决定他实际上想将他的更改 ver A1
提交到“远程仓库”,他将解除 skip-worktree
标志。由于文件 config.txt ver A1
未提交,Git Pull 仍然无法工作。User1
决定将文件 config.txt 提交到“本地仓库 1”。User1
再次执行 Pull
,然后自动或手动将 config.txt 合并到版本 A12
。然后,他将文件 A12 提交到“本地仓库 1”。然后 Push
到“远程仓库”。
现在“远程仓库”拥有版本 A12
,而 User1
在“本地仓库 1”中也拥有版本 A12
。
User1
的步骤是
- 在“本地仓库 1”中解除 config.txt ver
A1
的skip-worktree
标志
(git update-index --no-skip-worktree config.txt) - 将文件 config.txt ver
A1
提交到“本地仓库 1” - 拉取 (Pull)
- 解决文件合并(得到文件 config.txt ver
A12
) - 将文件 config.txt ver
A12
Push
到“远程仓库”
5.2. 变体 2:Stash 本地更改
如果 User1
决定他不想将他的更改提交到“远程仓库”,他将解除 skip-worktree
标志。由于文件 config.txt ver A1
未提交,Git Pull 仍然无法工作。User1
决定 stash 文件 config.txt。User1
再次执行 Pull
并将文件 config.txt ver A2
提取到“本地仓库 1”。然后 User1
将文件从 stash 应用到“本地仓库 1”。Git 将执行自动或手动合并。User1
手动将新文件合并到版本 A12
。然后,User1
将 skip-worktree
标志应用于文件 A12。
现在“远程仓库”拥有版本 A2
,而 User1
在“本地仓库 1”中拥有版本 A12
。
User1
的步骤是
- 在“本地仓库 1”中解除 config.txt ver
A1
的skip-worktree
标志
(git update-index --no-skip-worktree config.txt) - Stash 文件 config.txt ver
A1
- 拉取 (Pull)
- 将 stash 应用到“本地仓库 1”
- 解决文件合并(得到文件 config.txt ver
A12
) - 在“本地仓库 1”中为 config.txt ver
A12
设置skip-worktree
标志
(git update-index --skip-worktree config.txt)
6. 结论
Git 选项 skip-worktree
是处理诸如 web.config 等配置文件需要本地修改的情况的推荐方法。但是,有时情况会变得相当复杂,就像上面的问题一样,当同一个文件在其他地方被修改,然后 Git Pull 就无法工作时。
Git 没有什么是一帆风顺的。我使用流行的 Git GUI SourceTree,但即便如此,如果没有对您所做的事情有很好的理解,工具本身也无法解决问题。
7. 参考文献
- [1] https://codeproject.org.cn/Articles/5363864/Git-4-Ways-to-Ignore-Files
- [2] https://codeproject.org.cn/Articles/5363987/Git-SourceTree-Custom-Actions-for-skip-worktree-Op
- [3] https://stackoverflow.com/questions/35690736/handling-changes-to-files-with-skip-worktree-from-another-branch
8. 历史
- 2023年7月10日:初始版本