ChatGPT解决这个技术问题 Extra ChatGPT

如何删除子模块?

如何删除 Git 子模块?为什么我不能做git submodule rm module_name

这实际上不是真的。该答案没有解决从 .git/config 中删除子模块条目的问题。接受的答案显示了完全删除 aa 子模块的最新方法。在这个答案中也更简洁地解释了它:stackoverflow.com/a/36593218/1562138
我发现这篇文章对删除子模块很有帮助。它包括有关删除 .gitsubmodules 和 .git/config 文件中的条目的信息link
请节省一些时间,直接找到有效的答案(2017 年):stackoverflow.com/a/36593218/528313
我已经解决了两天的子模块问题。当我发现这个时,突破就来了:forums.developer.apple.com/thread/13102。基本上,Xcode,也许还有其他应用程序,都在努力扩展包含“~”的 url。一旦我将 ssh://username@server.remoteHost.com/~/git/MyRepo.git 更改为 ssh://username@server.remoteHost.com/home/username/git/MyRepo.git (查找实际路径在您的服务器上),所有的怪异现象在十分钟内消失了。另见stackoverflow.com/questions/32833100/…

2
20 revs, 14 users 33%

在现代 git 中(我在 2022 年写这篇文章,安装了更新的 git),这变得相当简单:

运行 git rm ,然后提交。

这将删除 <path-to-submodule> 处的文件树以及 .gitmodules 文件中的子模块条目。 您的存储库中子模块的所有痕迹都将被删除。

但是,作为 the docs note,子模块的 .git 目录被保留在周围(在主项目的 .git 目录的 modules/ 目录中),“可以检查过去的提交而无需从另一个存储库”。
如果您仍然想删除此信息,请手动删除 .git/modules/ 中的子模块目录,并删除文件 .git/config 中的子模块条目。这些步骤可以使用命令自动化

rm -rf .git/modules/,和

git config --remove-section submodule.

较早的社区 wiki 说明:

通过页面Git Submodule Tutorial

要删除子模块,您需要:

从 .gitmodules 文件中删除相关部分。暂存 .gitmodules 更改: git add .gitmodules 从 .git/config 中删除相关部分。从工作树和索引中删除子模块文件: git rm --cached path_to_submodule (没有尾部斜杠)。删除子模块的 .git 目录: rm -rf .git/modules/path_to_submodule 提交更改: git commit -m "Removed submodule " 删除现在未跟踪的子模块文件: rm -rf path_to_submodule

另请参阅alternative steps below


“顺便说一句,我不能简单地 git submodule rm 有什么原因吗?” ?
@abernier 一个简短的答案可能是“因为不存在这样的命令。”我的猜测是,他们正试图明确删除子模块文件与子模块配置,以避免意外的数据丢失。也许有人会认为 git submodule rm 只是删除子模块注册,如果该命令还删除了本地存储库,他们会感到惊讶。任何本地更改都将无法挽回地丢失。也许另一个人会认为只有文件会被删除。
坦白说,我不知道为什么。不过,我希望他们添加一个命令。这4个步骤太复杂了。
这是一个删除子模块的 bash 脚本,只需为 submodule-rm 创建一个 git 别名;)gist.github.com/2491147
还需要 rm -rf .git\modules\submodule 名称吗?
B
Błażej Michalik

git1.8.3 (April 22d, 2013) 起:

一旦您使用“git submodule init”表达您对子模块的兴趣,就没有瓷器方式说“我不再对这个子模块感兴趣”。 “git submodule deinit”是这样做的方法。

删除过程也使用 git rm(自 2013 年 10 月 git1.8.5 起)。

概括

步删除过程将是:

0. mv a/submodule a/submodule_tmp

1. git submodule deinit -f -- a/submodule    
2. rm -rf .git/modules/a/submodule
3. git rm -f a/submodule
# Note: a/submodule (no trailing slash)

# or, if you want to leave it in your working tree and have done step 0
3.   git rm --cached a/submodule
3bis mv a/submodule_tmp a/submodule

解释

rm -rf:这在 Daniel Schroederanswer 中有所提及,并由 the comments 中的 Eonil 总结:

这使 .git/modules// 保持不变。因此,如果您曾经使用此方法删除子模块并再次重新添加它们,则不可能,因为存储库已经损坏。

git rm:见 commit 95c16418

当前在子模块上使用“git rm”会从超级项目的工作树中删除子模块的工作树,并从索引中删除 gitlink。但是 .gitmodules 中的子模块部分保持不变,这是现在删除的子模块的剩余部分,可能会激怒用户(与 .git/config 中的设置相反,这必须提醒用户对该子模块表现出兴趣因此稍后在签出较旧的提交时将重新填充)。

让“git rm”帮助用户,不仅可以从工作树中删除子模块,还可以从 .gitmodules 文件中删除“submodule.”部分并暂存两者。

git submodule deinit:源于this patch

使用“git submodule init”,用户可以告诉 git 他们关心一个或多个子模块,并希望在下一次调用“git submodule update”时填充它。但是目前没有简单的方法可以告诉 git 他们不再关心子模块并想要摆脱本地工作树(除非用户对子模块内部有很多了解并删除“submodule.$name.url” .git/config 以及工作树本身的设置)。

