如何以静默方式"git pull"次要子模块,使其不需要任何提交



我对子模块和git还很陌生,但我一直在使用它们将我所有的tmux和vim插件包括在github上我自己的dotfiles存储库中。

这种情况并不经常发生,但有时当我拉取我的点文件存储库时,我的许多子模块文件都发生了变化。例如,在我最近的git fetch中,我得到了这样的东西(删除了几个插件更新以使其更短):

remote: Enumerating objects: 32, done.
remote: Counting objects: 100% (32/32), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 21 (delta 11), reused 20 (delta 10), pack-reused 0
Unpacking objects: 100% (21/21), 2.65 KiB | 14.00 KiB/s, done.
From https://github.com/someone/dotfiles
fb997fe..2bffa27  master     -> origin/master
Fetching submodule tmux/plugins/tmux-yank
From https://github.com/tmux-plugins/tmux-yank
d776f4e..1b1a436  master     -> origin/master
Fetching submodule vim/bundle/ultisnips
From https://github.com/SirVer/ultisnips
7941f98..d3b36cd  master     -> origin/master
Fetching submodule vim/bundle/vimtex
From https://github.com/lervag/vimtex
9b53bb31..49eab5d5  master     -> origin/master
* [new tag]           v1.4       -> v1.4

合并期间:

herophant:~/.dotfiles$ git merge
Updating fb997fe..2bffa27
Fast-forward
.gitmodules                   |  9 +++++++++
bashrc                        |  6 ++++++
tmux/plugins/tmux-yank        |  2 +-
vim/UltiSnips/tex.snippets    |  8 ++++++++
vim/bundle/rainbow            |  1 +
vim/bundle/syntastic          |  1 +
vim/bundle/ultisnips          |  2 +-
vim/bundle/vim-airline        |  2 +-
vim/bundle/vim-airline-themes |  2 +-
vim/bundle/vim-fugitive       |  2 +-
vim/bundle/vim-racket         |  1 +
vim/bundle/vimtex             |  2 +-
vim/ftplugin/tex.vim          |  1 +
vimrc                         | 20 ++++++++++++++++++--
14 files changed, 51 insertions(+), 8 deletions(-)
create mode 160000 vim/bundle/rainbow
create mode 160000 vim/bundle/syntastic
create mode 160000 vim/bundle/vim-racket
create mode 100644 vim/ftplugin/tex.vim

现在我的git状态(缩写)显示:

## master...origin/master
M .gitmodules
M tmux/plugins/tmux-yank
M vim/bundle/ultisnips
M vim/bundle/vim-airline
M vim/bundle/vim-airline-themes
M vim/bundle/vim-fugitive
M vim/bundle/vimtex

我真的不在乎子模块发生了什么,但如果它们正在更新,那可能是一件好事。我只想让他们默默地做这件事,这样我就不必再为此做出承诺了。有办法做到这一点吗?

编辑:即使我将此更改提交到原始哈希,在一台机器上提交一个原始提交哈希也会导致其他机器";修改";那些在CCD_ 2之后将散列提交到它们以前的版本。

例如,vim航空公司的主题昨天被修改了。我不确定发生了什么,但在做了git commit之后,vim航空公司的主题显示为已修改。好的,我再做一次承诺。这就是的变化

me@main-machine:~/.dotfiles$ git diff 4577802~ 4577802
diff --git a/vim/bundle/vim-airline-themes b/vim/bundle/vim-airline-themes
index e1b0d9f..7f53ebc 160000
--- a/vim/bundle/vim-airline-themes
+++ b/vim/bundle/vim-airline-themes
@@ -1 +1 @@
-Subproject commit e1b0d9f86cf89e84b15c459683fd72730e51a054
+Subproject commit 7f53ebc8f7af2fd7e6a0a31106b99491e01cd18f

