使用git --git-dir与--work-tree命令得到令人困惑的结果
为什么Git会显示既删除又未跟踪的矛盾状态?
首先先复现你的操作和对应的输出:
执行的命令:
git init --bare bare git init not-bare pushd not-bare echo something > file git add file git commit -m something git remote add bare ../bare git push bare master rm -rf .git popd git --work-tree=not-bare --git-dir=bare status
得到的输出:
On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: file Untracked files: (use "git add <file>..." to include in what will be committed) file
原因解释:
这个看似矛盾的状态,其实是Git同时对比三个不同层级内容产生的结果,我们一步步拆解:
先明确当前Git的运行环境:你用
--git-dir=bare指定了Git仓库目录是裸仓库bare,用--work-tree=not-bare指定了工作区是not-bare文件夹。bare仓库的master分支里已经有一个包含file的提交(来自之前的push操作);但not-bare文件夹的.git已被删除,现在它只是一个普通文件夹,里面还保留着file。Git状态的核心对比逻辑:
git status会做两次关键对比:- 第一次:暂存区(Index) vs HEAD分支的最新提交
裸仓库默认没有工作区,所以它的暂存区(index文件)是空的——你从来没在这个--work-tree和--git-dir的组合下执行过git add操作。而HEAD指向的提交里存在file,所以Git会认为:暂存区缺少了HEAD中的file,这是一个待提交的删除操作,因此在Changes to be committed下显示deleted: file。 - 第二次:工作区 vs 暂存区
你的工作区not-bare里存在file,但暂存区是空的,没有记录这个文件的存在。所以Git会把工作区里的file识别为未被跟踪的文件,显示在Untracked files里。
- 第一次:暂存区(Index) vs HEAD分支的最新提交
简单来说,就是空的暂存区在中间“起了冲突”:和HEAD比,它缺了file(看起来像要删除);和工作区比,它又没有file(看起来像没跟踪),所以就出现了这种看似矛盾的状态。
你可以验证这个逻辑:在当前环境下执行git add file,再看git status,此时暂存区有了file,和HEAD、工作区都没有差异,状态就会变成“nothing to commit, working tree clean”。
内容的提问来源于stack exchange,提问作者msbit
相关产品推荐
相关产品推荐