通过提供“deinit”命令来帮助这些用户。这将从 .git/config 中删除给定子模块的整个 submodule. 部分(或者对于所有已初始化的子模块,如果给定了 '.')。如果当前工作树包含修改,则失败,除非强制执行。抱怨在命令行中给出的子模块的 url 设置无法在 .git/config 中找到,但仍然不会失败。

这需要注意(取消)初始化步骤(.git/config.git/modules/xxx

从 git1.8.5 开始,git rm 负责:

'add' 步骤,它在 .gitmodules 文件中记录子模块的 url:它需要为您删除。

子模块特殊条目(如this question所示): git rm 将其从索引中删除: git rm --cached path_to_submodule (没有尾部斜杠)这将删除存储在索引中的具有特殊模式“160000”的目录,标记它作为子模块根目录。

如果您忘记了最后一步,并尝试将子模块添加为常规目录,您将收到如下错误消息:

git add mysubmodule/file.txt 
Path 'mysubmodule/file.txt' is in submodule 'mysubmodule'

注意:从 Git 2.17(2018 年第二季度)开始, git submodule deinit 不再是一个 shell 脚本。它是对 C 函数的调用。

请参阅 Prathamesh Chavan (pratham-pc)commit 2e61273commit 1342476(2018 年 1 月 14 日)。
(由 Junio C Hamano -- gitster --commit ead8dbe 中合并,2018 年 2 月 13 日)

git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
  ${GIT_QUIET:+--quiet} \
  ${prefix:+--prefix "$prefix"} \
  ${force:+--force} \
  ${deinit_all:+--all} "$@"

您能举例说明 submodule deinit 的用法吗?
@yourfriendzak 这里是某人成功使用它的一个例子:stackoverflow.com/a/16161950/6309。但请记住,与我最初认为的相反,1.8.3 尚未发布!在 Unix 上,您可以从源代码编译它。
@HamishDowner 特殊条目应该消失(该目录不再是子模块),并且 .gitmodules 应该没问题,但我仍然会仔细检查 .git 目录的任何内容(即 local config,在您的本地存储库中:未被 git pull 修改)
@Jayen 是的,如果您提交删除 .gitmodules 条目并删除索引中的特殊条目,并推送该存储库,其他人可以拉它并且该子模块将消失。
在当前的 git (v1.9+) 中,普通的旧 git rm submodule 完全按照其他人已经说过的那样做。
f
fvgs

这个问题的大多数答案都是过时的、不完整的或不必要的复杂。

使用 git 1.7.8 或更高版本克隆的子模块将在本地存储库中最多留下四个痕迹。删除这四个痕迹的过程由以下三个命令给出:

# Remove the submodule entry from .git/config
git submodule deinit -f path/to/submodule

# Remove the submodule directory from the superproject's .git/modules directory
rm -rf .git/modules/path/to/submodule

# Remove the entry in .gitmodules and remove the submodule directory located at path/to/submodule
git rm -f path/to/submodule

为什么这个答案的赞成票这么少?所有这些流行的答案都遗漏了一些东西,这是唯一以最简单的方式真正删除子模块所有痕迹的答案。请注意:命令的顺序很重要。
@mbdevpl 在接受答案 3 年后出现,我想没有人能说服 OP 接受这个答案
这是2018年不复杂的答案吗?
运行这些命令的 .gitmodules 文件似乎仍然不受影响
在 2019 年,这行不通。最后一行实际上尝试从 .git/modules 文件夹中删除,您已经在上面的行中删除了该文件夹。像接受的答案一样将 -- 添加到第一行似乎可以使这项工作。
N
Noel Yap

只是一个注释。从 git 1.8.5.2 开始,有两个命令可以:

git rm -r the_submodule
rm -rf .git/modules/the_submodule

正如@Mark Cheverton 的回答正确指出的那样,如果不使用第二行,即使您现在删除了子模块,剩余的 .git/modules/the_submodule 文件夹也会阻止将来添加或替换相同的子模块.此外,正如@VonC 提到的,git rm 将在子模块上完成大部分工作。

--更新 (07/05/2017)--

澄清一下,the_submodule 是项目中子模块的相对路径。例如,如果子模块位于子目录 subdir 内,则为 subdir/my_submodule

正如评论和 other answers 中正确指出的那样,这两个命令(尽管在功能上足以删除子模块)确实在 .git/config[submodule "the_submodule"] 部分留下了痕迹(截至 2017 年 7 月),可以删除使用第三个命令:

git config -f .git/config --remove-section submodule.the_submodule 2> /dev/null

我正在使用 git 版本 2.4.9 (Apple Git-60),我所要做的就是 rm the_submodule。我推了那个然后重新添加了一个与子模块同名的文件夹,它没有问题。
这不会从 .git/config 中删除子模块条目。有关删除子模块的完整方法,请参阅 stackoverflow.com/a/36593218/1562138
@drevicko 我刚刚用 Git 2.11.1 测试了这个,我观察到与以前相同的行为。 git init && git submodule add <repository> && git rm <name> 留下 .git/config 条目和 .git/modules/<name> 目录及其内容。也许您在删除子模块之前没有初始化它?
我觉得先运行这个更安全.. git submodule deinit -f the_submodule
@danday74 如果签出子模块,则实际上需要您的命令。否则你会得到一个错误Unlink of file '...' failed
5
5 revs, 4 users 69%

简单的步骤

删除配置条目: git config -f .git/config --remove-section submodule.$submodulename git config -f .gitmodules --remove-section submodule.$submodulename 从索引中删除目录: git rm --cached $submodulepath 提交删除未使用的文件: rm -rf $submodulepath rm -rf .git/modules/$submodulename

请注意: $submodulepath 不包含前导或尾随斜杠。

背景

当您执行 git submodule add 时,它只会将其添加到 .gitmodules,但一旦您执行 git submodule init,它就会添加到 .git/config

因此,如果您希望删除模块,但能够快速恢复,请执行以下操作:

git rm --cached $submodulepath
git config -f .git/config --remove-section submodule.$submodulepath

如果将其放入脚本中,最好先执行 git rebase HEAD,最后执行 git commit

另请查看 an answer to Can I unpopulate a Git submodule?


我有很多子模块(还有一个更大的混乱),所以我不得不通过一个 for 循环来传递它们。因为它们中的大多数在特定目录下,并且 ls 输出包含尾部斜杠。我做了类似for dir in directory/*; do git rm --cached $dir; done的事情。
为了得到这个可以在脚本中用于递归删除的列表 - git config -f .git/config -l | cut -d'=' -f1 | grep "submodule.$MODPATH" | sed 's/^submodule\.//' | sed 's/\.url$//' - - 看起来你必须真的这样做以防万一出现问题,否则只需 git submodule | grep -v '^+' | cut -d' ' -f3
获取未进行本地更改的模块列表 - git submodule | grep '^+' | cut -d' ' -f2
请注意,我必须在双引号 "submodulename" 中包含 submodulename .. 引用 .git/config 文件
简单的。高效的。在 2.25.0 中,在第 1 步之后,您需要在第 2 步之前暂存 .gitmodules 更改。
G
GAMITG

除了建议之外,我还必须 rm -Rf .git/modules/path/to/submodule 才能添加具有相同名称的新子模块(在我的情况下,我用原来的叉子替换)


我也遇到了麻烦。如果您尝试将子模块重新安装到相同的路径,它会将分支信息缓存在您提到的位置,这会使事情变得混乱。
谢谢,我也需要这个。 @Anton,我同意,并且我已经编辑了最高投票的答案以添加此信息。
我使用 --name 选项使替换工作...参见 stackoverflow.com/questions/14404704/…
U
U. Windl

要删除使用添加的子模块:

REPOSITORY=blah@blah.com:repos/blah.git
MOD_DIR=lib/blah
git submodule add $REPOSITORY $MOD_DIR

跑:

git rm $MOD_DIR

而已。

对于旧版本的 git(大约 ~1.8.5,实际上甚至在 2.26.2 中)使用:

git submodule deinit $MOD_DIR
git rm $MOD_DIR
git config -f .gitmodules --remove-section submodule.$MOD_DIR

确实+1。这是从 git 1.8.3 开始的唯一正确答案。应该被接受为正确的。
git rm 仍然在 .git/modules/ 中留下一些东西。 (2.5.4)
@RudolfAdamkovic 它对我有用吗?请注意,如果确切路径匹配,它只会删除子模块条目;如果您移动了一个子模块然后使用 git rm 它不会;在我的 mac 上使用 2.5.4 进行快速测试会更新 .gitmodules 文件,如此处的文档中所述:git-scm.com/docs/git-rm#_submodules ...但如果您发现某种平台/版本的组合不会发生这种情况,您可能应该提出一个关于它的错误。
这个答案并不完全正确。 git rm 将内容留在 .git/modules/ 目录和 .git/config 文件(ubuntu,git 2.7.4)中。其他答案 100% 有效:stackoverflow.com/a/36593218/4973698
deinit 会删除子模块但保留文件吗?我希望它删除 git 中的所有残余物,但保留实际文件夹。
C
Carmine Paolino

您必须删除 .gitmodules.git/config 中的条目,并从历史记录中删除模块的目录:

git rm --cached path/to/submodule

如果你在 git 的邮件列表上写邮件,可能有人会为你编写一个 shell 脚本。


不需要任何 shell 脚本,其他答案有删除子模块所有痕迹的命令:stackoverflow.com/a/36593218/4973698
C
Charles

您可以使用别名来自动化其他人提供的解决方案:

[alias]
  rms = "!f(){ git rm --cached \"$1\";rm -r \"$1\";git config -f .gitmodules --remove-section \"submodule.$1\";git config -f .git/config --remove-section \"submodule.$1\";git add .gitmodules; }; f"

把它放在你的 git config 中,然后你可以这样做:git rms path/to/submodule


-1 因为这太错误了。第一:这假设子模块的名称和路径是相同的通常情况并非如此。即 git clone https://github.com/hilbix/empty.git; cd empty; git submodule add https://github.com/hilbix/empty.git one; git mv one two; git rms two。第二:您必须从正确的路径执行此操作。 git 别名应该可以在工作树中的任何位置工作(或正常失败)。第三:git config -f .git/config 在子模块中失败,因为 .git 通常是那里的文件。
G
GAMITG

总而言之,这是你应该做的:

设置 path_to_submodule var(没有尾部斜杠): path_to_submodule=path/to/submodule 从 .gitmodules 文件中删除相关行: git config -f .gitmodules --remove-section submodule.$path_to_submodule 从 .git/config 中删除相关部分git config -f .git/config --remove-section submodule.$path_to_submodule 仅从索引中取消暂存和删除 $path_to_submodule(以防止丢失信息) git rm --cached $path_to_submodule 跟踪对 .gitmodules 所做的更改 git add .gitmodules 提交超级项目 git commit -m "Remove submodule submodule_name" 删除现在未跟踪的子模块文件 rm -rf $path_to_submodule rm -rf .git/modules/$path_to_submodule


所以其他所有拉下我更改的人都必须运行 rm -rf $path_to_submodule rm -rf .git/modules/$path_to_submodule 来删除子模块缓存?
我建议更新,git submodule update。如果子模块路径没有正确更新(git 抛出错误),请删除它们:rm -rf .git/modules/<submodule> && rm -rf <submodule> && git submodule update
C
Community

我发现 deinit 对我有用:

git submodule deinit <submodule-name>    
git rm <submodule-name>

git docs

deinit 取消注册给定的子模块,即从 .git/config 中删除整个 submodule.$name 部分及其工作树。


同意找到相同的解决方案。这是2018年今天最好的方式)
它没有删除 .git/modules/.. 。您应该删除它们,请参阅@fvgs 的答案
不知道为什么这个简单易行的解决方案不是第一
AFAICS 对于知道 deinit 的较新的 gits 来说,这似乎是最安全的答案,因为 the other answer 过早地删除了 .git/modules/submodule 目录,这似乎使 git s 时不时地失败。另外(请参阅我的评论)删除 .git/modules/submodule 可能是错误的路径,因此这是一个危险的步骤,最好稍后仅在 git 抱怨时采取(或者如果您 299% 确定这是您想要的,是正确的路径并且真的需要)。
我还需要 git commit 在工作目录 modified .gitmodulesdeleted <submodule-path> 中提交分阶段更改。
G
GAMITG

如果子模块是意外添加的,因为您添加、提交和推送了一个已经是 Git 存储库(包含 .git)的文件夹,那么您将没有要编辑的 .gitmodules 文件或任何东西在 .git/configIn this case all you need 是:

git rm --cached subfolder
git add subfolder
git commit -m "Enter message here"
git push

FWIW,在执行 git add 之前,我还删除了 .git 文件夹。


正是我的情况
B
Black

git submodule deinit 从 .gitmodules 中删除部分 git rm 删除需要从项目中删除的模块文件。将删除的文件添加到git并调用 git add .gitmodules Commit and Push


对我来说,调用 git submodule deinit <submodule_name>git rm <path_to_submodule> 就足够了。最后一个命令会自动删除 .gitmodules 内的条目。吉特 2.17
我需要 -rgit rmgit rm -r <path_to_submodule>
u
udondan

在这个网站上尝试了所有不同的答案后,我最终得到了这个解决方案:

#!/bin/sh
path="$1"
if [ ! -f "$path/.git" ]; then
  echo "$path is no valid git submodule"
  exit 1
fi
git submodule deinit -f $path &&
git rm --cached $path &&
rm -rf .git/modules/$path &&
rm -rf $path &&
git reset HEAD .gitmodules &&
git config -f .gitmodules --remove-section submodule.$path

这将恢复与添加子模块之前完全相同的状态。您可以立即再次添加子模块,这对于这里的大多数答案都是不可能的。

git submodule add $giturl test
aboveScript test

这使您可以进行干净的结帐,而无需提交任何更改。

对此进行了测试:

$ git --version
git version 1.9.3 (Apple Git-50)

为什么使用 git rm --cached $path 然后使用 rm -rf $path 而不是 git rm -r $path
-1 如果您尝试删除子模块中的子模块(子模块可以形成树!),则不起作用。此外,由于缺少引用,这是危险的错误!示例 git submodule add https://github.com/hilbix/empty.git 'dangerous .. submodule' ->当您尝试使用脚本删除“危险的 .. 子模块”时,这将 rm -rf .. 这很可能不是您想要的..
L
Lance Rushing

我目前在 2012 年 12 月所做的事情(结合了这些答案中的大部分):

oldPath="vendor/example"
git config -f .git/config --remove-section "submodule.${oldPath}"
git config -f .gitmodules --remove-section "submodule.${oldPath}"
git rm --cached "${oldPath}"
rm -rf "${oldPath}"              ## remove src (optional)
rm -rf ".git/modules/${oldPath}" ## cleanup gitdir (optional housekeeping)
git add .gitmodules
git commit -m "Removed ${oldPath}"

G
GAMITG

我最近发现了一个 git 项目,其中包含许多有用的 git 相关命令:https://github.com/visionmedia/git-extras

安装它并输入:

git-delete-submodule submodule

然后事情就完成了。子模块目录将从您的存储库中删除,并且仍然存在于您的文件系统中。然后您可以提交更改,例如:git commit -am "Remove the submodule"


您可以将其称为 git delete-submodule,因为 git-extras 需要在工作路径中。另请注意,我建议不要使用 git-extras,因为它的许多部分非常容易出错和危险。 IE git-delete-submodule 可能会删除 .git/modules/* 下的错误路径,因为它假定模块和路径是相同的(通常情况并非如此),如果您尝试删除子模块。 git-extras 可能有 99% 的帮助,但如果使用它完全出错,请不要抱怨。 您已被警告!
为了节省时间,请使用此命令 apt install git-extras && git delete-submodule submodule。 @Chien-Wei Huang 在帖子中有额外的 -
G
GAMITG

这是我所做的:

1.) 从 .gitmodules 文件中删除相关部分。您可以使用以下命令:

git config -f .gitmodules --remove-section "submodule.submodule_name"

2.) 暂存 .gitmodules 更改

git add .gitmodules

3.) 从 .git/config 中删除相关部分。您可以使用以下命令:

git submodule deinit -f "submodule_name"

4.)删除 gitlink (没有尾部斜杠):

git rm --cached path_to_submodule

5.) 清理 .git/modules

rm -rf .git/modules/path_to_submodule

6.) 提交:

git commit -m "Removed submodule <name>"

7.) 删除现在未跟踪的子模块文件

rm -rf path_to_submodule

谢谢你。对我来说,我不得不将前三个步骤的顺序重新排列为 3)、1)、2)。执行 1) 首先在第 3 步给出 fatal: no submodule mapping found in .gitmodules for path 'submodule_name'。但这两个步骤都是必要的。 (git v2.8.2)
T
Tino

为了读者的利益,这里试图对其进行总结,并提供一个分步指南,说明如果事情没有按预期工作时如何做到这一点。以下是 git 版本 2.17 及更高版本删除子模块经过测试且安全的方法

submodule="path/to/sub"              # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"

如果这对您不起作用,请参见下文。

没有选项。没有什么危险的。甚至不考虑做更多!

使用 Debian Buster 2.20.1 和 Ubuntu 18.04 2.17.1 进行测试。

"$submodule" 只是为了强调名称的放置位置,并且您必须小心空格等

如果在 Windows 上忽略第一行并将“$submodule”替换为正确指定子模块路径的 Windows 方式。 (我不是 Windows)

警告!永远不要自己触摸 .git 目录的内部!在 .git 中进行编辑进入了黑暗的一面。不惜一切代价远离!是的,您可以为此责怪 git,因为过去 git 中缺少许多方便的东西。就像再次删除子模块的正确方法一样。我认为 git submodule 的文档中有一个非常危险的部分。它建议您自己删除 $GIT_DIR/modules//。在我的理解中,这不仅是完全错误的,而且是极其危险的,并且会在未来引起重大的头痛!见下文。

注意

git module deinit

是直接倒数

git module init

git submodule deinit -- module
git rm -- module

也完全相反

git submodule add -- URL module
git submodule update --init --recursive -- module

因为有些命令基本上需要做的不仅仅是一件事情:

git submodule deinit -- 模块 (1) 更新 .git/config

(1) 更新 .git/config

git rm (2) 删除模块 (3) 的文件,从而递归删除子模块的子模块 (4) 更新 .gitmodules

(2) 移除模块的文件

(3) 从而递归删除子模块的子模块

(4) 更新.gitmodules

git submodule add 将数据拉入 .git/modules/NAME/ (1) 执行 git submodule init,因此更新 .git/config (2) 执行 git submodule update,因此,非递归地签出模块 (4) 更新 .gitmodules

将数据拉入 .git/modules/NAME/

(1) 执行 git submodule init,所以更新 .git/config

(2) 执行 git submodule 更新,因此,非递归地检出模块

(4) 更新.gitmodules

git submodule update --init --recursive -- 如果需要,模块会提取更多数据 (3) 递归检查子模块的子模块

如果需要,可以提取更多数据

(3)递归地检出子模块的子模块

这不能完全对称,因为保持严格对称没有多大意义。根本不需要两个以上的命令。 “拉入数据”也是隐含的,因为您需要它,但没有删除缓存的信息,因为这根本不需要并且可能会擦除宝贵的数据。

这确实让新手感到困惑,但基本上是一件好事:git 只是做了明显的事情并且做对了,甚至没有尝试做更多。 git 是一种工具,它必须完成可靠的工作,而不仅仅是另一个“Eierlegende Wollmilchsau”(“Eierlegende Wollmilchsau”在我看来是“瑞士军刀的某种邪恶版本”)。

所以我理解人们的抱怨,他们说“为什么不为我做git显而易见的事情”。这是因为这里的“明显”取决于观点。在每一种情况下的可靠性都更为重要。因此,在所有可能的技术情况下,对您来说显而易见的事情往往不是正确的事情。请记住:AFAICS git 遵循技术路径,而不是社交路径。 (因此聪明的名字:git)

如果这失败了

由于以下原因,上述命令可能会失败:

你的 git 太旧了。然后使用更新的 git。 (见下文如何。)

您有未提交的数据,可能会丢失数据。然后最好先提交它们。

您的子模块在 git clean 意义上不干净。然后首先使用该命令清理您的子模块。 (见下文。)

你过去做过一些 git 不支持的事情。然后你就处于黑暗面,事情变得丑陋和复杂。 (也许使用另一台机器修复它。)

也许还有更多我不知道的失败方式(我只是一些 git 高级用户。)

可能的修复如下。

使用较新的 git

如果您的机器太旧,则 git 中没有 submodule deinit。如果您不想(或不能)更新您的 git,那么只需使用另一台具有较新 git 的机器! git 是完全分布式的,因此您可以使用另一个 git 来完成工作:

workhorse:~/path/to/worktree$ git status --porcelain 不能输出任何东西!如果是这样,请先清理东西!

主力:~/path/to/worktree$ ssh account@othermachine

othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK

现在做子模块的东西

其他机器:~/TMPWORK$ git commit 。 -m 。 && 出口

主力:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git

主力:~/path/to/worktree$ git merge --ff-only FETCH_HEAD。如果这不起作用,请使用 git reset --soft FETCH_HEAD

现在清理东西,直到 git status 再次清理。你可以这样做,因为你之前已经把它清理干净了,这要归功于第一步。

这个 othermachine 可以是某个 VM,也可以是 Windows 下的某个 Ubuntu WSL,等等。甚至是 chroot(但我假设您不是 root,因为如果您是 root,则应该更容易更新到较新的 git)。

请注意,如果您无法 ssh 进入,有很多方法可以传输 git 存储库。您可以将工作树复制到某个 U 盘(包括 .git 目录)上,然后从 U 盘克隆。克隆副本,只是为了再次以干净的方式获取内容。这可能是一个 PITA,以防您的子模块无法直接从其他机器访问。但也有一个解决方案:

git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX

您可以使用此乘法,并将其保存到 $HOME/.gitconfig。就像是

git config --add 'url./mnt/usb/repo/.insteadof' https://github.com/

重写 URL,如

https://github.com/XXX/YYY.git

进入

/mnt/usb/repo/XXX/YYY.git

如果您开始习惯这种强大的 git 功能,那就很容易了。

先收拾东西

手动清理很好,因为这样你可能会发现一些你忘记的东西。

如果 git 抱怨未保存的内容,请提交并将其推送到安全的地方。

如果 git 抱怨一些剩菜, git status 和 git clean -ixfd 是你的朋友

尽量避免使用 rm 和 deinit 的选项。如果您是专业人士,则 git 的选项(如 -f)很好。但是当你来到这里时,你可能在子模块领域没有那么有经验。所以最好是安全而不是抱歉。

例子:

$ git status --porcelain
 M two
$ git submodule deinit two
error: the following file has local modifications:
    two
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'two' contains local modifications; use '-f' to discard them
$ cd two
$ git submodule deinit --all
error: the following file has local modifications:
    md5chk
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'md5chk' contains local modifications; use '-f' to discard them
$ cd md5chk
$ git submodule deinit --all
error: the following file has local modifications:
    tino
(use --cached to keep the file, or -f to force removal)
fatal: Submodule work tree 'tino' contains local modifications; use '-f' to discard them
$ cd tino
$ git status --porcelain
?? NEW
$ git clean -i -f -d
Would remove the following item:
  NEW
*** Commands ***
    1: clean                2: filter by pattern    3: select by numbers    4: ask each
    5: quit                 6: help
What now> 1
Removing NEW
$ cd ../../..
$ git status --porcelain
$ git submodule deinit two
Cleared directory 'two'
Submodule 'someunusedname' (https://github.com/hilbix/src.git) unregistered for path 'two'

您看,submodule deinit 上不需要 -f。如果事情是干净的,在 git clean 的意义上。另请注意,不需要 git clean -x这意味着 git submodule deinit 无条件删除被忽略的未跟踪文件。这通常是您想要的,但不要忘记它。有时被忽略的文件可能很宝贵,例如需要数小时到数天才能重新计算的缓存数据。

为什么从不删除 $GIT_DIR/modules//?

可能人们想删除缓存的存储库,因为他们害怕以后遇到问题。这是真的,但遇到那个“问题”是解决它的正确方法!因为修复很容易,并且做得对,你将能够从此过上幸福的生活。这避免了比您自己删除数据时更麻烦的麻烦。

例子:

mkdir tmptest &&
cd tmptest &&
git init &&
git submodule add https://github.com/hilbix/empty.git two &&
git commit -m . &&
git submodule deinit two &&
git rm two &&
git commit -m . &&
git submodule add https://github.com/hilbix/src.git two

最后一行输出以下错误:

A git directory for 'two' is found locally with remote(s):
  origin    https://github.com/hilbix/empty.git
If you want to reuse this local git directory instead of cloning again from
  https://github.com/hilbix/src.git
use the '--force' option. If the local git directory is not the correct repo
or you are unsure what this means choose another name with the '--name' option.

为什么会出现这个错误?因为 .git/modules/two/ 以前是从 https://github.com/hilbix/empty.git 填充的,现在应该从其他东西(即 https://github.com/hilbix/src.git)重新填充。如果您从 https://github.com/hilbix/empty.git 重新填充它,您将看不到它

现在要做什么?好吧,就按照说的做吧!使用--name someunusedname

git submodule add --name someunusedname https://github.com/hilbix/src.git two

.gitmodules 然后看起来像

[submodule "someunusedname"]
    path = two
    url = https://github.com/hilbix/src.git

ls -1p .git/modules/ 给出

someunusedname/
two/

这样将来您可以向前和向后切换分支/提交,并且再也不会遇到任何麻烦,因为 two/ 有两个不同的(并且可能不兼容的)上游存储库。最好的是:您也可以将两者都缓存在本地。

这不仅适用于你。对于使用您的存储库的所有其他人来说也是如此。

你不会失去历史。如果您忘记推送旧子模块的最新版本,您可以输入本地副本,稍后再执行。请注意,有些人忘记推送一些子模块是很常见的(因为这是新手的 PITA,直到他们习惯了 git)。

但是,如果您删除了缓存目录,则两个不同的签出项会相互碰撞,因为您不会使用 --name 选项,对吧?因此,每次您进行结帐时,您可能必须一次又一次地删除 .git/modules/<module>/ 目录。这是非常麻烦的,并且很难使用像 git bisect 这样的东西。

因此,将这个模块目录保留为占位符有一个非常技术性的原因。建议删除 .git/modules/ 以下内容的人要么不了解,要么忘记告诉您,如果遇到这样的子模块不兼容性,这会使 git bisect 等强大功能几乎无法使用。

另一个原因如上所示。查看 ls。你在那里看到什么?

嗯,模块 two/ 的第二个变体不在 .git/modules/two/ 之下,它在 .git/modules/someunusedname/ 之下!所以像 git rm $module; rm -f .git/module/$module 这样的东西是完全错误的!您必须咨询 module/.git.gitmodules 才能找到要删除的正确内容!

因此,不仅大多数其他答案都落入了这个危险的陷阱,even very popular git extensions had this bug (it's now fixed there)!因此,如果您不完全了解您在做什么,最好保留 .git/ 目录!

而从哲学的角度来看,抹杀历史永远是错误的!除了量子力学,像往常一样,但这是完全不同的东西。

仅供参考,您可能已经猜到了:hilbix 是我的 GitHub 帐户。


这个帖子的百科全书应该分成更清晰的部分,带有更大/更清晰的子标题以指示实际答案,以及不同的“疑难解答”/等部分。
同意“永远不要删除 $GIT_DIR/modules//”
M
Mona Jalal

所有的答案看起来都过时了。我正在使用 git 版本 2.28.0。一条线的答案是,

git rm path-to-submodule

但是,即使从源代码管理中删除了子模块, .git/modules/path-to-submodule 仍然包含子模块存储库, .git/config 包含其 URL,因此您仍然必须手动删除它们:

git config --remove-section submodule.path-to-submodule
rm -rf .git/modules/path-to-submodule

有时,您必须使用 -f 标志:

$ git rm -f img2vec

例如,因为您可能会收到如下错误:

$ git rm img2vec/
error: the following file has changes staged in the index:
    img2vec
(use --cached to keep the file, or -f to force removal)

过时了吗? My answer 确实提到了 git rm 选项和相关的配置更改。
既然这是顶级 &最新的答案,您也应该使用以下步骤对其进行更新: 1. 删除 .gitmodules 文件。 2. 通过调用 git rm --cached -r <path-to-submodule-dir> 从索引中删除相关数据
P
Peter Mortensen

我不得不将 John Douthat 的步骤更进一步,cd 进入子模块的目录,然后删除 Git 存储库:

cd submodule
rm -fr .git

然后我可以将文件作为父 Git 存储库的一部分提交,而不需要对子模块的旧引用。


在尝试执行 git rm --cache 步骤时,我也必须这样做才能通过“致命:不是 git 存储库:”错误。
Y
Yuri Pozniak

使用 git v2.7.4 简单的 3 个步骤就可以了。

git submodule deinit -f -- a/submodule    
git rm -f a/submodule
git commit

l
laser

以下是我认为必要或有用的 4 个步骤(首先是重要的):

git rm -f the_submodule
rm -rf .git/modules/the_submodule
git config -f .git/config --remove-section submodule.the_submodule
git commit -m "..."

理论上步骤 1 中的 git rm 应该会处理好它。希望有一天可以肯定地回答 OP 问题的第二部分(这可以在一个命令中完成)。

但截至 2017 年 7 月,第 2 步 是删除 .git/modules/ 中的数据的必要条件,否则,您将来无法重新添加子模块。

正如 tinlyx's answer 所指出的,对于 git 1.8.5+,您可能可以摆脱上述两个步骤,因为所有 git submodule 命令似乎都有效。

步骤 3 删除文件 .git/config 中的 the_submodule 部分。为了完整性,应该这样做。 (该条目可能会导致旧 git 版本出现问题,但我没有要测试的)。

为此,大多数答案建议使用 git submodule deinit。我发现使用 git config -f .git/config --remove-section 更加明确且不那么混乱。根据 git-submodule documentationgit deinit

取消注册给定的子模块...如果您真的想从存储库中删除子模块并提交,请改用 git-rm[1] 。

最后但并非最不重要的一点是,如果您不 git commit,您将/可能在执行 git submodule summary 时出错(从 git 2.7 开始):

fatal: Not a git repository: 'the_submodule/.git'
* the_submodule 73f0d1d...0000000:

这与您执行第 2 步还是第 3 步无关。


G
GAMITG

我刚刚找到了 .submodule (忘记了确切名称)隐藏文件,它有一个列表......你可以这样单独删除它们。我只有一个,所以我删除了它。很简单,但它可能会弄乱 Git,因为我不知道子模块是否附加了任何东西。到目前为止似乎还可以,除了 libetpan 通常的升级问题,但这(希望)是无关的。

注意到没有人发布手动擦除,所以添加


这是.gitmodules
A
Albert Tobac

对于 git 2.17 及更高版本,它只是:

git submodule deinit -f {module_name}
git add {module_name}
git commit

git 2.17.1git 2.20.1 都不起作用。但是,使用 git rm 而不是 git add 对两者都有效。注意:如果东西干净,则不需要 -f。如果您想防止意外的数据丢失,请务必永远不要使用带有 git 的选项。另请注意,这会留下 .git/modules/{module_name}最好将其保留在此处,因为 git 会打印正确的(!) 帮助,如果某事因此而被阻止,则如何继续。
佚名
project dir:     ~/foo_project/
submodule:       ~/foo_project/lib/asubmodule
- - - - - - - - - - - - - - - - - - - - - - - - -
run:
  1.   cd ~/foo_project
  2.   git rm lib/asubmodule && 
          rm .git/modules/lib/asubmodule && 
            git submodule lib/asubmodule deinit --recursive --force

A
Ashish Sondagar

从 git 中删除子模块的最佳方法:

$ git submodule deinit -f <submodule-name>
$ rm -rf .git/modules/<submodule-name>
$ git config -f .gitmodules --remove-section submodule.<submodule-name>
$ git config -f .git/config --remove-section submodule.<submodule-name>
$ git rm --cached <submodule-name>
$ git commit -m 'rm submodule: <submodule-name>'

问题:这不是缺少 git add .gitmodules 吗?
是的,你可以添加这个,git add .gitmodules
b
botbot

如果您刚刚添加了子模块,例如,您只是添加了错误的子模块或将其添加到错误的位置,只需执行 git stash 然后删除该文件夹。这是假设添加子模块是您在最近的回购中所做的唯一事情。


R
Rahul Dapke

总而言之,这是你应该做的:

设置 path_to_submodule var(没有尾部斜杠):

path_to_submodule=path/to/submodule

从 .gitmodules 文件中删除相关行:

git config -f .gitmodules --remove-section submodule.$path_to_submodule

从 .git/config 中删除相关部分

git config -f .git/config --remove-section submodule.$path_to_submodule

仅从索引中取消暂存并删除 $path_to_submodule(以防止丢失信息)

git rm --cached $path_to_submodule

跟踪对 .gitmodules 所做的更改

git add .gitmodules

提交超级项目

git commit -m "Remove submodule submodule_name"

删除现在未跟踪的子模块文件

rm -rf $path_to_submodule

rm -rf .git/modules/$path_to_submodule

另请参阅:Alternative guide lines


您能否通过如何在“git submodule add”之后删除子模块但从未提交过它来扩展它?我假设在这种情况下不需要提交来删除子模块,对吧?
我认为您需要交换 git rm --cached $path_to_submodulegit add .gitmodules 否?我确实收到了第一个命令的错误:fatal: Please stage your changes to .gitmodules or stash them to proceed,因为我对 .gitmodules 进行了未暂存的更改。首先执行 git add .gitmodules 解决了这个问题。
P
Pooja Singh

这对我有用。上面的答案在终端中显示了这一点,没有其他任何事情发生

'fatal: not removing 'demolibapp' recursively without -r'

demolibapp 是我要删除的子模块名称 git submodule deinit demolibapp git rm --cached demolibapp -r rm -rf .git/modules/demolibapp git add --all git commit -m "removing extra submodules" git push rm -rf demolibapp


T
Techradar

我创建了一个 bash 脚本来简化删除过程。它还会检查 repo 中是否有未保存的更改并要求确认。它已经在 os x 上进行了测试,如果它在常见的 linux 发行版上也能正常工作,会很有趣:

https://gist.github.com/fabifrank/cdc7e67fd194333760b060835ac0172f