You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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同时对比三个不同层级内容产生的结果,我们一步步拆解:

  1. 先明确当前Git的运行环境:你用--git-dir=bare指定了Git仓库目录是裸仓库bare,用--work-tree=not-bare指定了工作区是not-bare文件夹。bare仓库的master分支里已经有一个包含file的提交(来自之前的push操作);但not-bare文件夹的.git已被删除,现在它只是一个普通文件夹,里面还保留着file。

  2. 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里。

简单来说,就是空的暂存区在中间“起了冲突”:和HEAD比,它缺了file(看起来像要删除);和工作区比,它又没有file(看起来像没跟踪),所以就出现了这种看似矛盾的状态。

你可以验证这个逻辑:在当前环境下执行git add file,再看git status,此时暂存区有了file,和HEAD、工作区都没有差异,状态就会变成“nothing to commit, working tree clean”。


内容的提问来源于stack exchange,提问作者msbit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:39:34