如何删除子模块?


3539

如何删除Git子模块?

顺便说一句,我不能简单地做一个原因 git submodule rm whatever吗?


109
现在,简单的答案stackoverflow.com/a/21211232/94687是正确的答案,应标记为正确答案。现在,它的简单 git rm modulenamerm -rf .git/modules/modulename
IMZ -伊万Zakharyaschev

10
这实际上是不对的。该答案不能解决从中删除子模块条目的问题.git/config。接受的答案显示了完全删除一个子模块的最新方法。在此答案中也更简洁地解释了:stackoverflow.com/a/36593218/1562138
fvgs

我发现本文对删除子模块非常有帮助。它包含有关删除.gitsubmodules和.git / config文件链接
Ri_16年

12
请节省一些时间,直接找到可行的答案(2017年):stackoverflow.com/a/36593218/528313
Vincenzo Pii

我已经将子模块问题解决了两天。当我发现以下内容时,便取得了突破:forums.developer.apple.com/thread/13102。基本上,Xcode,也许还有其他应用,都在努力扩展包含“〜”的网址。一旦我将ssh://username@server.remoteHost.com/~/git/MyRepo.git更改为ssh://username@server.remoteHost.com/home/username/git/MyRepo.git(查找实际路径)在您的服务器上),所有怪异现象在十分钟后消失了。另请参见stackoverflow.com/questions/32833100/...
埃莉斯面包车Looij

Answers:


2212

git1.8.3(2013年4月22日)开始

用“ submodule init” 表示对子模块的兴趣后,瓷器就没有办法说“我不再对此子模块感兴趣”。
submodule deinit”是这样做的方法。

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

摘要

3个步骤的删除过程如下:

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 -rfDaniel Schroeder回答中提到了这一点,Eonil评论中总结了这一点

.git/modules/<path-to-submodule>/保持不变。
因此,如果您一次使用此方法删除了子模块并再次重新添加,则将不可能,因为存储库已损坏。


git rm:参见commit 95c16418

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

让“ git rm”不仅通过从工作树中删除子模块,而且还通过submodule.<submodule name>.gitmodules文件中删除“ ”部分并同时上载这两个步骤来帮助用户。


git submodule deinit:源于此补丁

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

通过提供“ deinit”命令来帮助那些用户。
将从给定子模块(给定子模块(如果给定为')的所有子模块中删除)中删除整个submodule.<name>.git/config.
如果当前工作树包含修改,则该操作失败,除非强制执行。
对于在命令行上给出的子模块,在找不到url设置时提出投诉.git/config,但仍然不会失败。

如果(取消)初始化步骤(.git/config.git/modules/xxx),则需要注意

由于git1.8.5的git rm需要关心的:

  • add”步骤在.gitmodules文件中记录了子模块的url :需要为您删除。
  • 子模块特殊条目(如该问题所示):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(Q2 2018)开始,git子模块deinit不再是Shell脚本。
这是对C函数的调用。

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

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

18
您能举一个使用示例submodule deinit吗?
zakdances

5
@yourfriendzak是成功使用它的一个示例:stackoverflow.com/a/16161950/6309。但是请记住,与我最初的想法相反,1.8.3尚未发布!在Unix上,您可以从源代码进行编译。
VonC

2
@HamishDowner特殊条目应该消失了(目录不再是子模块),并且.gitmodules应该没问题,但是我仍然会仔细检查.git目录中的任何内容(即本地配置,在本地存储库中):这不是由a git pull)修改
VonC 2013年

2
@Jayen是的,如果您.gitmodules在索引中提交了删除条目和特殊条目的删除,并推送该存储库,其他人可以将其拉出,并且该子模块将消失。
VonC

3
在当前的git(v1.9 +)中,git rm submodule就像其他人已经说过的那样,plain old 确实可以满足您的要求。
彼得·彼得森

3445

通过页面Git Submodule Tutorial

要删除子模块,您需要:

  1. .gitmodules文件中删除相关部分。
  2. 进行.gitmodules更改:
    git add .gitmodules
  3. 从中删除相关部分.git/config
  4. 从工作树和索引中删除子模块文件:(
    git rm --cached path_to_submodule不带斜杠)。
  5. 删除子模块的.git目录:
    rm -rf .git/modules/path_to_submodule
  6. 提交更改:
    git commit -m "Removed submodule <name>"
  7. 删除现在未跟踪的子模块文件:
    rm -rf path_to_submodule

另请参阅以下替代步骤


410
“并且顺便说一句,有什么原因我不能简单地git子模块rm吗?” ?
abernier 2011年

48
@abernier简短的回答可能是“因为不存在这样的命令”。我的猜测是,他们正试图明确删除子模块文件与子模块配置,以避免意外的数据丢失。也许有人会认为git submodule rm只是删除子模块注册,如果命令也删除了本地存储库,就会感到惊讶。任何本地更改都将不可避免地丢失。也许另一个人会认为只有文件会被删除。
约翰·杜塔

119
坦白说,我不知道为什么。我希望他们添加一条命令。这四个步骤太复杂了。
约翰·杜塔特

25
这是一个删除子模块的bash脚本,只需为submodule-rm创建一个git别名;)gist.github.com/2491147
Capi Etheriel 2012年

