Git 之消失的文件
今天来跟大家分享一个有趣的事情,在开始之前,想问问大家如何在 Git 中,如何在 Git 项目中,让一个文件消失?或者说,对 Git 来说不可见?
似乎很简单对不对?用 .gitignore 文件不就可以了。对,你说的没错,只是除了这个方法呢?
演示
接下来如果你如果想尝试这个方法,请别在你的真实项目中操作,搞坏了我可没法负责。
1 | mkdir test_git_repo |
到这里没什么奇怪的对么,好,在 test_git_repo 这个目录里面继续。
1 | mkdir hidden_path |
然后在 hidden_path 中创建一个提交。
1 | echo 1 > 1.txt |
回到上层目录,同样创建一个提交。
1 | cd .. # test_git_repo |
好了,关键的一步来了,把 hidden_path 中的 .git 文件夹删掉。
1 | rm -rf hidden_path/.git |
最终,我们的魔法操作来了:
1 | echo test > hidden_path/test.txt |
当你用 git status
,你会发现这样的输出:
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
test.txt
nothing added to commit but untracked files present (use "git add" to track)
即使进到 hidden_path 去查看 git status
也是一样。奇怪了,hidden_path/test.txt 这个文件哪里去了?
而当你用 ls 查看的时候,却发现那个文件还是存在的,但是它却在当前的 git 项目中「消失」了。你也可以测试看看,无论你往这个文件夹里面写任何文件,它都会「消失」。
好了,接下来,让我们把消失的文件找回来。
1 | git rm --cached hiddle_path |
这时候再来看 git stauts
,你就会发现消失的文件回来了:
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: hiddle_path
new file: hiddle_path/1.txt
new file: hiddle_path/test.txt
原理
相信熟悉 git 的同学已经看出来了,就是因为 git submodule 。
其实这个「小技巧」是我在处理一个不那么熟悉 git 的同事问题时候发现的,当时也是很奇怪,检查了很多次有没有把那个文件夹加入到 .gitignore 里面去,在反复查看好多遍,并且确认整个项目中只有这一个 .gitignore 文件之后,才考虑到是 git submodule 的问题。因为我发现了同事提交了一个空文件夹,大家应该知道,git 是不支持提交空文件夹的,而且查看 git 历史也会发现这个问题。
问了同事才明白,同事不小心把外部依赖拷贝进项目并且提交了,他这样做相当于在主项目 git 中添加了一个 submodule 文件,这个文件在文件系统中会被替换成一个文件夹。本来如果他继续提交的话,我们也会很容易发现这是个 submodule,但是同事接下来的的骚操作就是他直接把 submodule 的 .git 删掉,然后又提交一次,于是结果就是这个 submodule 文件会被当前的主项目 git 给忽略了,因为它的 file mode 依然是 160000,还是会被 git 当作 submodule 处理。1
这里提一下:
file mode 160000 在 git 中的意义是:git 会认为你在记录一个提交,作为另一个项目的目录入口,而不是一个文件夹或者文件。2
因此,删掉 submodule 的 .git 目录后,对应的 commit 永远不会改变,也就相当于这个目录下的所有文件都会被 git 忽略。
Ref
首发于 Github issues: https://github.com/xizhibei/blog/issues/177 ,欢迎 Star 以及 Watch
本文采用 署名-非商业性使用-相同方式共享(BY-NC-SA)进行许可作者:习之北 (@xizhibei)
原链接:https://blog.xizhibei.me/zh-cn/2021/07/11/the-missing-files-in-git/