有没有正确的方法在本地修改Git子模块?

时间:2017-08-01 09:29:21

标签: git git-submodules

在下面的示例中,我想证明对Git子模块进行更改并在本地提交它可能会导致一种非常糟糕的情况,我希望找到一个可行的解决方案(除了答案"伙计,不要使用Git子模块它是邪恶的")

示例

我首先创建两个存储库:一个主项目及其子模块:

~ $ for r in main sub; do mkdir $r; cd $r; git init; cd ..; done
Initialized empty Git repository in ~/main/.git/
Initialized empty Git repository in ~/sub/.git/

让我们把一些内容放到子模块中:

~/ $ cd sub
~/sub $ touch sub && git add sub
~/sub $ git commit -m "Added sub"
[master (root-commit) a14ce2f] Added sub
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 sub

然后我们在主项目中导入该子模块:

~/sub $ cd ../main
~/main $ git submodule add ../sub sub
Cloning into '~/main/sub'...
done.
~/main $ git commit -am "Added submodule sub"
[master (root-commit) bd37219] Added submodule sub
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 sub

现在的问题是:我想在本地修改子模块的猴子补丁。

~/main $ cd sub
~/main/sub $ echo "Monkey patched"" >> sub
> echo "Monkey patched"^C>> sub
~/main/sub $ echo "Monkey patched" >> sub
~/main/sub $ git commit -am "Local hotfix"
[master 0b37958] Local hotfix
 1 file changed, 1 insertion(+)
~/main/sub $ ..
~/main $ git commit -am "Hijacked sub-module"
[master 1b3a4af] Hijacked sub-module
 1 file changed, 1 insertion(+), 1 deletion(-)

一切看起来都很漂亮,因为它看起来如此,但邪恶就在那里。

Alice希望在该项目上工作,因此她克隆了主存储库(让我们想象主服务器被Bob推送到集线器的某个地方)

~/main $ ..
~/test $ git clone main alice
Cloning into 'alice'...
done.
~/test $ cd alice
~/alice $ git submodule init
Submodule 'sub' (~/sub) registered for path 'sub'

到目前为止,爱丽丝很高兴直到现在:

~/alice $ git submodule update
Cloning into '~/sub'...
done.
error: Server does not allow request for unadvertised object 0b3795831f31cf8e9c4444a021936c12210e24c6
Fetched in submodule path 'sub', but it did not contain 0b3795831f31cf8e9c4444a021936c12210e24c6. Direct fetching of that commit failed.

如果很明显Git没有跟踪主存储库中的猴子补丁,而是跟踪子模块的本地历史记录。

这对我来说就像是Git子模块的设计失败,或者我只是误解了我今天要求的东西。

主要问题

有没有办法

  • 允许在本地劫持Git子模块,
  • 阻止Git的新用户这样做?

为什么我要在本地修改子模块?

我正在开发嵌入式固件开发,其中每个新项目都包含:

  • 开发框架
  • 与我正在使用的MCU相关的SDK
  • 子模块是我在主板上使用的每个物理组件(蓝牙IC,扩展器,LED驱动程序......)的驱动程序

有时我需要修补物理组件的代码库。例如,我想通过提高无线电功率来扩展蓝牙IC的原生范围(这不是驱动程序通常允许的功能)。

1 个答案:

答案 0 :(得分:2)

修改

我的回答如果有点偏。这里的问题是如何在本地更改内容而不将其发布到子模块的远程存储库中(因为这并不总是可行),但仍然允许其他人使用您的更改。

您必须以某种方式将更改发布给您的队友。因此,更改不能仅保留在子模块中。以下之一将实现这一目标:

  • 分叉有问题的存储库,并将分叉的存储库添加为子模块。这样,您“拥有”回购并可以修改您想要的所有内容,并将更改推送到您自己的分叉远程仓库。
  • 使子模块成为您自己的存储库的一部分:您可以合并“子模块”存储库,使其成为您自己的存储库的一部分(例如,如here所述)。

旧答案

在本地修改子模块完全没问题。你必须记住的一件最重要的事情是:

仅在推送子模块存储库中的更改后才推送主存储库中的子模块更改。

您的示例并未真正涵盖这一点,因为您没有推送到远程服务器。我在这里看一个集中的工作流程,因为这是大多数人根据我的经验所做的事情。

修改子模块,提交并提交主存储库中的子模块更改,但只推送后者时,远程主存储库引用服务器端未知的子模块提交,生成{{1错误。当您首先将子模块更改推送到子模块的存储库,然后主存储库更改时,Alice可以克隆主存储库,初始化并更新子模块并继续进行更改。

在您的示例中

现在您的示例中的问题是您仅在Server does not allow request for unadvertised object中修改了子模块,而在子模块存储库本身(~/main/sub中的子模块)中没有。当Alice从~/sub/克隆时,子模块引用~/main/,其中您更新的提交未知。您必须将更改推送到~/sub/以使提交公共可用,之前您允许任何人在主存储库中获取更新的子模块提交。