33
还需要rm -rf .git \ modules \ submodule名称吗?
rogerdpack

484

请注意。从git 1.8.5.2开始,将执行以下两个命令:

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

正如@Mark Cheverton的答案正确指出的那样,如果不使用第二行,即使现在删除了子模块,残留的.git / modules / the_submodule文件夹也将阻止以后再添加或替换同一子模块。 。另外,正如@VonC所提到的,git rm它将在子模块上完成大部分工作。

-更新(07/05/2017)-

为了澄清,the_submodule是项目内部子模块的相对路径。例如,subdir/my_submodule子模块是否在子目录中subdir

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

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

5
我使用的是git版本2.4.9(Apple Git-60),我要做的就是rm the_submodule。我推动了该操作,然后重新添加了一个与子模块相同的文件夹,它的工作没有问题。
大卫·席尔瓦·史密斯

19
这不会从中删除子模块条目.git/config。有关删除子模块的完整方法,请参见stackoverflow.com/a/36593218/1562138
fvgs

2
@drevicko我刚刚使用Git 2.11.1进行了测试,并且观察到了与以前相同的行为。git init && git submodule add <repository> && git rm <name>留下.git/config条目和.git/modules/<name>目录及其内容。也许您没有在删除子模块之前对其进行初始化?
fvgs

2
我觉得更安全地运行第一个.. git子模块deinit -f the_submodule
danday74'Mar 10''17

1
@JarrodSmith是的,这就是道路。请查看更新。
tinlyx

478

该问题的大多数答案已经过时,不完整或不必要地复杂。

使用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

39
为什么这个答案投票很少?所有这些流行的答案都缺少某些内容,这是唯一以最简单的方法真正删除子模块的所有痕迹的答案。请注意:命令的顺序很重要。
mbdevpl


5
@mbdevpl是在接受答案的三年后提出的,我想没人能说服OP接受这个答案
Andy

10
这是2018年不复杂的答案吗?
沃伦·P

9
.gitmodules文件似乎仍然未受影响运行这些命令
Fractalf

206

简单步骤

  1. 删除配置条目:
    git config -f .git/config --remove-section submodule.$submodulename
    git config -f .gitmodules --remove-section submodule.$submodulename
  2. 从索引中删除目录:
    git rm --cached $submodulepath
  3. 承诺
  4. 删除未使用的文件:
    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 在最后,如果你把这个脚本。

也看看 参阅“我可以不填充Git子模块吗?”的答案


