Git 提交到公共子模块(主分支)
我有两个或多个项目(我们称之为 ProjectFoo 和 ProjectBar),其中有一些通用代码,我将它们放入子模块< /强>。
我的理解是,如果我从 ProjectFoo 内提交对子模块的更改,它将位于一个独立的头中,只有所有 ProjectFoo 克隆才能看到:
(master) $ cd ProjectFooBarCommoneSubmodule/
(master) $ git commit -am "Common code fix."
(56f21fb0...) $ git push
Everything up-to-date
这可能是因为 master
分支没有改变。我可能可以做类似 git checkout master && 的事情git merge 一切都是最新的 但这看起来很丑陋。可能 git reset --hard master 会做同样的事情,但看起来更丑陋。
如何让项目共享通用代码,并从内部使用它的项目进行更新?换句话说,提交该子模块应该更新使用同一子模块的所有各种存储库(存储库,而不仅仅是克隆)。
---- 编辑 ----
显然我签出的存储库混乱且损坏。它应该从一开始就这样工作(在本例中的 ProjectFoo 上):
(master) $ cd ProjectFooBarCommoneSubmodule/
(master) $ git commit -am "Common code fix."
(master) $ git push
....
fbfdd71..0acce63 master -> master
(master) $ cd ..
(master) $ git add ProjectFooBarCommoneSubmodule
(master) $ git commit -m "Submodule update."
然后从其他项目(例如 ProjectBar)上获取更改:
(master) $ cd ProjectFooBarCommoneSubmodule/
(master) $ git pull
将更新到最新版本通用代码。如果它位于独立的头上,则可能需要 git checkout master
。
I've two or more projects (let's call them ProjectFoo and ProjectBar) having some common code that I put in a submodule.
My understanding is that if I commit changes to a submodule from within ProjectFoo it'll be in a detached head that only all ProjectFoo clones can see:
(master) $ cd ProjectFooBarCommoneSubmodule/
(master) $ git commit -am "Common code fix."
(56f21fb0...) $ git push
Everything up-to-date
That's probably because the master
branch hasn't changed. I could probably do something like git checkout master && git merge Everything up-to-date
but that seem pretty ugly. May be a git reset --hard master
would do the same but it seems even uglier.
How to have a common code shared by project, updated from within those projects using it? In other words, committing to that submodule should update all various repositories (repositories, not just clones) that use this same submodule.
---- EDIT ----
Visibly my checked-out repository was messed up and broken. It should have worked right from the start like that (on ProjectFoo in this example):
(master) $ cd ProjectFooBarCommoneSubmodule/
(master) $ git commit -am "Common code fix."
(master) $ git push
....
fbfdd71..0acce63 master -> master
(master) $ cd ..
(master) $ git add ProjectFooBarCommoneSubmodule
(master) $ git commit -m "Submodule update."
Then to get that change from on other projects, like ProjectBar:
(master) $ cd ProjectFooBarCommoneSubmodule/
(master) $ git pull
Would update to the latest common code. A git checkout master
may be required if it's on a detached head.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
简短的回答:
较长的:
Git 子模块是一种依赖机制,其中主项目(例如 A)在子项目(例如 B)中定义了指定的修订版,该修订版将用于构建项目 A。从 A: 的角度来看,该行为必须是可预测的。依赖关系不能更改,除非有人决定将更改合并到项目 A 中。如果项目 B: 的更改自动导入,则可能会发生各种令人讨厌的事情,其中编译错误可能是最好的错误,因为 A 会立即注意到失败。这就是为什么B:的头部保持分离状态。
B 的状态存储在 A 中(查看 git submodule status ),并且必须在 A 中完成并提交修订更改才能生效。这就是上面示例中发生的情况,A 更改存储在存储库中的修订号,并将版本升级到最新版本。该过程也必须在其他主存储库中重复,因此没有自动“使用主”开关 AFAIK。
顺便提一句。 有关子模块的 Git 书籍章节 和 子模块手册页包含许多有关子模块的有用信息,以及正常用法和典型陷阱。值得一看。
编辑:我会尝试更好地解释这一点,
我冒昧地在 我的 github 帐户上创建示例项目。提交毫无意义并且包含垃圾,但设置应该没问题。请检查一下以遵循。
ProjectFoo 和 ProjectBar 共享公共子模块中的代码。
ProjectFooBarCommoneSubmodule:master 是 6850e4e4c1fac49de398
在 ProjectFoo 中:
-6850e4e4c1fac49de39890703f21486ca04b87a0 common
在 ProjectBar 中:
-6850e4e4c1fac49de39890703f21486ca04b87a0 common
所以两者都指向同样的修订版,对吗?这里的技巧是看到 ProjectFoo 和 ProjectBar 指向修订版 (6850e4e4c1fac49de39890703f21486ca04b87a0) 而不是分支 (master),尽管它们是同一件事。第一个是独立的头,另一个是命名的分支。
如果您想对 ProjectFooBarCommoneSubmodule 进行一些修复,您可以转到例如 ProjectFoo 中的子目录,然后选择分支而不是修订版:
然后向上一个目录,并检查 git 子模块状态。它应该告诉您,您现在不同步。例如
+e24bd2bf45d52171a63b67ac05cd4be0ac965f60 common (heads/master-1-ge24bd2b)
现在您可以执行 git add,设置对此特定提交的引用(ge24bd...),执行提交,之后子模块引用指向此修订版,它也恰好是 ProjectFooBarCommoneSubmodule 上的 master。
现在您还需要更新 ProjectBar 中的引用。转到 ProjectBar/common,然后执行 git fetch origin (这是快速合并),
这样做,与任何 git 存储库一样,您不需要在分离的头上工作。您可以在 master 上工作,也可以创建一个命名分支。无论哪种方式,请确保上游包含 ProjectFooBarCommoneSubmodule 更改,否则如果 ProjectFoo 和 ProjectBar 引用不存在的内容,您将破坏它们。希望这能更好地解释它
Short answer:
The longer one:
Git submodules are a dependency mechanism, where the main project (say A) defines a specified revision in a subproject (say B), which will be used in building project A. In order for the tool to be useful the behavior has to be predictable from A:s point of view. Dependencies cannot change, unless somebody decides to incorporate the change to project A. All kinds of nasty things could happen, were project B:s changes automatically imported, of which compile errors are probably the best ones, as A would notice the failures immediately. This is why B:s head is kept in detached state.
The state of B is store in A (check out
git submodule status
), and a revision change has to be done and committed in A, in order for it to have any effect. This is what happens in the example above, A changes the revision number stored in the repo, and bumps up the version to the latest one. The process will have to be repeated in the other main repo as well, so no automatic "use master" switch AFAIK.BTW. The Git book chapter on submodules and the submodule man page contain lots of useful info about submodules, as normal usage and typical pitfalls as well. Worth checking out.
EDIT: I'll try to explain this better
I took the liberty to create example projects on my github account. The commits are meaningless and contain junk, but the setup should be fine. Please check it out to follow.
Both ProjectFoo and ProjectBar share the code in the common submodule.
ProjectFooBarCommoneSubmodule:master is 6850e4e4c1fac49de398
In ProjectFoo:
-6850e4e4c1fac49de39890703f21486ca04b87a0 common
In ProjectBar:
-6850e4e4c1fac49de39890703f21486ca04b87a0 common
So both point to the same revision, right? The trick here is to see, that ProjectFoo and ProjectBar point to the revision (6850e4e4c1fac49de39890703f21486ca04b87a0) not the branch (master), although they are the same thing. The first one is a detached head, and the other a named branch.
If you want to do some fixing on ProjectFooBarCommoneSubmodule, you can go to the subdir in e.g. ProjectFoo, and choose the branch instead of the revision:
Then go one directory up, and check git submodule status. It should tell you, that you are now out of sync. E.g
+e24bd2bf45d52171a63b67ac05cd4be0ac965f60 common (heads/master-1-ge24bd2b)
Now you can do a git add, to set the reference to this particular commit(ge24bd...), do a commit, and after this the submodule reference points to this revision, which also happens to be master on ProjectFooBarCommoneSubmodule.
Now you need to update the reference in ProjectBar as well. Go to ProjectBar/common, and do git fetch origin (this is a fast forward merge), do
So, as with any git repository, you don't need to work on a detached head. You can either work on master, or create a named branch. Either way, make sure that upstream contains the ProjectFooBarCommoneSubmodule changes, or you will break both ProjectFoo and ProjectBar, if they reference something that doesn't exist. Hope this explained it better
在
子模块
上:git push origin HEAD:master
On the
submodule
:git push origin HEAD:master
我只是这样做:
git submodule foreach git push -u origin master
I just do:
git submodule foreach git push -u origin master
注意:
如果子模块之一不包含任何提交,则会失败。
为了解决这个问题,你必须强制命令结果为 0。
通过使用 echo 管道,你可以强制整个命令返回 0 并继续在其他子模块上执行 commit 命令
Notice:
will fail if one of the submodules containt no commit to do.
To get rid of this, you have to force the command result to 0.
By using the echo piped you force the whole command to return with 0 and continue executing the commit command on the other submodules
如果您想一次提交并推送所有子模块,请执行以下操作:
If you want to commit and push all submodules at once do:
要将分离的 HEAD 中的更改合并到 master 中,请运行:
然后 checkout master (使用
-f
强制):如果您有多个子模块需要处理,请使用:
git submodule foreach,例如
To merge changed from detached HEAD into master, run:
then checkout master (use
-f
for force):If you've got multiple submodules to deal with, use:
git submodule foreach
, e.g.如果没有子模块的推送权限和/或只想将子模块内容提交到父存储库:
If one don't have push rights to the submodule and/or just wants to commit submodule contents to the parent repository: