如何无声地“ git pull”辅助子模块,以使其不再需要提交?

问题描述

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

这种情况很少发生,但是有时候当我对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

我并不在乎子模块发生了什么,但是如果它们正在更新,那可能是一件好事。我只希望他们静地执行此操作,这样我就不必再次承诺要对此进行解释。有没有办法做到这一点?

编辑:即使我将此更改提交到原始哈希,在一台计算机上提交一个原始提交哈希也会导致其他计算机在git pull之后将这些提交哈希“修改”到其先前版本。

例如,vim-airline-themes已于昨天修改。我不确定发生了什么,但是在执行git commit之后,vim-airline-themes主题显示为已修改。好,我再做一次提交。这就是改变了

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存储库中执行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的文件。该文件进入每个提交,并存储新的superproject克隆所需的信息,以便运行每个子模块自己的git clone

  • 第二个,以及需要进行新提交的原因,每个 commit 存储一个数据对,其中包括:

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

超级项目Git使用这些哈希ID来知道每个子模块中的git checkout。子模块存储库由其超级项目 控制,由超级项目Git执行以下操作:

(cd $path && git checkout $hash)

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

各个子模块都已更新的事实并不是这里的触发器。您(大概)想使用子模块中的最新提交的事实是触发因素:您需要在超级项目中记录这个事实。为此,需要在超级项目Git中进行新的提交。


编辑:,如下面的注释中所述,要准确地确定您要从哪个子模块存储库中确定哪些提交会变得非常棘手。我个人不喜欢git pull,但是它确实具有在此处有用的功能:您可以让它递归地进入每个子模块并在每个子模块中运行另一个git pull。不过那是一把多刃的剑,因为您可能本身就不需要 pull

您可以在超级项目中运行的git submodule命令也具有多种操作模式:git submodule update --remote让您的超级项目在每个子模块中运行git fetch,后跟{每个子模块中的{1}}。将其与不带git checkout的{​​{1}}进行比较,后者将在每个子模块中运行git submodule update,然后在每个子模块中运行--remote。这提出了一个显而易见的(但很好的)问题:鉴于我们刚刚说过两者都做同样的事情,区别到底是什么?答案在于git fetch使用的哈希ID 。没有git checkout的用户使用 superproject 要求的哈希ID。带有git checkout的用户使用在相关子模块中带有某些远程跟踪名称的哈希ID,该哈希ID由该子模块中运行的--remote更新。

涉及到如此众多的存储库-超级项目一个,超级项目一个远程,每个子模块一个,每个子模块一个远程,所有这些都在这里使用-令人困惑。另外,每个子模块可以是其一个或多个子模块的超项目,并且每个操作都可以递归进行,也可以不进行递归操作,这是一个噩梦。

这种事情是子模块有时被称为“ sob-modules”的挥之不去的原因之一。子模块的许多最痛苦的方面是……好吧,我现在不会说 fixed ,但要比十年前减轻。但是由于分散,Git在本质上已经很棘手,子模块只会使这种情况变得更糟。

没有所有方法可以解决所有问题:这确实是一个难题,您只需要在其中添加很多头骨汗水即可。如果您的各个子模块的作者协调他们的工作,那将会有所帮助。