【问题标题】:Git diff says subproject is dirtyGit diff 说子项目很脏
【发布时间】:2011-02-02 11:36:50
【问题描述】:

我刚刚运行了一个 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

这是什么意思?我该如何解决?

【问题讨论】:

    标签: git git-submodules


    【解决方案1】:

    2021 年 1 月更新,十年后:

    "git diff"(man) 显示了一个子模块工作树,其中包含未跟踪的 cruft 作为子模块提交 <objectname>-dirty,但一个自然的期望是“-dirty”指示器将对齐使用“git describe --dirty”(man),它不会将工作树中未跟踪的文件视为肮脏的来源。
    Git 2.31(2021 年第一季度)已修复此不一致问题。

    参见Sangeeta Jain (sangu09) 的commit 8ef9312(2020 年 11 月 10 日)。
    (由 Junio C Hamano -- gitster -- 合并到 commit 0806279,2021 年 1 月 25 日)

    diff:不要将带有未跟踪文件的子模块显示为“-dirty”

    签字人:Sangeeta Jain

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

    在没有配置变量或命令行选项时,将--ignore-submodules=untracked设为git diff的默认值(man),这样命令就不会给'-dirty'后缀一个子模块,其工作树具有未跟踪的文件,以使其与在子模块工作树中运行的git describe --dirty 保持一致。

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

    git config 现在包含在其man page 中:

    默认设置为未跟踪,以便任何未跟踪的 子模块被忽略。


    原始答案(2011 年)

    正如 Mark Longair 的博文 Git Submodules Explained 中所述,

    1.7.0 及更高版本的 git 在 git 子模块的行为中包含 annoying change。
    如果子模块有任何修改过的文件或未跟踪的文件,则现在将其视为脏,而以前只有在子模块中的 HEAD 指向错误的提交时才会出现这种情况。

    git submodule 输出中加号 (+) 的含义已更改,您第一次遇到此问题时需要花费一些时间来找出问题所在,例如查看更改日志或在 git.git 上使用 git bisect 来查找更改。为“在指定的版本,但很脏”引入一个不同的符号对用户来说会好得多。

    您可以通过以下方式修复它:

    • 提交或撤消每个子模块中的更改/演变,然后返回父存储库(差异不应再报告“脏”文件)。要撤消对子模块的所有更改,只需 cd 进入子模块的根目录并执行 git checkout .

    dotnetCarpentercomments你可以这样做:git submodule foreach --recursive git checkout .

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

    Git 版本 1.7.2 中的新功能

    正如Noam comments below, this question 提到的,从 git 版本 1.7.2 开始,您可以忽略脏子模块:

    git status --ignore-submodules=dirty
    

    【讨论】:

    • 还有一件好事要知道:您仍然可以执行 git commit -a 而不必担心添加这些更改。尽管它们在前面标有M,但它们不会最终出现在您的提交中。
    • 对我来说,我必须进入每个脏子模块并运行git clean -id。
    • @GDP2 您可以在一行中使用git submodule foreach --recursive git clean -id(首先在备份存储库中进行测试;))
    • 我一直莫名其妙地看到这种情况,发生的事情是我有未跟踪的文件,这些文件不在子模块的.gitignore 中。将它们添加到那里或添加到我的全局忽略列表中修复了问题。
    • 你 10 年更新的答案让我感到困惑。不过,您 10 年前的原始答案仍然有效:git submodule foreach --recursive git checkout .
    【解决方案2】:

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

    git config --global diff.ignoreSubmodules dirty
    

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

    [diff]
      ignoreSubmodules = dirty
    

    更多信息可以找到here

    【讨论】:

    • 政治上最正确的建议可能会说“你为什么不保持你的子模块干净呢?”无论如何,这个解决方案仍然显示修改过的文件吗? form 哪个git版本可以做这个过程?
    【解决方案3】:

    同样删除子模块,然后运行 ​​git submodule init 和 git submodule update 显然可以解决问题,但可能并不总是合适或可能的。

    【讨论】:

    • 当我将一些现有文件夹转换为子模块然后拉到另一台仍然有旧文件夹的机器上时,这对我有用。
    【解决方案4】:

    编辑:这个答案(以及大多数其他答案)已过时;见Devpool's answer instead。


    最初,没有将“git diff --ignore-submodules”和“git status --ignore-submodules”设置为全局默认值的配置选项(另请参阅Setting git default flags on commands)。另一种方法是在.git/config 文件(仅限本地)或.gitmodules(将是由 git 版本化)。例如:

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

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

    【讨论】:

    • As for > Git 2.31 甚至在这个编辑过的帖子中链接的推荐答案似乎已经过时了。无论如何,在接受的答案中有关 git 版本的大多数上下文信息。还是很迷茫怎么办! (我的 ubuntu LTS 中有 Git 2.17)
    • 我检查了在此解决方案中使用 Git 2.17 修改 .gitmodules 的情况,它达到了预期的效果。也许我错了,但我最喜欢这个解决方案,因为 .gitmodules 将由 git 进行版本控制。 (+1)如果像推荐的答案那样做,应该做git config --global diff.ignoreSubmodules untracked而不是git config --global diff.ignoreSubmodules dirty
    【解决方案5】:

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

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

    【讨论】:

    • 我宁愿了解发生了什么,但这也是唯一对我有用的事情......
    • 有时斧头是最好的工具 :) 在推送后使用 'git status' 会感觉更好,看看一切是否干净。 (只是在偏执的日子里,我会把我的子模块移到回收站)
    【解决方案6】:

    之所以如此,是因为您拥有的子模块指针并不是子模块目录中的实际指针。要解决此问题,您必须再次运行 git submodule update:

    【讨论】:

      【解决方案7】:
      git submodule foreach --recursive git checkout .
      

      这对我没有用,但它给了我一个在子模块中更改的文件列表(在我的例子中只有一个)(我没有在那里做任何事情)。

      所以我可以转到子模块,git status 显示我的 HEAD 已分离 -> git checkout master,git status 再次查看修改后的文件,git checkout >filename

      【讨论】:

        【解决方案8】:

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

        要在子模块中禁用文件模式,您可以编辑 /.git/modules/path/to/your/submodule/config 并添加

        [core]
          filemode = false
        

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

        【讨论】:

        • 感谢您提示文件模式更改也会引发这种行为,但文件模式在子模块中通常是不可取的吗?
        【解决方案9】:

        您对您的存储库有足够的权限吗?

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

        根本原因是.git 文件夹中的一些文件归root 所有,所以git 没有写入权限,因此git 无法更改脏 状态以我的用户身份运行时的子模块数。

        你有同样的问题吗?

        在您的存储库的根文件夹中,使用 find 列出 root 拥有的文件 [可选]

        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 所有权。

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

        我希望这对某人有所帮助,请在这里退出。

        【讨论】:

        • 感谢您的分享,希望我应该在遇到这种情况时记住这一点。想知道所有版本的 git 是否都有针对这个用例的非特定错误消息。
        【解决方案10】:

        就我而言,我不确定是什么导致了这种情况发生,但我知道我只是希望将子模块重置为最新的远程提交并完成它。这涉及结合这里几个不同问题的答案:

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

        来源:

        How do I revert my changes to a git submodule?

        Easy way to pull latest of all git submodules

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 2014-10-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多