如何删除子模块?

发布于 2024-08-01 17:29:25 字数 67 浏览 4 评论 0原文

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

How do I remove a Git submodule?
Why can't I do
git submodule rm module_name?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

墨小墨 2024-08-08 17:29:25

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

  • Run git rm;,然后提交

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

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

  • rm -rf .git/modules/
  • git config --remove-section submodule.


较旧的社区 wiki 说明:

通过页面 Git 子模块教程< /em>:

要删除子模块,您需要:

  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"
  7. 删除现在未跟踪的子模块文件:
    rm -rf path_to_submodule

另请参阅以下替代步骤

In modern git (I'm writing this in 2022, with an updated git installation), this has become quite a bit simpler:

  • Run git rm <path-to-submodule>, and commit.

This removes the filetree at <path-to-submodule>, and the submodule's entry in the .gitmodules file. I.e. all traces of the submodule in your repository proper are removed.

As the docs note however, the .git dir of the submodule is kept around (in the modules/ directory of the main project's .git dir), "to make it possible to checkout past commits without requiring fetching from another repository".
If you nonetheless want to remove this info, manually delete the submodule's directory in .git/modules/, and remove the submodule's entry in the file .git/config. These steps can be automated using the commands

  • rm -rf .git/modules/<path-to-submodule>, and
  • git config --remove-section submodule.<path-to-submodule>.


Older community wiki instructions:

Via the page Git Submodule Tutorial:

To remove a submodule you need to:

  1. Delete the relevant section from the .gitmodules file.
  2. Stage the .gitmodules changes:
    git add .gitmodules
  3. Delete the relevant section from .git/config.
  4. Remove the submodule files from the working tree and index:
    git rm --cached path_to_submodule (no trailing slash).
  5. Remove the submodule's .git directory:
    rm -rf .git/modules/path_to_submodule
  6. Commit the changes:
    git commit -m "Removed submodule <name>"
  7. Delete the now untracked submodule files:
    rm -rf path_to_submodule

See also: alternative steps below.

白云不回头 2024-08-08 17:29:25

git1.8.3 ( 2013 年 4 月 22 日)

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

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

摘要

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 -rf:这在Daniel中提到施罗德答案,并由Eonil

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


git rm:请参阅提交 95c16418

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

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


git submodule deinit:它源于 此补丁

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


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

如果(反)初始化步骤(.git/config.git/modules/xxx

自 git1.8.5 开始,git rm code> 还负责:

  • 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 submodule deinit 不再是 shell 脚本。
这是对 C 函数的调用。

请参阅 提交 2e61273提交 1342476(2018 年 1 月 14 日),作者:Prathamesh Chavan ( pratham-pc)
(由 Junio C Hamano -- gitster -- 合并于 提交 ead8dbe,2018 年 2 月 13 日)

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

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

There was no Porcelain way to say "I no longer am interested in this submodule", once you express your interest in a submodule with "git submodule init".
"git submodule deinit" is the way to do so.

The deletion process also uses git rm (since git1.8.5 October 2013).

Summary

The 3-steps removal process would then be:

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

Explanation

rm -rf: This is mentioned in Daniel Schroeder's answer, and summarized by Eonil in the comments:

This leaves .git/modules/<path-to-submodule>/ unchanged.
So if you once delete a submodule with this method and re-add them again, it will not be possible because repository already been corrupted.


git rm: See commit 95c16418:

Currently using "git rm" on a submodule removes the submodule's work tree from that of the superproject and the gitlink from the index.
But the submodule's section in .gitmodules is left untouched, which is a leftover of the now removed submodule and might irritate users (as opposed to the setting in .git/config, this must stay as a reminder that the user showed interest in this submodule so it will be repopulated later when an older commit is checked out).

Let "git rm" help the user by not only removing the submodule from the work tree but by also removing the "submodule.<submodule name>" section from the .gitmodules file and stage both.


git submodule deinit: It stems from this patch:

With "git submodule init" the user is able to tell git they care about one or more submodules and wants to have it populated on the next call to "git submodule update".
But currently there is no easy way they can tell git they do not care about a submodule anymore and wants to get rid of the local work tree (unless the user knows a lot about submodule internals and removes the "submodule.$name.url" setting from .git/config together with the work tree himself).

Help those users by providing a 'deinit' command.
This removes the whole submodule.<name> section from .git/config either for the given
submodule(s)
(or for all those which have been initialized if '.' is given).
Fail if the current work tree contains modifications unless forced.
Complain when for a submodule given on the command line the url setting can't be found in .git/config, but nonetheless don't fail.

This takes care if the (de)initialization steps (.git/config and .git/modules/xxx)

Since git1.8.5, the git rm takes also care of the:

  • 'add' step which records the url of a submodule in the .gitmodules file: it is need to removed for you.
  • the submodule special entry (as illustrated by this question): the git rm removes it from the index:
    git rm --cached path_to_submodule (no trailing slash)
    That will remove that directory stored in the index with a special mode "160000", marking it as a submodule root directory.

If you forget that last step, and try to add what was a submodule as a regular directory, you would get error message like:

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

Note: since Git 2.17 (Q2 2018), git submodule deinit is no longer a shell script.
It is a call to a C function.

See commit 2e61273, commit 1342476 (14 Jan 2018) by Prathamesh Chavan (pratham-pc).
(Merged by Junio C Hamano -- gitster -- in commit ead8dbe, 13 Feb 2018)

git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
  ${GIT_QUIET:+--quiet} \
  ${prefix:+--prefix "$prefix"} \
  ${force:+--force} \
  ${deinit_all:+--all} "$@"
_畞蕅 2024-08-08 17:29:25

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

[email protected]: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

To remove a submodule added using:

[email protected]:repos/blah.git
MOD_DIR=lib/blah
git submodule add $REPOSITORY $MOD_DIR

Run:

git rm $MOD_DIR

That's it.

For old versions of git (circa ~1.8.5, actually even in 2.26.2) use:

git submodule deinit $MOD_DIR
git rm $MOD_DIR
git config -f .gitmodules --remove-section submodule.$MOD_DIR
遇见了你 2024-08-08 17:29:25

简单步骤

  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 子模块吗?的答案。

Simple steps

  1. Remove config entries:
    git config -f .git/config --remove-section submodule.$submodulename
    git config -f .gitmodules --remove-section submodule.$submodulename
  2. Remove directory from index:
    git rm --cached $submodulepath
  3. Commit
  4. Delete unused files:
    rm -rf $submodulepath
    rm -rf .git/modules/$submodulename

Please note: $submodulepath doesn't contain leading or trailing slashes.

Background

When you do git submodule add, it only adds it to .gitmodules, but
once you did git submodule init, it added to .git/config.

So if you wish to remove the modules, but be able to restore it quickly,
then do just this:

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

It is a good idea to do git rebase HEAD first and git commit
at the end, if you put this in a script.

Also have a look at an answer to Can I unpopulate a Git submodule?.

只怪假的太真实 2024-08-08 17:29:25

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

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

The majority of answers to this question are outdated, incomplete, or unnecessarily complex.

A submodule cloned using git 1.7.8 or newer will leave at most four traces of itself in your local repo. The process for removing those four traces is given by the three commands below:

# 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
旧夏天 2024-08-08 17:29:25

只是一个注释。 从 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

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

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

Just a note. Since git 1.8.5.2, two commands will do:

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

As @Mark Cheverton's answer correctly pointed out, if the second line isn't used, even if you removed the submodule for now, the remnant .git/modules/the_submodule folder will prevent the same submodule from being added back or replaced in the future. Also, as @VonC mentioned, git rm will do most of the job on a submodule.

--Update (07/05/2017)--

Just to clarify, the_submodule is the relative path of the submodule inside the project. For example, it's subdir/my_submodule if the submodule is inside a subdirectory subdir.

As pointed out correctly in the comments and other answers, the two commands (although functionally sufficient to remove a submodule), do leave a trace in the [submodule "the_submodule"] section of .git/config (as of July 2017), which can be removed using a third command:

git config -f .git/config --remove-section submodule.the_submodule 2> /dev/null
你对谁都笑 2024-08-08 17:29:25

我发现 deinit 对我很有用:

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

来自 git文档

去初始化

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

I found deinit works good for me:

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

From git docs:

deinit

Unregister the given submodules, i.e. remove the whole submodule.$name
section from .git/config together with their work tree.

苯莒 2024-08-08 17:29:25

我必须按照 John Douthat 的步骤更进一步,cd 进入子模块的目录,然后删除 Git 存储库:

cd submodule
rm -fr .git

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

I had to take John Douthat's steps one step further and cd into the submodule's directory, and then remove the Git repository:

cd submodule
rm -fr .git

Then I could commit the files as a part of the parent Git repository without the old reference to a submodule.

黒涩兲箜 2024-08-08 17:29:25

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

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

With git v2.7.4 simple 3 steps worked just fine.

git submodule deinit -f -- a/submodule    
git rm -f a/submodule
git commit
春庭雪 2024-08-08 17:29:25

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

The best way to remove a submodule from 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>'
寂寞笑我太脆弱 2024-08-08 17:29:25

在我看来,您可以通过以下三个步骤来完成此

操作此命令将删除内容

git submodule deinit -f devops

现在删除目录

rm -rvf devops

最后一步是从子模块文件中删除条目

git rm -f devops

这不是从.git层次结构中删除模块目录

cd .git/modules/ && rm -rvf devops

In my opinion you can do this with below three steps

This command will delete content

git submodule deinit -f devops

Now remove the directory

rm -rvf devops

The last step is to remove entry from submodule file

git rm -f devops

This is not it delete module directory from .git hierarchy

cd .git/modules/ && rm -rvf devops
巾帼英雄 2024-08-08 17:29:25

以下是我认为必要或有用的 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 的回答 所指出的,对于 git 1.8.5+,您可能可以摆脱上述两个步骤,正如所有git submodule 命令似乎有效。

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

为此,大多数答案建议使用 git submodule deinit 。 我发现使用 git config -f .git/config --remove-section 更明确且更容易混淆。 根据 git-submodule 文档git deinit

取消注册给定的子模块...如果你真的想删除一个
来自存储库的子模块并使用 git-rm[1] 提交
相反

最后但并非最不重要的一点是,如果您不git commit,那么在执行git submodule summary时您将/可能会收到错误(从 gi​​t 2.7 开始):

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

这与无论您执行步骤 2 还是步骤 3。

Here are the 4 steps that I found necessary or useful (important ones first):

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

In theory, git rm in step 1 should take care of it. Hopefully, the second part of OP question can be answered positively one day (that this can be done in one command).

But as of July 2017, step 2 is necessary to remove data in .git/modules/ for otherwise, you can't e.g. add the submodule back in the future.

You can probably get away with the above two steps for git 1.8.5+ as tinlyx's answer noted, as all git submodule commands seem to work.

Step 3 removes the section for the_submodule in the file .git/config. This should be done for completeness. (The entry may cause problems for older git versions, but I don't have one to test).

For this, most answers suggest using git submodule deinit. I find it more explicit and less confusing to use git config -f .git/config --remove-section. According to the git-submodule documentation, git deinit:

Unregister the given submodules ... If you really want to remove a
submodule from the repository and commit that use git-rm[1]
instead.

Last but not least, if you don't git commit, you will/may get an error when doing git submodule summary (as of git 2.7):

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

This is regardless of whether you do steps 2 or 3.

伴随着你 2024-08-08 17:29:25

我按照同一指南中的说明进行操作
如何删除子模块?

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

但它一直说:

fatal: no submodule mapping found in .gitmodules for path

所以我所做的就是在 .gitignore 中包含路径,如下所示(路径末尾没有星号):

<path>

然后我修改了任何文件并进行了简单推送

$ git add .
$ git commit -m "Ignoring sharedlibs folder <path> on .gitignore"
$ git push -u origin master

I followed the instructions from this very same guide
How do I remove a submodule?

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

But it kept saying:

fatal: no submodule mapping found in .gitmodules for path

So what I did is including the path in .gitignore like this (With no asterisk in the end of the path):

<path>

Then I modified any file and did a simple push:

$ git add .
$ git commit -m "Ignoring sharedlibs folder <path> on .gitignore"
$ git push -u origin master
尸血腥色 2024-08-08 17:29:25

我刚刚找到了 .gitmodules 隐藏文件,它有一个列表...您可以通过这种方式单独删除它们。 我只有一张,所以我把它删除了。 很简单,但它可能会弄乱 Git,因为我不知道子模块是否附加了任何东西。 到目前为止看起来还不错,除了 libetpan 常见的升级问题之外,但这(希望)无关。

I just found the .gitmodules hidden file, it has a list... you can erase them individually that way. I just had one, so I deleted it. Simple, but it might mess up Git, since I don't know if anything's attached to the submodule. Seems ok so far, aside from libetpan's usual upgrade issue, but that's (hopefully) unrelated.

兮颜 2024-08-08 17:29:25

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

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

With git 2.17 and above it's just:

git submodule deinit -f {module_name}
git add {module_name}
git commit
强者自强 2024-08-08 17:29:25
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
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
梦忆晨望 2024-08-08 17:29:25

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

If you have just added the submodule, and for example, you simply added the wrong submodule or you added it to the wrong place, simply do git stash then delete the folder. This is assuming that adding the submodule is the only thing you did in the recent repo.

浅唱ヾ落雨殇 2024-08-08 17:29:25

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

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

另请参阅:替代指南

To summarize, this is what you should do :

Set path_to_submodule var (no trailing slash):

path_to_submodule=path/to/submodule

Delete the relevant line from the .gitmodules file:

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

Delete the relevant section from .git/config

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

Unstage and remove $path_to_submodule only from the index (to prevent losing information)

git rm --cached $path_to_submodule

Track changes made to .gitmodules

git add .gitmodules

Commit the superproject

git commit -m "Remove submodule submodule_name"

Delete the now untracked submodule files

rm -rf $path_to_submodule

rm -rf .git/modules/$path_to_submodule

See also : Alternative guide lines

桃扇骨 2024-08-08 17:29:25

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

In addition to the recommendations, I also had to rm -Rf .git/modules/path/to/submodule to be able to add a new submodule with the same name (in my case I was replacing a fork with the original)

夜夜流光相皎洁 2024-08-08 17:29:25

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

[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

You can use an alias to automate the solutions provided by others:

[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"

Put that in your git config, and then you can do: git rms path/to/submodule

苹果你个爱泡泡 2024-08-08 17:29:25

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

  1. 设置path_to_submodule var(无尾部斜杠):

    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

To summarize, this is what you should do :

  1. Set path_to_submodule var (no trailing slash):

    path_to_submodule=path/to/submodule

  2. Delete the relevant line from the .gitmodules file:

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

  3. Delete the relevant section from .git/config

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

  4. Unstage and remove $path_to_submodule only from the index (to prevent losing information)

    git rm --cached $path_to_submodule

  5. Track changes made to .gitmodules

    git add .gitmodules

  6. Commit the superproject

    git commit -m "Remove submodule submodule_name"

  7. Delete the now untracked submodule files

    rm -rf $path_to_submodule

    rm -rf .git/modules/$path_to_submodule

情深已缘浅 2024-08-08 17:29:25

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

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

FWIW,在执行 git add< 之前,我还删除了 .git 文件夹/代码>。

If the submodule was accidentally added because you added, committed and pushed a folder that was already a Git repository (contained .git), you won’t have a .gitmodules file to edit, or anything in .git/config. In this case all you need is :

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

FWIW, I also removed the .git folder before doing the git add.

爱格式化 2024-08-08 17:29:25
  1. git submodule deinit
  2. .gitmodules 中删除该部分
  3. git rm
  4. 删除您要删除的模块文件需要从您的项目中删除。
  5. 将删除的文件添加到git中,调用git add .gitmodules
  6. 提交并推送
  1. git submodule deinit <path to submodule>
  2. Remove the section from .gitmodules
  3. git rm <path to submodule>
  4. Delete the module files which you need to remove from your project.
  5. Add the deleted files to git and call git add .gitmodules
  6. Commit and Push
北座城市 2024-08-08 17:29:25

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

#!/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)

After experimenting with all the different answers on this site, I ended up with this solution:

#!/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

This restores the exact same state as before you added the submodule. You can right away add the submodule again, which was not possible with most of the answers here.

git submodule add $giturl test
aboveScript test

This leaves you with a clean checkout with no changes to commit.

This was tested with:

$ git --version
git version 1.9.3 (Apple Git-50)
调妓 2024-08-08 17:29:25

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}"

What I'm currently doing Dec 2012 (combines most of these answers):

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}"
请恋爱 2024-08-08 17:29:25

这是我所做的:

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

Here is what I did :

1.) Delete the relevant section from the .gitmodules file. You can use below command:

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

2.) Stage the .gitmodules changes

git add .gitmodules

3.) Delete the relevant section from .git/config. You can use below command:

git submodule deinit -f "submodule_name"

4.) Remove the gitlink (no trailing slash):

