"git submodule absorbgitdirs" 的相反/反向操作是什么?

16
如何对git submodule absorbgitdirs进行反向操作?即将子模块的.git信息从superproject/.git/modules/移动回superproject/path/to//.git目录?
我仍希望 成为 superproject 的子模块,只是不想在 superproject 的 .git/modules 目录中保存 的 .git 目录信息。
2个回答

9
请注意,这将使superproject/path/to/<module>/成为一个嵌套的Git仓库,其SHA1仍将被父项目记录。
为了保持完全相同的状态,您可以复制superproject/.git/modules/<module>并重命名为superproject/path/to/<module>,然后将<module>/<module>重命名为<module>/.git
然后,您可以使用git submodule deinit来删除子模块:
mv asubmodule asubmodule_tmp
git submodule deinit -f -- a/submodule    
rm -rf .git/modules/a/submodule

# if you want to leave it in your working tree
git rm --cached asubmodule
mv asubmodule_tmp asubmodule

我仍然希望成为超级项目的子模块

那么它的.git文件夹将在superproject/.git/modules/<module>中。

子模块absorbgitdirs没有选择:

如果子模块的git目录在子模块内部,则将子模块的git目录移动到其超级项目的$GIT_DIR/modules路径中,然后通过设置core.worktree并添加指向嵌入在超级项目git目录中的git目录的.git文件来连接git目录和其工作目录。

我在git config中没有看到任何可能移动$GIT_DIR/modules的配置。

absorbgitdirs是在Git 2.12(2016年第4季度)提交f6f8586时引入的。
它的测试显示它希望使用GIT_DIR/modules

旧版Git(Git 1.7.8之前,2011年10月)在子模块文件夹内直接使用.git


正如Jeremiah Rose评论中所指出的:

另一个用例是:如果您使用Docker容器在子模块内使用git命令,但容器无法看到超级项目并报错。 :(


2
@genpfault 是的:Git 的旧版本将 .git 直接放在子模块文件夹中。 - VonC
1
@genpfault 我已经更新了答案,以指示子模块.git何时移动到GIT_DIR/modules,以及何时将absorbgitdirs添加到Git中。 - VonC
1
@CharlesBailey:解决一个损坏的脚本,该脚本期望一个“真正”的.git目录,而不是子模块存根.git文件。显然修复脚本是正确的方法。 - genpfault
4
@CBBailey:另一个类似的情况是,当构建脚本查询Git版本标签(例如git describe)时,由于父级gitdir不可用(例如在单独的Docker上下文中构建),它们不可用。 - alecov
2
另一个使用情况是,如果您正在使用Docker容器在子模块内使用git命令,而容器无法看到超级项目并出现错误。 :( - Jeremiah Rose
显示剩余4条评论

8
我写了一个脚本来完成这个任务。将以下内容添加到你的~/.gitconfig文件中:
[alias]
    extract-submodules = "!gitextractsubmodules() { set -e && { if [ 0 -lt \"$#\" ]; then printf \"%s\\n\" \"$@\"; else git ls-files --stage | sed -n \"s/^160000 [a-fA-F0-9]\\+ [0-9]\\+\\s*//p\"; fi; } | { local path && while read -r path; do if [ -f \"${path}/.git\" ]; then local git_dir && git_dir=\"$(git -C \"${path}\" rev-parse --absolute-git-dir)\" && if [ -d \"${git_dir}\" ]; then printf \"%s\t%s\n\" \"${git_dir}\" \"${path}/.git\" && mv --no-target-directory --backup=simple -- \"${git_dir}\" \"${path}/.git\" && git --work-tree=\"${path}\" --git-dir=\"${path}/.git\" config --local --path --unset core.worktree && rm -f -- \"${path}/.git~\" && if 1>&- command -v attrib.exe; then MSYS2_ARG_CONV_EXCL=\"*\" attrib.exe \"+H\" \"/D\" \"${path}/.git\"; fi; fi; fi; done; }; } && gitextractsubmodules"

然后运行:

git extract-submodules [<path>...]

如果您运行时没有指定任何子模块,它将提取所有子模块。
如果您想查看代码的执行情况,只需更改
&& gitextractsubmodules

最后加上

&& type gitextractsubmodules

然后运行该命令,不带参数,使Bash漂亮地打印函数体。

按照您的建议去做以查看代码正在执行的操作,并不会将函数体进行漂亮的打印。相反,它只是告诉您函数的类型:(即 gitextractsubmodules 是一个 shell 函数)。 - Rik
@Rik:有趣,感谢反馈。试试使用declare -f。你在用什么shell? - user541686
我正在Debian上使用终端 - 尽管我也尝试过Terminology。默认的交互式shell是/bin/bash,默认的非交互式是dash。我认为它是通过非交互式运行的,因此是ash,因此bash命令不可用。我尝试了type -f,但出现错误-f未找到,我尝试了typeset -fdeclare -fwhence,所有后面的命令都未找到。似乎没有解决方案,除非使用git bash - Rik
@Rik:在这种情况下,我认为你想做的是将其转换为一个带有#!/bin/bash.sh脚本文件并调用它 - user541686
2
我已将这个单行脚本整理成可读的 POSIX 脚本,并添加了对嵌套子模块的支持。https://gist.github.com/Jamesits/64f9daf3f9467a8aee9a1a5c6e970ea3 - Jamesits
作为对使用此功能的人的警告:如果您有一个包含子模块的子模块,这将破坏这些子模块。您需要进入每个损坏的子模块并取消初始化/初始化这些子模块。 - Roman Alexander

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