在主存储库中的子目录与子模块化分支之间切换
我们已将子目录 S 放入单独的存储库中,并将其作为子模块重新添加到分支 B 中。现在,当我想切换回原始分支 A(该子目录已签入原始存储库中)时,git 会抱怨子模块中的内容未被跟踪,必须首先移走。我们是否可以切换回 A,而无需手动将 S 拖走,然后将其移回 B?
更新:下面的评论表明这可能是旧分支的缺陷,并且 git 不愿意在这里做一些聪明的事情。是这样吗?对主存储库中带有 S 的原始分支进行什么样的变基(如果有)可以让它与子模块化版本共存并可以随时检出?
We've made a subdirectory S into a separate repo and re-added it as a submodule in a branch B. Now when I want to switch back to the original branch A, where the subdirectory was checked into the original repo, git complains that the stuff from the submodule is untracked and has to be moved away first. Can we switch back to A at all without manually dragging the S away and they moving it back in for B?
Update: the comments below indicate it may be a deficiency of the old branch and git not willing to do a smart thing here. Is this so, and what kind of rebasing, if any, of the original branch with S in the main repo can let it coexist and be checkout-able at any time vs. the submodularized version?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的历史记录看起来像这样:
git ls-tree A
显示(例如):git ls-tree A:S
显示(例如):git ls-tree B
显示(例如):(cd S; git ls-tree HEAD)
显示(例如):您想要从提交 Y(或更高版本)移动到提交 X(或更早版本)反之亦然。
如果您的活动分支是 B,那么 git checkout A 会说(例如):
除非您告诉它这样做(例如使用“强制”选项),否则 Git 会非常努力地永远不会丢失数据。 Git 在这里发现并报告的问题是分支 A 的
S/somefile
内容与工作树的内容不同。因为S/somefile
没有被跟踪(从超级项目的角度来看),Git 拒绝替换该文件,从而拒绝切换分支/提交。Git 可以说在这方面更聪明(通过注意到文件在子模块中被跟踪,因此当在超级项目中切换分支时它不应该被认为是未跟踪的),但这是当前实现的限制。有一个针对 Git 的 Google Summer of Code 2011 项目,旨在解决子模块的某些领域支持,但我不清楚这个确切的问题是否会得到解决。
您可以按照您的建议重写您的历史记录,以便
S
始终显示为子模块。这肯定会为未来的提交切换提供最平滑的表面,但由于您需要确保子模块的原始存储库中的提交反映了S
目录的每个历史状态,因此情况变得复杂在原始提交中。如果您有许多不同的S
树(即,在将其转换为子模块之前,您在S
下进行了一些本地更改),那么这可能是一个复杂的过程/脚本。一个更简单的解决方法可能是在切换到将其作为目录的提交之前暂时签出子模块中的“空分支”。
在子模块中创建“空分支”。
您可以在子模块的原始存储库中发布此“分支”,这样其他人就不需要自己重新创建它。
当您需要从
S
是子模块的提交切换到S
是目录的提交时,请首先签出子模块中的“空分支”:您将看到此警告,因为 Git 会留下
S/.git
:由于
S/.git
仍然存在,因此在处理具有S
的提交时,应小心仅在S
外部发出 Git 命令code> 作为目录;在S
下发出的 Git 命令将在S/.git
上运行(在这种状态下,它只是一个“子存储库”,而不是完整的子模块)而不是顶层.git
存储库。当您需要从
S
是目录的提交切换到S
是子模块的提交时,您需要签出相应的分支/提交切换超级项目的提交后在子模块中。您可以使用 git submodule update 来恢复超级项目中记录的提交。或者,如果您正在处理子模块中的分支,只需将其签出即可。
Your history looks something like this:
git ls-tree A
shows (e.g.):git ls-tree A:S
shows (e.g.):git ls-tree B
shows (e.g.):(cd S; git ls-tree HEAD)
shows (e.g.):You want to move from commit Y (or later) to commit X (or earlier) or vice versa.
If your active branch is B, then
git checkout A
says (e.g.):Git tries very hard to never lose data unless you tell it to do so (e.g. with “force” options). The problem Git finds and reports here is that branch A has different content for
S/somefile
then the working tree. BecauseS/somefile
is not tracked (from the perspective of the superproject), Git refuses to replace the file and thus refuses to switch branches/commits.Git could arguably be smarter about this (by noticing that the file is tracked in the submodule, so it should not really be considered untracked when switching branches in the superproject), but it is a limitation of the current implementation. There is a Google Summer of Code 2011 project for Git that aims to address some areas of submodule support, but it is not clear to me whether this exact problem will be covered.
You could, as you suggest, rewrite your history so that
S
always appeared to have been a submodule. This would certainly present the smoothest surface for future commit switches, but it is complicated by the fact that you would need to make sure you have commits in the submodule’s origin repository that reflect each historical state of theS
directory in the original commits. If you have many differentS
trees (i.e. you had made some local changes underS
before converting it to a submodule), then this may be a complicated process/script.A simpler workaround might be to temporarily checkout an “empty branch” in the submodule before switching to a commit that has it as a directory.
Create the “empty branch” in the submodule.
You could publish this “branch” in the submodule’s origin repository so that no one else would need to recreate it form themselves.
When you need to switch from a commit where
S
is a submodule to a commit whereS
is a directory, checkout the “empty branch” in the submodule first:You will see this warning because Git will leave behind
S/.git
:Because
S/.git
is still present, you should be careful to issue Git commands only outsideS
when working on a commit that hasS
as a directory; Git commands issued underS
would operate on theS/.git
(in this state, it is just a “subrepository”, not a full submodule) instead of the top level.git
repository.When you need to switch from a commit where
S
is a directory to a commit whereS
is a submodule, you will need to check out the appropriate branch/commit in the submodule after switching the superproject’s commit.You can use
git submodule update
to restore the commit that is recorded in the superproject. Or, if you were working on a branch in the submodule, just check it back out.