Git diff说子项目是脏的

我刚刚运行了一个git diff,我得到以下输出的所有我的大约10个子模块

diff --git a/.vim/bundle/bufexplorer b/.vim/bundle/bufexplorer
--- a/.vim/bundle/bufexplorer
+++ b/.vim/bundle/bufexplorer
@@ -1 +1 @@
-Subproject commit 8c75e65b647238febd0257658b150f717a136359
+Subproject commit 8c75e65b647238febd0257658b150f717a136359-dirty

这是什么意思?我该怎么解决呢?

144538 次浏览

十年后的2021年1月更新:

"git diff"(< a href = " https://git-scm.com/docs/git-diff " rel = " noreferrer " > < / >)显示了一个子模块工作树,当子模块提交<objectname>-dirty时,它具有未跟踪的cruft,但一个自然的期望是“-dirty"指示器将与&;__abc6 &;(man)对齐,它不认为工作树中有未跟踪的文件是脏文件的来源。
Git 2.31 (Q1 2021)修复了不一致的问题

参见提交8 ef9312 (10 Nov 2020) by Sangeeta Jain (sangu09)
(由Junio C Hamano—gitster提交0806279中合并,25 Jan 2021)

diff:不显示未跟踪文件的子模块为"

署名:Sangeeta Jain

Git diff报告子模块目录为-dirty,即使在子模块目录中只有未跟踪的文件。
这与git describe --dirty(man)在该状态下在子模块目录中运行时所说的内容不一致

当没有配置变量或命令行选项时,将--ignore-submodules=untracked设置为git diff(< a href = " https://git-scm.com/docs/git-diff " rel = " noreferrer " > < / >)的默认值,这样命令就不会为工作树中有未跟踪文件的子模块提供'-dirty'后缀,以使其与子模块工作树中运行的git describe --dirty一致。

并且还将--ignore-submodules=none设置为git status(man)的默认值,这样用户就不会最终删除具有未提交(未跟踪)文件的子模块。

git config现在在它的手册页中包含:

默认设置为untracked,这样任何untracked 子模块被忽略


原答案(2011)

正如Mark Longair的博客文章Git子模块说明中提到的,

git 1.7.0及以上版本在git子模块的行为中包含烦人的变化
现在,如果子模块有任何修改过的文件或未跟踪的文件,那么子模块就会被认为是脏的,而以前只有当子模块中的HEAD指向错误的提交时才会被认为是脏的。

在git子模块的输出中,加号(+)的含义已经发生了变化,当你第一次遇到这个问题时,需要一段时间才能弄清楚哪里出了问题,例如通过查看更改日志或在git上使用git平分。Git找到变化。对用户来说,引入一个不同的符号表示“在指定的版本,但肮脏”会更友好。

你可以通过以下方法修复:

  • 在返回父repo (diff不应该报告“肮脏”)之前,在每个子模块中提交或撤销更改/演进。文件了)。要撤消对子模块的所有更改,只需将cd放入子模块的根目录并执行git checkout . . c

dotnetCarpenter 评论,你可以做一个:git submodule foreach --recursive git checkout .

  • 或将--ignore-submodules添加到你的git diff中,以暂时忽略那些“;脏”;子。

Git 1.7.2新版功能

正如诺姆 下面的评论这个问题提到,从git版本1.7.2开始,你可以忽略脏子模块:

git status --ignore-submodules=dirty

同样,删除子模块,然后运行git submodule initgit submodule update显然也可以达到这个目的,但可能并不总是合适或可能的。

如果启用了文件模式设置,并且您更改了子模块子树中的文件权限,则子模块可能被标记为脏。

要禁用子模块中的文件模式,可以编辑/ . /模块/道路/ /你/子模块/配置并添加

[core]
filemode = false

如果你想忽略所有脏状态,你可以在/ .gitmodules文件中设置ignore = dirty属性,但我认为只禁用文件模式更好。

之所以会出现这种情况,是因为子模块的指针并不是子模块目录中的实际内容。要解决这个问题,你必须再次运行git submodule update:

git submodule foreach --recursive git checkout .

这并没有为我做的技巧,但它给了我一个文件列表(在我的情况下只有一个),在子模块中已更改(没有我做任何事情)。

所以我可以转到子模块,git状态显示我的head被分离-> git checkout master, git状态再次看到修改后的文件,git checkout >filename<, git拉,一切正常。

编辑:这个答案(和大多数其他答案)是过时的;看到Devpool的回答是


最初,没有配置选项使"git diff --ignore-submodules"和"git status --ignore-submodules"为全局默认值(但也请参阅在命令上设置git默认标志)。另一种方法是在你想忽略的每个子模块上设置默认的ignore配置选项(对于git diffgit status),要么在.git/config文件中(仅在本地),要么在.gitmodules文件中(将由git进行版本控制)。例如:

[submodule "foobar"]
url = git@bitbucket.org:foo/bar.git
ignore = untracked

ignore = untracked忽略未跟踪的文件,ignore = dirty也忽略已修改的文件,ignore = all也忽略提交。 显然没有办法为所有子模块通配符

我最终删除了子模块目录,并再次初始化它

cd my-submodule
git push
cd ../
rm -rf my-submodule
git submodule init
git submodule update

在我的例子中,我不确定是什么导致了这种情况的发生,但我知道我只是想让子模块被重置到它们最新的远程提交,然后完成它。这涉及到把这里几个不同问题的答案结合起来:

git submodule update --recursive --remote --init

来源:

我如何恢复我的更改到一个git子模块?< / >

简单的方法拉最新的所有git子模块

要忽略任何子模块中所有未跟踪的文件,使用以下命令忽略这些更改。

git config --global diff.ignoreSubmodules dirty

它将添加以下配置选项到您的本地git配置:

[diff]
ignoreSubmodules = dirty

更多信息可以找到在这里

你对你的回购有足够的权限吗?

我的解决方案与git无关,但是我看到了相同的错误消息,以及子模块的状态。

根本原因是.git文件夹中的一些文件是由root拥有的,因此git没有写访问权,因此git不能改变子模块的状态。

你也有同样的问题吗?

从存储库的根文件夹中,使用find列出根目录下的文件[可选]

find .git -user root

解决方案(Linux)

更改.git文件夹中的所有文件,使其所有者为

sudo chown -R $USER:$USER .git


# alternatively, only the files listed in the above command...
sudo find .git -user root -exec chown $USER:$USER {} +

这是怎么发生的?

在我的例子中,我从docker容器中构建了子模块中的库,docker守护进程传统上以root运行,因此创建的文件属于root:root所有权。

我的用户通过代理通过该服务拥有根权限,所以即使我没有sudo任何东西,我的git存储库仍然有由root拥有的更改。

我希望这能帮到某人,离开这里。

检查子模块的递归性。我的问题是我的子模块错误地指向了他内部的另一个子模块。