1
我有很多子模块(还有更大的混乱),所以我不得不将它们传递给for循环。由于它们中的大多数都在特定目录和ls输出的下面,所以包含斜杠。我做了类似的事情for dir in directory/*; do git rm --cached $dir; done
Pablo Olmos de Aguilera C.

要获得此列表,可以在脚本中使用该列表以进行递归删除--- 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
麻烦

2
获取未进行本地更改的模块列表git submodule | grep '^+' | cut -d' ' -f2
errordeveloper 2011年

请注意,我必须submodulename在双引号中添加"submodulename"..引用.git/config文件
muon

简单。高效。在2.25.0中,第1步后,你需要阶段.gitmodules步骤2之前改变
米歇尔Donais

83

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


1
我也有麻烦。如果您尝试将子模块重新安装到相同的路径,则会将分支信息保留在您提到的位置中,这会使事情混乱。
jangosteve 2012年

谢谢,我也需要这个。@Anton,我同意,并且我编辑了投票最高的答案以添加此信息。
威廉·丹尼斯斯

我使用了--name选项,使更换工作......看到stackoverflow.com/questions/14404704/...
joseph.hainline

60

要删除使用以下方式添加的子模块:

git submodule add blah@blah.com:repos/blah.git lib/blah

跑:

git rm lib/blah

而已。

对于旧版本的git(大约1.8.5),请使用:

git submodule deinit lib/blah
git rm lib/blah
git config -f .gitmodules --remove-section submodule.lib/blah

1
确实是+1。这是从git 1.8.3起唯一的正确答案。应该被接受为正确的一种。
Xananax 2014年

6
git rm仍然留下东西.git/modules/。(2.5.4)
鲁道夫·亚当科维奇

1
@RudolfAdamkovic对我有用吗?注意,只有在精确路径匹配的情况下,才删除子模块条目。如果已经移动了子模块然后再使用git rm它,则不会;在我的Mac上使用2.5.4进行的快速测试会更新.gitmodules文件,如此处的文档所述:git-scm.com/docs/git-rm#_submodules ...但如果您发现某种形式的平台组合, /版本不会发生这种情况,您可能应该提出一个错误。
Doug

2
这个答案并不完全正确。git rm将内容保留在.git/modules/目录和 .git/config文件中(ubuntu,git 2.7.4)。其他答案有效100%:stackoverflow.com/a/36593218/4973698
mbdevpl

50

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

git rm --cached path/to/submodule

如果您要在git的邮件列表上写,也许有人会为您做一个shell脚本。


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

42

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

[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配置中,然后您可以执行以下操作: git rms path/to/submodule


-1,因为这显然太错误了。首先:这假定子模块的名称和路径相同,但通常情况并非如此。IE浏览器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通常在那里有一个文件。
蒂诺

42

总之,这是您应该做的:

  1. 设置path_to_submodulevar(不带斜杠):

    path_to_submodule=path/to/submodule

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

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

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

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

  4. 取消登台并仅从索引中删除$ path_to_submodule(以防止丢失信息)

    git rm --cached $path_to_submodule

  5. 跟踪对.gitmodules所做的更改

    git add .gitmodules

  6. 提交超级项目

    git commit -m "Remove submodule submodule_name"

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

    rm -rf $path_to_submodule

    rm -rf .git/modules/$path_to_submodule


因此,其他拒绝我更改的人都必须运行rm -rf $ path_to_submodule rm -rf .git / modules / $ path_to_submodule才能删除子模块缓存?
j2emanue 2015年

我建议更新git submodule update。如果子模块的路径未正确更新(git引发错误),请将其删除:rm -rf .git/modules/<submodule> && rm -rf <submodule> && git submodule update
luissquall 2015年

40

如果由于添加,提交并推送了已经是Git存储库(包含)的文件夹而意外添加了子模块.git,则将没有.gitmodules文件可编辑,也没有任何内容.git/config在这种情况下,您需要做的是:

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

FWIW.git在执行此操作之前,我还删除了该文件夹git add


正是我的情况
zhekaus

37

我发现deinit对我有用的作品:

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

git docs

取消初始化

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


同意找到相同的解决方案。这是今天(2018年)最好的方式)
woto

1
它没有删除.git / modules / ..。你应该将其删除,请参阅@fvgs答案
维勒姆·库尔兹

不知道为什么这个简单的解决方案不是第
一位的

对于新git,AFAICS似乎是最安全的答案deinit,因为另一个答案.git/modules/submodule过早地删除了目录,这似乎会使新git的snow或失败。另外(请参阅我的评论)删除.git/modules/submodule路径可能是错误的,因此这是一个危险的步骤,只有在git抱怨时才最好采取此步骤(或者如果您有299%的把握,这是您真正需要的路径)。
蒂诺

我还需要git commit在工作目录dir modified .gitmodules和中进行阶段性更改deleted <submodule-path>
Yuriy Pozniak

20

在尝试了该站点上的所有不同答案之后,我得出了以下解决方案:

#!/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 $paththen rm -rf $path代替git rm -r $path
bfontaine 2014年

-1在尝试删除子模块中的子模块时不起作用(子模块可以形成树!)。另外,由于缺少报价,这是危险的越野车!实例git submodule add https://github.com/hilbix/empty.git 'dangerous .. submodule'- >当您尝试删除“危险..子模块”你的脚本,这将rm -rf ..是最有可能不是你想要的..
蒂诺

17

我目前在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}"

15

这是我所做的:

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)。首先执行fatal: no submodule mapping found in .gitmodules for path 'submodule_name'步骤1)的步骤3。但是,这两个步骤都是必需的。(git v2.8.2)
U007D'8

13

我最近发现了一个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%的帮助,但是如果使用它完全出错,请不要抱怨。 你被警告了!
Tino

10

我必须将John Douthat的步骤进一步向前移动,cd进入子模块的目录,然后删除Git存储库:

cd submodule
rm -fr .git

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


我也必须这样做,以便在尝试执行此git rm --cache步骤时避免出现“致命的:不是git仓库:”错误。
RickDT

9

这是我认为必要或有用的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 "..."

理论上git rm第1步中应注意这一点。希望OP问题的第二部分可以在一天之内得到肯定的回答(可以在一个命令中完成)。

但是从2017年7月开始,必须删除第2步.git/modules/,否则您将无法再添加子模块。

正如tinlyx的回答所指出的那样,您可能可以摆脱git 1.8.5+的上述两个步骤,因为所有git submodule命令似乎都可以使用。

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

为此,大多数答案建议使用git submodule deinit。我发现它更明确,使用起来也更容易混淆git config -f .git/config --remove-section。根据git-submodule文档git 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无关。


7
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

7

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

注意到没有人发布手动擦除,因此添加了


.gitmodules
Arialdo Martini

7

在git 2.17及更高版本中,它只是:

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

没有用,也git 2.17.1没有用git 2.20.1。但是,使用git rm而不是git add同时适用于两者。注意:如果东西干净,-f则不需要。如果要防止意外的数据丢失,请切勿将选项与一起使用git。还要注意,这留.git/modules/{module_name}在原地。 最佳做法是将其保留在该位置,因为git如果由于此原因而阻塞某些东西,则打印正确的(!)有助于继续操作。
蒂诺

4

如果您刚刚添加了子模块,例如,您只是添加了错误的子模块或将其添加到错误的位置,则只需git stash删除文件夹即可。这是假设添加子模块是您在最近的存储库中所做的唯一一件事。


3

为了读者的利益,这里尝试对它进行总结,并逐步指导如何在无法正常工作的情况下进行操作。以下是测试和安全的方式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/<name>/自己。 以我的理解,这不仅是错误的,而且是非常危险的,并且在将来引起了很多头痛! 见下文。

注意

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 -- module
    • (1)更新 .git/config
  • git rm
    • (2)删除模块文件
    • (3)从而递归地删除子模块的子模块
    • (4)更新 .gitmodules
  • git submodule add
    • 将数据提取到 .git/modules/NAME/
    • (1)这样做git submodule init,所以更新.git/config
    • (2)这样做git submodule update,因此,非递归地检出模块
    • (4)更新 .gitmodules
  • git submodule update --init --recursive -- module
    • 必要时提取更多数据
    • (3)递归检出子模块的子模块

这不能完全对称,因为使其严格对称没有太大意义。根本不需要两个以上的命令。另外,“拉入数据”是隐式的,因为您需要它,但不会删除缓存的信息,因为根本不需要这样做,并且可能会擦除珍贵的数据。

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

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

如果失败

上面的命令可能由于以下原因而失败:

  • git太老了。然后使用更新的git。(请参阅下面的方法。)
  • 您有未提交的数据,并且可能会丢失数据。然后最好先提交他们。
  • git clean某种意义上说,您的子模块不干净。然后,首先使用该命令清理您的子模块。(见下文。)
  • 您过去所做的事情不受的支持git。然后,您处于阴暗面,事情变得丑陋而复杂。(也许使用另一台计算机对其进行了修复。)
  • 也许还有更多我不知道的失败方法(我只是一些git高级用户。)

可能的修复方法如下。

使用较新的 git

如果你的机器太旧,没有submodule deinit在你的git。如果您不想(或可以)更新您的计算机git,则只需使用另一台更新的计算机即可gitgit是完全分布式的,因此您可以使用另一个git来完成工作:

  • workhorse:~/path/to/worktree$ git status --porcelain 一定不要输出任何东西!如果是这样,请先清理东西!
  • workhorse:~/path/to/worktree$ ssh account@othermachine
  • othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
  • 现在做子模块的东西
  • othermachine:~/TMPWORK$ git commit . -m . && exit
  • workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
  • workhorse:~/path/to/worktree$ git merge --ff-only FETCH_HEAD。如果这不起作用,请使用git reset --soft FETCH_HEAD
  • 现在清理事物,直到git status再次清理。您可以这样做,因为由于第一步,您之前已经将它清理干净。

othermachine可能是一些虚拟机,或者一些Ubuntu的WSL Windows下,不管。甚至一个chroot(但我假设您不是root用户,因为如果是root,则更容易将其更新为较新的版本git)。

请注意,如果您不能ssh进入,则有许多方法来运输git存储库。您可以将工作树复制到某些USB记忆棒(包括.git目录)上,然后从该记忆棒克隆。克隆副本,只是为了以一种干净的方式再次获取内容。如果您的子模块不能直接从其他计算机访问,则这可能是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 status并且git clean -ixfd是你的朋友
  • 尝试从选项弃权rmdeinit,只要你能。如果您是专业人士-fgit则提供的选项(如)会很好。但是当您来到这里时,您可能在该submodule地区没有那么丰富的经验。因此,最好不要后悔。

例:

$ 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'

您知道,-f不需要submodule deinit。从git clean某种意义上说,如果一切都干净。另请注意,这git clean -x不是必需的。 这意味着git submodule deinit无条件删除被忽略的未跟踪文件。 这通常是您想要的,但不要忘记它。有时,被忽略的文件可能很珍贵,例如缓存的数据需要数小时至数天才能重新计算。

为什么从不删除$GIT_DIR/modules/<name>/

人们可能想删除缓存的存储库,因为他们害怕以后会遇到问题。的确如此,但是遇到“问题”才是解决问题的正确方法!因为修复很容易,而且操作正确,您以后就可以过上幸福的生活。与您自己删除数据相比,这避免了麻烦的麻烦。

例:

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找到合适的东西删除!

因此,不仅大多数其他答案都陷入了这一危险陷阱,即使是非常受欢迎的git扩展程序都存在此错误现已在此处修复)!因此,.git/如果您不完全了解自己在做什么,最好还是掌握一下目录!

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

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


该帖子的百科全书应分为更清晰的部分,带有较大/更清晰的子标题以指示实际答案,以及不同的“疑难解答” / etc部分。
安德鲁

2

总之,这是您应该做的:

设置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

另请参阅:替代指南


您能否通过在“ 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第一可以解决这个问题。
卡洛·伍德

2

这很容易:

  1. 从中删除该部分 .gitmodules
  2. 呼叫: git add .gitmodules
  3. 呼叫: git submodule deinit <path to submodule>
  4. 呼叫: git rm <path to submodule>
  5. 提交并推送

您将必须手动删除项目上的模块文件。


2
对我来说,足以叫git submodule deinit <submodule_name>git rm <path_to_submodule>。最后一个命令会自动删除中的条目.gitmodules。Git 2.17
Dmytro Ovdiienko


0

在最新的git中,只需执行4个操作即可删除git子模块。

  • 删除中的相应条目 .gitmodules
  • 阶段变更 git add .gitmodules
  • 删除子模块目录 git rm --cached <path_to_submodule>
  • 提交 git commit -m "Removed submodule xxx"

0

如果您需要使用bash脚本在一行命令中执行以下操作:

$ cd /path/to/your/repo && /bin/bash $HOME/remove_submodule.sh /path/to/the/submodule

$HOME名为ie 的目录中创建bash脚本文件remove_submodule.sh

#!/bin/bash

git config -f .gitmodules --remove-section submodule.$1
git config -f .git/config --remove-section submodule.$1
git rm --cached $1
git add .gitmodules
git commit -m "Remove submodule in $1"
rm -rf $1
rm -rf .git/modules/$1
git push origin $(git rev-parse --abbrev-ref HEAD) --force --quiet


0
  • 可以通过运行删除子模块git rm <submodule path> && git commit。可以使用撤消git revert
    • 删除操作将删除超级项目的跟踪数据,该数据既是gitlink条目,也是.gitmodules文件中的部分。
    • 子模块的工作目录已从文件系统中删除,但是保留了Git目录,因为它可以签出过去的提交而无需从另一个存储库中获取。
  • 要完全删除子模块,请另外手动删除$GIT_DIR/modules/<name>/

资源: git help submodules


-1

删除git子模块

要卸下git子模块,需要执行以下4个步骤。

  1. 删除.gitmodules文件中的相应条目 。条目可能如下所述
[submodule "path_to_submodule"]
    path = path_to_submodule
    url = url_path_to_submodule
  1. 阶段变更 git add .gitmodules
  2. 删除子模块目录git rm --cached <path_to_submodule>
  3. 提交git commit -m "Removed submodule xxx"并推送。

下面需要另外2个步骤才能完全清除本地克隆副本中的子模块。

  1. 删除.git/config文件中的相应条目。条目可能如下所述
[submodule "path_to_submodule"]
    url = url_path_to_submodule
  1. rm -rf .git/modules/path_to_submodule

这第五和第六步不会创建任何需要提交的更改。


如果您使用git submodule deinit git-scm.com/docs/git-submodule#Documentation/…
黑色
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.