将Git管理的子目录转换为子模块

13

我们以前在Rails应用程序的vendor/plugins/delayed_job目录下使用本地延迟作业hack。它被安装为一次性事件并检入主应用程序存储库的git中。

现在,我们决定在github上fork delayed_job,并用git子模块替换子目录,如此处所述:

http://doblock.com/articles/using-git-submodules-to-manage-plugins-in-rails

在执行这个操作之前,我只是简单地删除了vendor/plugins/delayed_job,没有将其检入。现在,尽管添加了子模块,在主存储库中运行git status仍然会显示vendor/plugins/delayed_job中的新文件。
当一个作为存储库一部分的子目录被删除并且成为一个git子模块时,我们应该如何处理这种情况?我们应该先使用git rm进行删除,还是更彻底地消除它,然后再克隆一个子模块到它的位置?
2个回答

17

假设您不关心工作树中vendor/plugins/delayed_job的当前内容(即将作为子模块检出的内容已经是适当替换工作树中内容的),将目录转换为子模块的常规过程如下:

git rm -r vendor/plugins/delayed_job
git submodule add github.com:account/delayed_job.git vendor/plugins/delayed_job

当然,GitHub存储库的URL可能会有所不同;例如,您可能想使用HTTP URL而不是上面的SSH URL。

但是,似乎您做了一些不同的事情。据我所知,您做了类似于这样的事情:

rm -rf vendor/plugins/delayed_job
git clone github.com:account/delayed_job.git vendor/plugins/delayed_job

这个过程有两个缺陷:

  1. 简单使用rm命令会使旧文件留在Git索引中。
  2. 直接克隆会给你一个“子仓库”,而不是官方的子模块。

假设你在vendor/plugins/delayed_job中没有故意暂存的更改(因为你正用子模块替换它),你可以使用以下命令来清理现场:

git rm --cached -r vendor/plugins/delayed_job
git submodule add github.com:account/delayed_job.git vendor/plugins/delayed_job

清除索引中所有vendor/plugins/delayed_job的条目应该可以解决你的“仍然显示新文件”的问题。使用git submodule add将创建.gitmodules文件,这将将“子存储库”转换为真正的子模块。


1
Chris,感谢你的简要说明!我们执行了第一个rm -fr命令,但是第二个命令是:git submodule add ... 这是你展示的最后一个命令。我猜它与git clone的不同之处只在于它创建.gitmodules文件,是吗?所以我们可能应该按照你的建议继续操作... - Alexy
1
@Alexy:是的,git submodule add会创建.gitmodules文件。您应该在git status的“要提交的更改”部分中看到它列出。但我仍然对您提到的“vendor/plugins/delayed_job”目录下的“新文件”感到困惑。索引不可能在特定目录下同时有子模块和普通文件;一旦子模块放置在那个目录下,您的git status就不应该显示任何“新文件”了(尽管可能会有“删除”的文件,因为索引必须清理该目录下的文件)。 - Chris Johnsen
我们没有执行 git rm 命令,即使在刚添加子模块后,仍然看到新文件被报告...基本上是在子模块中显示新文件,即使存在 .gitmodules 文件。也许我们应该像你建议的那样回滚并先执行 rm 命令? - Alexy
1
@Alexy:我猜你可以执行 git rm --cached -r vendor/plugins/delayed_job/ 命令来清理子模块目录下的普通文件条目。如果省略尾随斜杠,则可能需要运行 git add vendor/plugins/delayed_job(此处不能使用尾随斜杠!) 来重新添加子模块的 "gitlink" 条目。如果你已经有了一个克隆的子仓库并且在 .gitmodules 中有相应的条目,那么你不需要再次使用 git submodule add 命令。 - Chris Johnsen
@Alexy:然而,我仍然不明白你是如何在一个路径下拥有一个子模块(“gitlink”条目)和该路径下的文件。这在技术上是可能的,但这是一个错误的状态;如果它可以在最近版本的Git中重现,那么这就是一个bug。 - Chris Johnsen

4

我坚决不建议这样做。由于git无法处理目录类型变为子模块,你会遇到很多问题。最好的方法是删除旧文件夹,再以不同的名称创建一个新的。

我们有一个被许多人(50+)使用的仓库,并决定将一个文件夹作为子模块。为了不必更改某些构建脚本等内容,我们进行了以上更改。但这使得git混乱不堪,因此每个旧分支(子模块更改之前的)在切换之前都需要删除文件夹并进行其他繁琐操作,合并旧分支非常困难,最糟糕的是我们的自动构建系统宕机了,而且无法像单个用户那样手动解决问题。

所以,不要这样做。Git绝对不能优雅地处理它。


你是否按照这里概述的步骤进行操作:https://dev59.com/tGcs5IYBdhLWcg3w3Hun#12515629? - Mr_and_Mrs_D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接