git rm --cached path_to_submodule

5.) Cleanup the .git/modules:

rm -rf .git/modules/path_to_submodule

6.) Commit:

git commit -m "Removed submodule <name>"

7.) Delete the now untracked submodule files

rm -rf path_to_submodule
不羁少年 2024-08-08 17:29:25

所有答案看起来都已经过时了。 我正在使用 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)

All the answers look outdated. I am using git version 2.28.0. One line answer is,

git rm path-to-submodule

However, even though the submodule is removed from source control, .git/modules/path-to-submodule still contains the submodule repository and .git/config contains its URL, so you still have to remove those manually:

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

Sometimes, you have to use the -f flag:

$ git rm -f img2vec

For example, because you might get an error like this:

$ 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)
流殇 2024-08-08 17:29:25

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

安装它并输入:

git delete-submodule submodule

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

I recently find out a git project which include many useful git related command: https://github.com/visionmedia/git-extras

Install it and type :

git delete-submodule submodule

Then things are done. The submodule directory will be removed from your repo and still exist in your filesystem. You can then commit the change like: git commit -am "Remove the submodule".

逆蝶 2024-08-08 17:29:25

为了读者的利益,本文试图对其进行总结,并提供有关如何在事情未按预期进行时进行操作的分步指南。 以下是 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"< /code> 使用 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 -- module
    • (1) 更新 .git/config
  • git rm
    • (2)删除模块的文件
    • (3)从而递归地删除子模块的子模块
    • (4) 更新 .gitmodules
  • git submodule add
    • 将数据拉入.git/modules/NAME/
    • (1) 执行 git submodule init,因此更新 .git/config
    • (2) 执行 git 子模块更新,因此,非递归地检查模块
    • (4) 更新 .gitmodules
  • git submodule update --init --recursive --模块
    • 根据需要提取更多数据
    • (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 不得输出任何内容! 如果是这样,请先清理东西!
  • 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。 && 退出
  • workhorse:~/path/to/worktree$ git fetch account@othermachine:TMPWORK/.git
  • workhorse:~/path/to/worktree$ git merge --ff -仅 FETCH_HEAD。 如果这不起作用,请使用 git reset --soft FETCH_HEAD
  • 现在清理一些东西,直到 git status 再次干净为止。 你能够这样做,因为你已经通过第一步将其清理干净了。

这个othermachine可以是某个VM,也可以是Windows下的某个Ubuntu WSL,等等。 甚至是 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 抱怨有些剩菜,git statusgit clean -ixfd 是你的朋友
  • 尝试放弃使用 rmdeinit 选项只要你可以。 如果您是专业人士,git 的选项(如 -f)非常有用。 但当您来到这里时,您可能在 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'

您会看到,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// 目录。 这非常麻烦,并且很难使用像 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 帐户。

For the benefit of the reader, this here tries to sum it up and give a step-by-step guide on how to do it if things do not work as expected. Following is the tested and safe way for git version 2.17 and above to get rid of a submodule:

submodule="path/to/sub"              # no trailing slash!
git submodule deinit -- "$submodule"
git rm -- "$submodule"
  • If this does not work for you, see below.
  • No options. Nothing dangerous. And do not even consider doing more!
  • Tested with Debian Buster 2.20.1 and Ubuntu 18.04 2.17.1.
  • "$submodule" is just to emphasize where to put the name, and that you have to be careful with spaces and the like
  • If on Windows ignore the first line and replace "$submodule" with the Windows way of a properly specified path to the submodule. (I am not Windows)

Warning!

Never touch the insides of the .git directory yourself! Editing inside .git enters the dark side. Stay away at all cost!

And yes, you can blame git for this, as many handy things were missing in git in the past. Like a proper way to remove submodules again.

I think there is a very dangerous part in the documentation of git submodule.
It recommends to remove $GIT_DIR/modules/<name>/ yourself.
In my understanding this is not only plain wrong, it is extremely dangerous and provokes major headaches in future! See below.

Note that

git module deinit

is the direct inverse to

git module init

but

git submodule deinit -- module
git rm -- module

also is quite the inverse to

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

because some commands basically need to do more than just a single thing:

  • git submodule deinit -- module
    • (1) updates .git/config
  • git rm
    • (2) removes the files of the module
    • (3) thereby recursively removes the submodules of the submodule
    • (4) updates .gitmodules
  • git submodule add
    • pulls in the data to .git/modules/NAME/
    • (1) does git submodule init, so updates .git/config
    • (2) does git submodule update, so, nonrecursively checks out the module
    • (4) updates .gitmodules
  • git submodule update --init --recursive -- module
    • pulls in further data if needed
    • (3) checks out the submodules of the submodule recursively

This cannot be fully symmetric, as keeping it strictly symmetric does not make much sense. There simply is no need for more than two commands. Also "pulling in the data" is implicit, because you need it, but removing the cached information is not done, because this is not needed at all and might wipe precious data.

This truly is puzzling to newcomers, but basically is a good thing: git just does the obviously thing and does that right, and does not even try to do more. git is a tool, which must do a reliable job, instead of being just another "Eierlegende Wollmilchsau" ("Eierlegende Wollmilchsau" translates for me to "some evil version of a Swiss army knife").

So I understand complaints of people, saying "Why doesn't do git the obvious thing for me". This is because "obvious" here depends from the point of view. Reliability in each and every situation is far more important. Hence what's obvious for you often is not the right thing in all possible technical situations. Please remember that: AFAICS git follows the technical path, not the social one. (Hence the clever name: git)

If this fails

The commands above may fail due to following:

  • Your git is too old. Then use a newer git. (See below how to.)
  • You have uncommitted data and might lose data. Then better commit them first.
  • Your submodule is not clean in a git clean sense. Then first clean your submodule using that command. (See below.)
  • You have done something in the past which is unsupported by git. Then you are on the dark side and things get ugly and complicated. (Perhaps using another machine fixes it.)
  • Perhaps there are more ways to fail I am not aware of (I am just some git power-user.)

Possible fixes follow.

Use a newer git

If your machine is too old there is no submodule deinit in your git. If you do not want (or can) update your git, then just use another machine with a newer git! git is meant to be fully distributed, so you can use another git to get the job done:

  • workhorse:~/path/to/worktree$ git status --porcelain must not output anything! If it does, cleanup things first!
  • workhorse:~/path/to/worktree$ ssh account@othermachine
  • othermachine:~$ git clone --recursive me@workhorse path/to/worktree/.git TMPWORK && cd TMPWORK
  • Now do the submodule stuff
  • 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. If this does not work, use git reset --soft FETCH_HEAD
  • Now cleanup things, until git status is clean again. You are able to do so, because you have had it clean before, thanks to the first step.

This othermachine can be some VM, or some Ubuntu WSL under Windows, whatever. Even a chroot (but I assume that you are non-root, because if you are root it should be more easy to update to the newer git).

Note that if you cannot ssh in, there are trainloads of ways to transport git repositories. You can copy your worktree on some USB stick (including the .git directory), and clone from the stick. Clone the copy, just to get things in a clean fashion again. This might be a PITA, in case your submodules are not accessible from othermachine directly. But there is a solution for this, too:

git config --add url.NEWURLPREFIX.insteadOf ORIGINALURLPREFIX

You can use this multiply, and this is saved into $HOME/.gitconfig. Something like

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

rewrites URLs like

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

into

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

It's easy if you start to become accustomed to powerful git features like this.

Cleanup things first

Cleaning manually up is good, because this way you perhaps detect some things you forgot about.

  • If git complains about unsaved stuff, commit and push it somewhere safe.
  • If git complains about some leftovers, git status and git clean -ixfd is your friend
  • Try to abstain from options to rm and deinit as long as you can. Options (like -f) for git are good if you are a Pro. But as you came here, you probably are not so experienced in the submodule area. So better be safe than sorry.

Example:

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

You see, there is no -f needed on submodule deinit. If things are clean, in a git clean sense. Also note that git clean -x is not needed. This means git submodule deinit unconditionally removes untracked files which are ignored. This is usually what you want, but do not forget about it. Sometimes ignored files might be precious, like cached data which takes hours to days to be calculated again.

Why never remove $GIT_DIR/modules/<name>/?

Probably people want to remove the cached repository, because they are afraid to run into a problem later. This is true, but running into that "problem" is the correct way to solve it! Because the fix is easy, and done right you will be able to live happily ever after. This avoids more cumbersome trouble than when you remove the data yourself.

Example:

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

The last line outputs following error:

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.

Why this error? Because .git/modules/two/ previously was populated from https://github.com/hilbix/empty.git and now shall be re-populated from something else, namely https://github.com/hilbix/src.git. You won't see this if you re-populate it from https://github.com/hilbix/empty.git

What to do now? Well, just do exactly as told! Use --name someunusedname

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

.gitmodules then looks like

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

ls -1p .git/modules/ gives

someunusedname/
two/

This way in future you can switch branches/commit forward and backward and will never get into any trouble again, due to two/ having two different (and possibly incompatible) upstream repositories. And the best is: You keep both cached locally, too.

  • This is not only true for you. It also is true for all others using your repository.
  • And you do not lose history. In case you forgot to push the very latest version of the old submodule, you can enter the local copy and do so later on. Note that it is quite common that somebody forgets to push some submodules (because this is a PITA for newcomers, until they became accustomed to git).

However if you removed the cached directory, both different checkouts will stumble upon each other, because you will not use the --name options, right? So each time you do the checkout you perhaps have to remove the .git/modules/<module>/ directory again and again. This is extremely cumbersome and makes it hard to use something like git bisect.

So there is a very technical reason to keep this module directory as a placeholder. People who recommend to remove something below .git/modules/ either do not know better or forget to tell you that this makes powerful features like git bisect nearly impossible to use if this crosses such a submodule incompatibility.

A further reason is shown above. Look at the ls. What do you see there?

Well, the 2nd variant of module two/ is not under .git/modules/two/, it is under .git/modules/someunusedname/! So things like git rm $module; rm -f .git/module/$module are totally wrong! You must either consult module/.git or .gitmodules to find the right thing to remove!

So not only most other answers fall into this dangerous trap, even very popular git extensions had this bug (it's now fixed there)! So better keep your hands of the .git/ directory if you do not exactly, what you are doing!

And from the philosophical view, wiping history is always wrong!
Except for quantum mechanics, as usual, but this is something completely different.

FYI you probably guessed it: hilbix is my GitHub account.

染柒℉ 2024-08-08 17:29:25

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

git rm --cached path/to/submodule

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

You must remove the entry in .gitmodules and .git/config, and remove the directory of the module from the history:

git rm --cached path/to/submodule

If you'll write on git's mailing list probably someone will do a shell script for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文