我承诺,做更多的git pull只是为了确定,并且";没有新的改变";。我转到另一台机器,从我的dotfiles repo中执行git pull,并看到/vim/bundle/vim-airline-themes子模块已被修改。发生了什么变化?

me@other-machine:~/.dotfiles$ git diff vim/bundle/vim-airline-themes
diff --git a/vim/bundle/vim-airline-themes b/vim/bundle/vim-airline-themes
index 7f53ebc..e1b0d9f 160000
--- a/vim/bundle/vim-airline-themes
+++ b/vim/bundle/vim-airline-themes
@@ -1 +1 @@
-Subproject commit 7f53ebc8f7af2fd7e6a0a31106b99491e01cd18f
+Subproject commit e1b0d9f86cf89e84b15c459683fd72730e51a054

Git似乎出于某种原因想要撤销自己的更改?这一切似乎都是多余的,我相信这是可以通过某种方式防止的。解决方案是什么?

简短的答案是否定的。更具体地说:

我只想让他们安静地这样做,这样我就不必再为此做出另一次承诺。

您真的必须进行新的提交!子模块是另一个Git存储库,因此,它由两部分实现:

  • 首先(在很多方面都不那么重要),您将在超级项目的工作树的顶层中有一个名为.gitmodules的文件。该文件进入每个提交,并存储新的超级项目克隆运行每个子模块的git clone所需的信息。

  • 第二,也是您需要进行新提交的原因,每个提交都存储一个数据对,包括:

    • 子模块的路径,以及
    • 要在子模块中使用的原始提交哈希ID

超级项目Git使用这些哈希ID来知道在每个子模块中git checkout要做什么。子模块存储库由其超级项目控制,由超级项目Git执行:

(cd $path && git checkout $hash)

以在指定的提交时获得子模块中分离的HEAD。$path$hash来自超级项目提交。

每个不同的子模块都得到了更新,这并不是这里的触发因素。事实上,您(大概)希望在子模块中使用最新的提交是触发因素:您需要将此事实记录在您的超级项目中。要做到这一点,需要在超级项目Git中进行新的提交。


编辑:正如下面的评论中所指出的,要确定您想要从哪个子模块存储库中进行哪些提交可能会变得非常棘手。我个人不喜欢git pull,但它确实有一个功能在这里很有用:你可以让它递归地进入每个子模块,并在每个子模块中运行另一个git pull。不过,这是一把多刃剑,因为你可能不想要本身的拉动

您可以在超级项目中运行的git submodule命令也有许多操作模式:git submodule update --remote让您的超级项目在每个子模块中运行git fetch,然后在每个子模块中运行一个git checkout。将其与没有--remotegit submodule update进行比较,后者将在每个子模块中运行一个git pull0,然后在每个子模块中运行git checkout。这带来了一个明显(但很好)的问题:鉴于我们刚刚说过两者都做同样的事情,确切地说,区别是什么?答案在于git checkout使用哪个散列ID。没有--remote的项目使用超级项目要求的哈希ID。具有--remote的子模块使用哈希ID,该哈希ID与所讨论的子模块中的某个远程跟踪名称一起使用,并由该子模块中运行的git fetch更新。

涉及到这么多存储库——有一个用于超级项目,一个用于远程超级项目,每个子模块一个,每个子模块一个远程存储库,所有这些都在这里使用——这让人感到困惑。此外,每个子模块都可以是一个或多个子模块的超级项目,每个操作都可以是递归的,也可以不是递归的,这简直是一场噩梦。

这种事情是子模块有时被称为"模块"的挥之不去的原因之一;sob模块";。子模块的许多最痛苦的方面是。。。好吧,我不会说现在已经修复了,但比十年前更痛苦了。但是Git由于是分布式的,本质上已经很棘手了,而子模块只会让情况变得更糟。

所有这些都没有单一的治疗方法:这真的是一个难题,你只需要付出大量的汗水。如果你的各个子模块的作者协调他们的工作,这会有所帮助。

最新更新