最近,我使用以下命令更新了vim配置存储库中的子模块:
git submodule update --recursive --remote
当我打电话给git status
时,我得到了这个:
On branch master
Your branch is ahead of 'origin/master' by 5 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
(commit or discard the untracked or modified content in submodules)
modified: .vim/pack/starter-pack/start/YouCompleteMe (modified content)
no changes added to commit (use "git add" and/or "git commit -a")
然后我跟随了具有修改内容的子模块链#34;并发现唯一的修改是未经跟踪的子模块提交:
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: vendor/bottle (new commits)
modified: vendor/jedi (new commits)
modified: vendor/waitress (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
这些子模块的主分支(瓶子,绝地,女服务员)都在其远程起源的主分支之后,所以我认为git submodule update
所做的不仅仅是每个仓库的拉动起源,而是找到父仓库的适当版本需要。
为什么即使git使用(new commits)
标记此回购标记,如果它是父模块所需的确切提交?那里发生了什么?
答案 0 :(得分:1)
这里发生的事情是你的超级项目现在不一致了。具体来说,您的超级项目需要提交 gitlinks 。
你应该像往常一样添加新的gitlinks(git add
)并提交(像往常一样)。然后,您可以像往常一样推送新提交。
子模块只是一个Git存储库,由另一个Git存储库直接使用。在这种情况下,子模块本身只是一个普通的Git存储库:它不知道这个其他Git存储库。另一个存储库是我们称之为 superproject 的存储库,它 知道子模块。
.git
目录通常,创建Git存储库的方法是从其他地方克隆它:
git clone http://...
或其他什么。或者,您可以在目录中运行git init
。无论哪种方式,最终都会得到一个.git
目录,其中包含Git存储库本身。在此.git
中,您通常会定义一个名为origin
的远程。这是一个简短的名称(具体来说,名称origin
!),用于记录网址,这是您在上面git clone
提供的网址。该URL甚至可以指向您自己的存储库,例如GitHub。
(如果您从其他人的存储库开始,然后决定在GitHub上创建自己的存储库,您甚至可能有两个存储库。通常您会命名自己的存储库{{1} }和另一个origin
,但就Git本身而言,这些只是任意名称。我们都同意upstream
的唯一原因是这是名称origin
创建的对我们来说,当我们第一次运行git clone
时。)
无论如何,git clone url
目录中的数据包括以下内容:
.git
。超级项目需要了解每个子模块的几个方面。首先,超级项目有一个名为origin
的文件。在此.gitmodules
文件中,您将找到每个子模块的 URL 。您还可以找到每个子模块的路径。
the gitmodules documentation中描述了此文件的确切形式和内容。引用它,假设它说:
.gitmodules
这意味着当您克隆超级项目,然后运行[submodule "libfoo"]
path = include/foo
url = git://foo.com/git/lib.git
时,您的Git将知道它应该运行git submodule init
- url 部分 - 克隆进入git clone git://foo.com/git/lib.git
目录:路径部分。
这个谜题中缺少一个关键部分。在你的Git将另一个Git克隆到include/foo
后,在子模块中检出哪些提交?
在大多数普通存储库中,这不是一个大问题。检查了什么提交?我不知道,我只是跑include/foo
,对吧?这让我得到分支git checkout master
上的最新提交,这就是我想要的。
超级项目和子模块不会以这种方式工作。当我使用我的超级项目的子模块时,我在子模块中围绕一个特定的提交构建我的超级项目代码。例如,我可能会专门依赖其他人的master
库,因此我会进入子项目并运行v3.4.1
以查看特定的标记。
理想情况下,我可能有我的超级项目记录标记(这会很好,而gitlinks 应该允许这样做,但目前他们不会这样做。) 1 但是Git中的标签实际上只是一个特定提交的人类可读名称。标记git checkout v3.4.1
可能是提交v3.4.1
或其他类似的名称。那个 - 丑陋的哈希ID - 实际上是进入gitlink的。
gitlink本身存储在每次提交中,就像常规文件存储在每次提交中一样。如果我在超级项目中使用新的或修改过的feeddadac0ffee...
文件进行新提交,则新版本的README
将进入Git存储库,新提交将引用新的README
。之后的每次提交都会继续引用新的README
。
同样适用于gitlink:如果我的README
引用了子模块的include/foo
的哈希ID,则此处的每个提交都有一个gitlink条目,其中包含:&#34;当您检查此提交,您还应该进入v3.4.1
子模块并检查哈希ID include/foo
&#34;。
1 如果有人想尝试添加它,我认为有一种方法可以做到这一点,甚至可能有点向后兼容:像往常一样存储原始哈希ID,然后是NUL byte,后跟引用名称。不了解新类型gitlink的旧Git可以直接使用哈希ID,而较新的Git可以检测并使用该名称。无论如何,在从SHA-1到Git未来使用的哈希过渡中,Gitlink条目都需要进行类似的更改,所以这可能是添加它的好时机。
所以,我用feeddadac0ffee...
测试了我的超级项目,一切正常。大!但是现在负责这个v3.4.1
库的人已经更新了他们的代码并发布了版本include/foo
。这个新版本有一些新功能,我想使用它。
作为超级项目的所有者,我现在应该进入我的子模块v3.4.2
然后git fetch
。 (这可能不是git checkout v3.4.2
,也许是哈希ID feeddadac0ffee
。)然后我应该回到我的超级项目,进行使用新子模块所需的任何更改,测试一切,并提交。
当我进行新提交以使用子模块的deadcabbadcab005e...
时,我不仅应该提交我的更改。我还需要更新我的 gitlink 。由于我已经完成v3.4.2
- 或git checkout deadcabbadcab005e
,这是完全相同的事情,实际上在子模块中,我所要做的就是在我的超级项目中git checkout v3.4.2
。这会将更新的gitlink添加到我的索引中,这样当我运行git add include/foo
时,我会记录 new gitlink以及其他更改。
这会产生一个新的提交,我现在可以推送我的提交,如果有其他地方我也保留我的超级项目(在GitHub或其他)。