如何使 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 04:04:51  来源:igfitidea点击:

How to make an existing directory within a git repository a git submodule

gitversion-controlgit-submodules

提问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/submoduleis a submodule.

基本上我的问题是我无法让 git 理解这~/main-project/submodule是一个子模块。



I have good experience with git submodules:
in my dotfiles repositoryI created the .gitmodules file in ~/dotfiles-repoand 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 .gitmodulesfile in ~/main-projectbut:

我创建了.gitmodules文件,~/main-project但是:

  • If I make changes to ~/main-project/submoduleand even push the changes, I don't get a similar response like <submodule> (new commits) # in redwhen running git statusin ~/main-project. I just get the changes that were made in those directories
  • When I hit the folders' links at githubfor these directories it's not directing me to the repositories themselves but I stay in the same repository.

    1. Maybe I'm missing the whole point. What are the main features of submodules?
    2. Why does git understands the submodules in the dotfiles repobut not in my other repo?
    3. Is it because I have already told git to add the files inside ~/main-project/submoduleto the index?
  • 如果我更改~/main-project/submodule,甚至推的变化,我没有得到这样一个类似的反应<submodule> (new commits) # in red中运行时git status~/main-project我只是得到了在这些目录中所做的更改
  • 当我点击github这些目录的文件夹链接时,它并没有将我定向到存储库本身,而是留在同一个存储库中。

    1. 也许我错过了整点。子模块的主要特点是什么?
    2. 为什么git的理解在子模块的点文件回购,但不是在我的其他回购
    3. 是因为我已经告诉 git 将里面的文件添加~/main-project/submodule到索引中了吗?

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/modulespath and then connect the git directory and its working directory by setting the core.worktreeand 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 和我自己在之前的答案中所建议的那样从头开始,不如添加运行以下命令:

  1. Without removing from the index the submodule, Add the submodule's url to .gitmodulesand to .git/configwith
    git submodule add <url> <path>
  2. Move the submodule's $GIT_DIRdirectory (.gitin regular repositories) to .git/modules/<path>with
    git submodule absorbgitdirs <path>
  1. 如果没有索引中删除的子模块,子模块的URL加入.gitmodules.git/config
    git submodule add <url> <path>
  2. 移动子模块的$GIT_DIR目录(.git在常规库),以.git/modules/<path>
    git submodule absorbgitdirs <path>

Original answer - pre v2.12.0

原始答案 - v2.12.0 之前

git submodule absorbgitdirswas 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.

解决方案很简单。它是从这里提取的。

  1. git rm submodule-dir
    This will delete all the files that git was tracking after in submodule-dir
  2. rm -rf submoduledir
    This will delete all the other files that might have been left in submodule-dirbecause git ignored them.
  3. 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 in submodul-dir. Now it's time to do:
  4. git submodule add <remote-path-to-submodule>
    This will re-add the submodule but as a true submodule.
  5. At this point it might be a good idea to check .gitmodulesand see if the submodules have been added successfully. In my case I already had an .gitmodulesfile so I had to modify it.
  1. git rm submodule-dir
    这将删除 git 跟踪的所有文件 submodule-dir
  2. rm -rf submoduledir
    这将删除可能submodule-dir因为 git 忽略它们而留在其中的所有其他文件。
  3. 现在,我们必须提交才能从索引中删除文件:
    git commit
    提交后,我们清理了 git 跟随的文件,而submodul-dir. 现在是时候做:
  4. git submodule add <remote-path-to-submodule>
    这将重新添加子模块,但作为真正的子模块。
  5. 此时,检查.gitmodules并查看子模块是否已成功添加可能是个好主意。就我而言,我已经有了一个.gitmodules文件,所以我不得不修改它。

回答by DomQ

There is basically no better way than pretending to start over:

基本上没有比假装重新开始更好的方法了

  1. ensure that everything is committed everywhere
  2. move your sub-repository out of the way
  3. git submodule addfrom the sub-repository's remote
  4. cd mysubmodule
  5. git fetch ../wherever/you/stashed/the/sub-repository/in/step-1
  6. git merge FETCH_HEAD
  1. 确保在任何地方都承诺一切
  2. 将您的子存储库移开
  3. git submodule add从子存储库的远程
  4. cd mysubmodule
  5. git fetch ../wherever/you/stashed/the/sub-repository/in/step-1
  6. 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/modulesto host the Git objects for the submodule,
  • An entry in the .gitmodulesconfiguration 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 statusafter you have performed a commit in the submodule. You can also make some experimentswith git ls-treeto observe this commit object in more detail.

提交对象包含在父树对象中(或更准确地说,由 SHA1 引用)。这是不寻常的,因为事情通常会反过来发生,但这解释了为什么git status在子模块中执行提交后,您会看到主存储库中出现一个目录。您还可以进行一些实验git ls-tree更详细地观察此提交对象。

The subdirectory in .git/modulesstands in for a .gitsubdirectory in the submodule; and in fact, there is a .gitfilein 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 .gitdirectory, 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 .gitmodulesfile provides the URL that git submodule update --remoteand friends should pull from; which obviously is distinct from the main repository's set of remotes. Note also that .gitmodulesis copied in part into .git/configby the git submodule synccommand and other commands that invoke it behind the scenes.

.gitmodules文件提供了git submodule update --remote和朋友应该从中提取的 URL ;这显然不同于主存储库的一组遥控器。另请注意,该命令和其他在幕后调用它的命令.gitmodules将部分复制到其中。.git/configgit 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 absorbgitdirsfor 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:

要按顺序回答您的问题:

  1. 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.
  2. 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).
  3. Yes :)
  1. 根据 GitHub 的子模块的目的。在功能方面,它被设计为一个子存储库(几乎可以像对待任何其他文件一样对待),即由父存储库控制的版本,其中父存储库跟踪子模块(子存储库)的当前提交 ID,而不是比它的内容
  2. 这很可能是因为您已经将文件添加到存储库的索引中。在这种情况下,解决方案是git rm --cached submodule-name/。然后创建一个中间提交,然后将文件夹添加为存储库:(git add submodule-name注意在子模块的情况下 submodule-name后面没有斜杠)。
  3. 是的 :)


The answeryou mentioned may correct the history of your commits as well:

您提到的答案也可能更正您提交的历史记录:

  1. Advantages:
  1. 优点

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.

该文件夹将被视为所有提交历史记录中的子模块,而不仅仅是所有未来提交。如果您检出到以前的版本,在那里它被视为文件夹,这可以避免任何复杂化。这是一个复杂的问题,因为当您返回到分支的顶端时,您可能还必须进入您的子模块并签出到最新提交以恢复所有文件(这些文件可能会从您的工作目录中删除)。这可以通过对最新提交进行某种递归检出来避免。

  1. Disadvantages:
  1. 缺点

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.

如果提交历史被修改,所有其他贡献者也必须重新克隆项目,因为他们会遇到合并冲突或更糟的情况;重新将问题提交回项目。