如何使 git 存储库中的现有目录成为 git 子模块
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36386667/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to make an existing directory within a git repository a git submodule
提问by Doron Behar
I'm very confused about git-submodules.
我对 git-submodules 很困惑。
Basically my problem is that I can't make git understand that ~/main-project/submodule
is a submodule.
基本上我的问题是我无法让 git 理解这~/main-project/submodule
是一个子模块。
I have good experience with git submodules:
in my dotfiles repositoryI created the .gitmodules file in ~/dotfiles-repo
and I added there paths and urls. Since then, If I make changes to the files within the submodules and run git status
, I'd get something like like: .vim/bundle/auto-complete (new commits) # in red
我对 git 子模块有很好的经验:
在我的dotfiles 存储库中,我创建了 .gitmodules 文件,~/dotfiles-repo
并在其中添加了路径和 url。从那时起,如果我对子模块中的文件进行更改并运行git status
,我会得到类似的结果:.vim/bundle/auto-complete (new commits) # in red
I created the .gitmodules
file in ~/main-project
but:
我创建了.gitmodules
文件,~/main-project
但是:
- If I make changes to
~/main-project/submodule
and even push the changes, I don't get a similar response like<submodule> (new commits) # in red
when runninggit status
in~/main-project
. I just get the changes that were made in those directories When I hit the folders' links at
github
for these directories it's not directing me to the repositories themselves but I stay in the same repository.- Maybe I'm missing the whole point. What are the main features of submodules?
- Why does git understands the submodules in the dotfiles repobut not in my other repo?
- Is it because I have already told git to add the files inside
~/main-project/submodule
to the index?
- 如果我更改
~/main-project/submodule
,甚至推的变化,我没有得到这样一个类似的反应<submodule> (new commits) # in red
中运行时git status
在~/main-project
。我只是得到了在这些目录中所做的更改 当我点击
github
这些目录的文件夹链接时,它并没有将我定向到存储库本身,而是留在同一个存储库中。
I've read this questionwhich led me to this answerBut I'm not sure I need git-subtree
. I don't want to do things that might do changes hard to be revert.
我已经阅读了这个问题,这让我得到了这个答案但我不确定我需要git-subtree
. 我不想做那些可能会造成难以恢复的变化的事情。
Edit: This suggested duplicate-solutiondidn't work either, I recieved an error that
Updates were rejected because the remote contains work that you do not have locally
. It seems that @GabLeRouxpractically told me to push<repo-A>
to the url of<repo-B>
.
编辑:这个建议的重复解决方案也不起作用,我收到一个错误,
Updates were rejected because the remote contains work that you do not have locally
. 似乎@GabLeRoux实际上告诉我推<repo-A>
送到<repo-B>
.
采纳答案by Doron Behar
Use git submodule absorbgitdirs
用 git submodule absorbgitdirs
This is what the docsstate this command does:
这是该命令的文档状态:
If a git directory of a submodule is inside the submodule, move the git directory of the submodule into its superprojects
$GIT_DIR/modules
path and then connect the git directory and its working directory by setting thecore.worktree
and adding a .git file pointing to the git directory embedded in the superprojects git directory.
如果子模块的 git 目录在子模块内,则将子模块的 git 目录移动到它的超级项目
$GIT_DIR/modules
路径中,然后通过设置core.worktree
并添加一个指向嵌入在子模块中 的 git 目录的 .git 文件来连接 git 目录和它的工作目录超级项目 git 目录。
So instead of starting all over as suggested in the previous answers by @DomQ and myself, one can just add run the following:
因此,与其像@DomQ 和我自己在之前的答案中所建议的那样从头开始,不如添加运行以下命令:
- Without removing from the index the submodule, Add the submodule's url to
.gitmodules
and to.git/config
withgit submodule add <url> <path>
- Move the submodule's
$GIT_DIR
directory (.git
in regular repositories) to.git/modules/<path>
withgit submodule absorbgitdirs <path>
- 如果没有索引中删除的子模块,子模块的URL加入
.gitmodules
并.git/config
与git submodule add <url> <path>
- 移动子模块的
$GIT_DIR
目录(.git
在常规库),以.git/modules/<path>
与git submodule absorbgitdirs <path>
Original answer - pre v2.12.0
原始答案 - v2.12.0 之前
git submodule absorbgitdirs
was introduced only in v2.12.0-rc0(see commit).
git submodule absorbgitdirs
仅在v2.12.0-rc0中引入(参见提交)。
The Solution is quite simple. It was extracted from here.
解决方案很简单。它是从这里提取的。
git rm submodule-dir
This will delete all the files that git was tracking after insubmodule-dir
rm -rf submoduledir
This will delete all the other files that might have been left insubmodule-dir
because git ignored them.- Now, we have to commit in order to remove the files from the index:
git commit
After the commit, we cleaned the files that git followed and didn't followed insubmodul-dir
. Now it's time to do: git submodule add <remote-path-to-submodule>
This will re-add the submodule but as a true submodule.- At this point it might be a good idea to check
.gitmodules
and see if the submodules have been added successfully. In my case I already had an.gitmodules
file so I had to modify it.
git rm submodule-dir
这将删除 git 跟踪的所有文件submodule-dir
rm -rf submoduledir
这将删除可能submodule-dir
因为 git 忽略它们而留在其中的所有其他文件。- 现在,我们必须提交才能从索引中删除文件:
git commit
提交后,我们清理了 git 跟随的文件,而submodul-dir
. 现在是时候做: git submodule add <remote-path-to-submodule>
这将重新添加子模块,但作为真正的子模块。- 此时,检查
.gitmodules
并查看子模块是否已成功添加可能是个好主意。就我而言,我已经有了一个.gitmodules
文件,所以我不得不修改它。
回答by DomQ
There is basically no better way than pretending to start over:
基本上没有比假装重新开始更好的方法了:
- ensure that everything is committed everywhere
- move your sub-repository out of the way
git submodule add
from the sub-repository's remotecd mysubmodule
git fetch ../wherever/you/stashed/the/sub-repository/in/step-1
git merge FETCH_HEAD
- 确保在任何地方都承诺一切
- 将您的子存储库移开
git submodule add
从子存储库的远程cd mysubmodule
git fetch ../wherever/you/stashed/the/sub-repository/in/step-1
git merge FETCH_HEAD
To explain why this is so, it seems to me than a deeper understanding of what submodules areis needed, than what one can glean from the git-submodule(1)
manual page (or even the relevant chapter from the Git book). I found some more in-depth explanations on this blog post, but since that post is a bit lengthy I am taking the liberty summarize them here.
要解释为什么是这样的话,在我看来比一个更深入的了解什么的子模块都需要的,比一个从搜集git-submodule(1)
手册页(或者甚至是从Git的书相关章节)。我在这篇博文中找到了一些更深入的解释,但由于那篇文章有点长,我冒昧地在这里总结一下。
At a low level, a git submodule consists of the following elements,
在底层,一个 git 子模块由以下元素组成,
- A commit objectat the top of the submodule tree,
- (In recent versions of Git) A subdirectory in
.git/modules
to host the Git objects for the submodule, - An entry in the
.gitmodules
configuration file.
- 一个commit对象的子模块树的顶部,
- (在 Git 的最新版本中)一个子目录,
.git/modules
用于托管子模块的 Git 对象, .gitmodules
配置文件中的一个条目。
The commit object is contained (or more precisely, referenced by SHA1) in the parent tree object. This is unusual, as things usuallyhappen the other way round, but this explains why you see a directory appear in the main repository's git status
after you have performed a commit in the submodule. You can also make some experimentswith git ls-tree
to observe this commit object in more detail.
提交对象包含在父树对象中(或更准确地说,由 SHA1 引用)。这是不寻常的,因为事情通常会反过来发生,但这解释了为什么git status
在子模块中执行提交后,您会看到主存储库中出现一个目录。您还可以进行一些实验以git ls-tree
更详细地观察此提交对象。
The subdirectory in .git/modules
stands in for a .git
subdirectory in the submodule; and in fact, there is a .git
filein the submodule that points to the former using a gitdir:
line. This is the default behavior since version 1.7.8 of Git. Not sure why everything wouldn't Just Work if you just kept on having a separate .git
directory, except as noted in the release notes you would probably run into trouble when switching between a branch that has the submodule and another that doesn't.
in 的子目录.git/modules
代表.git
子模块中的子目录;实际上,子模块中有一个.git
文件使用gitdir:
一行指向前者。这是自 Git 1.7.8 版以来的默认行为。不知道为什么如果你只是继续拥有一个单独的.git
目录,为什么一切都不会正常工作,除非在发行说明中指出,在具有子模块的分支和另一个没有子模块的分支之间切换时可能会遇到问题。
The .gitmodules
file provides the URL that git submodule update --remote
and friends should pull from; which obviously is distinct from the main repository's set of remotes. Note also that .gitmodules
is copied in part into .git/config
by the git submodule sync
command and other commands that invoke it behind the scenes.
该.gitmodules
文件提供了git submodule update --remote
和朋友应该从中提取的 URL ;这显然不同于主存储库的一组遥控器。另请注意,该命令和其他在幕后调用它的命令.gitmodules
将部分复制到其中。.git/config
git submodule sync
While it is fairly easy to do the necessary changes by hand for .gitmodules
+ .git/config
, and also for .git/modules
+ mysubmodule/.git
(and in fact, there is even git submodule absorbgitdirs
for the latter), there isn't really a porcelain to create only the in-tree commit object. Hence the proposed solution by moving + redoing changes presented above.
虽然这是很容易通过手做必要的修改.gitmodules
+ .git/config
,也为.git/modules
+ mysubmodule/.git
(事实上,甚至有git submodule absorbgitdirs
后者),没有一个真正的瓷器创造只有在树commit对象。因此,建议的解决方案是通过移动 + 重做上面提出的更改。
回答by reubenjohn
To answer your questions in order:
要按顺序回答您的问题:
- The purposeof submodules according to GitHub. Feature wise, it has been designed to be conceptualized a child repository (which can almost be treated like any other file), that is version controlled by a parent repository, where the parent tracks the current commit ID of the submodule (child repository) rather than it's content.
- It's most likely because you've already added the files to the index of the repository. In which case, the solution is to
git rm --cached submodule-name/
. Then create an intermediate commit, followed by the adding of the folder as a repository:git add submodule-name
(notice that there is no trailing slashafter submodule-name in the case of submodules). - Yes :)
- 根据 GitHub 的子模块的目的。在功能方面,它被设计为一个子存储库(几乎可以像对待任何其他文件一样对待),即由父存储库控制的版本,其中父存储库跟踪子模块(子存储库)的当前提交 ID,而不是比它的内容。
- 这很可能是因为您已经将文件添加到存储库的索引中。在这种情况下,解决方案是
git rm --cached submodule-name/
。然后创建一个中间提交,然后将文件夹添加为存储库:(git add submodule-name
注意在子模块的情况下 submodule-name后面没有斜杠)。 - 是的 :)
The answeryou mentioned may correct the history of your commits as well:
您提到的答案也可能更正您提交的历史记录:
- Advantages:
- 优点:
That folder will be treated as a submodule in all of your commit history, not just all future commits. This avoids any complications if you checkout to a previous version where it was treated like a folder. This is a complication because when you return to the tip of your branch, you may have to enter your submodule also and checkout to the latest commit to restore all the files (which may be deleted from your working directory). This could be avoided by doing some kind of a recursive checkout to your latest commit.
该文件夹将被视为所有提交历史记录中的子模块,而不仅仅是所有未来提交。如果您检出到以前的版本,在那里它被视为文件夹,这可以避免任何复杂化。这是一个复杂的问题,因为当您返回到分支的顶端时,您可能还必须进入您的子模块并签出到最新提交以恢复所有文件(这些文件可能会从您的工作目录中删除)。这可以通过对最新提交进行某种递归检出来避免。
- Disadvantages:
- 缺点:
If the commit history is modified, all other contributors would also have to re-clone the project since they will get merge conflicts or worse; reintroduce the problem commits back into the project.
如果提交历史被修改,所有其他贡献者也必须重新克隆项目,因为他们会遇到合并冲突或更糟的情况;重新将问题提交回项目。