un-submodule 一个 git 子模块

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1759587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 07:22:06  来源:igfitidea点击:

un-submodule a git submodule

gitgit-submodules

提问by Quickredfox

How do I un-submodule a git submodule (bring all the code back into the core) ?

如何取消子模块 git 子模块(将所有代码带回核心)?

As in how "should" I, as in "Best procedure" ...

就像我“应该”如何一样,就像在“最佳程序”中一样......

回答by gyim

If all you want is to put your submodule code into the main repository, you just need to remove the submodule and re-add the files into the main repo:

如果您只想将子模块代码放入主存储库,则只需删除子模块并将文件重新添加到主存储库中:

git rm --cached submodule_path # delete reference to submodule HEAD (no trailing slash)
git rm .gitmodules             # if you have more than one submodules,
                               # you need to edit this file instead of deleting!
rm -rf submodule_path/.git     # make sure you have backup!!
git add submodule_path         # will add files instead of commit reference
git commit -m "remove submodule"

If you also want to preserve the history of the submodule, you can do a small trick: "merge" the submodule into the main repository so that the result will be the same as it was before, except that the submodule files are now in the main repository.

如果你还想保留子模块的历史,你可以做一个小技巧:将子模块“合并”到主存储库中,这样结果就会和以前一样,只是子模块文件现在在主存储库。

In the main module you will need to do the following:

在主模块中,您需要执行以下操作:

# Fetch the submodule commits into the main repository
git remote add submodule_origin git://url/to/submodule/origin
git fetch submodule_origin

# Start a fake merge (won't change any files, won't commit anything)
git merge -s ours --no-commit submodule_origin/master

# Do the same as in the first solution
git rm --cached submodule_path # delete reference to submodule HEAD
git rm .gitmodules             # if you have more than one submodules,
                               # you need to edit this file instead of deleting!
rm -rf submodule_path/.git     # make sure you have backup!!
git add submodule_path         # will add files instead of commit reference

# Commit and cleanup
git commit -m "removed submodule"
git remote rm submodule_origin

The resulting repository will look a bit weird: there will be more than one initial commit. But it won't cause any problems for git.

生成的存储库看起来有点奇怪:将有多个初始提交。但它不会对 git 造成任何问题。

In this second solution you will have the big advantage that you can still run git blame or git log on the files which were originally in submodules. In fact what you did here is to rename many files inside one repository, and git should autodetect this. If you still have problems with git log, try some options (--follow, -M, -C) which do better rename/copy detection.

在第二个解决方案中,您将拥有一个很大的优势,即您仍然可以对最初位于子模块中的文件运行 git blame 或 git log 。事实上,你在这里所做的是重命名一个存储库中的许多文件,git 应该自动检测到这一点。如果 git log 仍然有问题,请尝试一些选项(--follow、-M、-C),它们可以更好地重命名/复制检测。

回答by VonC

Since git 1.8.5 (Nov 2013) (without keeping the history of the submodule):

git 1.8.5(2013 年 11 月)起(不保留子模块的历史记录):

mv yoursubmodule yoursubmodule_tmp
git submodule deinit yourSubmodule
git rm yourSubmodule
mv yoursubmodule_tmp yoursubmodule
git add yoursubmodule

That will:

那将:

  • unregister and unload(ie delete the content of) the submodule (deinit, hence the mvfirst),
  • clean up the .gitmodulesfor you (rm),
  • and remove the special entryrepresenting that submodule SHA1 in the index of the parent repo (rm).
  • 注销并卸载(即删除)子模块(deinit,因此是mv第一个),
  • .gitmodules为你清理( rm),
  • 并删除父存储库 ( )索引中代表该子模块 SHA1的特殊条目rm

Once the removal of the submodule is complete (deinitand git rm), you can rename the folder back to its original name and add it to the git repo as a regular folder.

一旦子模块的删除完成(deinitgit rm),您可以将文件夹重命名回其原始名称,并将其作为常规文件夹添加到 git 存储库中。

Note: if the submodule was created by an old Git (< 1.8), you might need to remove the nested .gitfolder within the submodule itself, as commentedby Simon East

注意:如果子模块是由旧 Git(< 1.8)创建的,您可能需要删除.git子模块本身内的嵌套文件夹,如Simon East评论



If you need to keep the history of the submodule, see jsears's answer, which uses git filter-branch.

如果您需要保留子模块的历史记录,请参阅jsears回答,它使用git filter-branch.

回答by jsears

I've created a script that will translate a submodule to a simple directory, while retaining all file history. It doesn't suffer from the git log --follow <file>issues that the other solutions suffer from. It's also a very easy one-line invocation that does all of the work for you. G'luck.

我创建了一个脚本,它将子模块转换为一个简单的目录,同时保留所有文件历史记录。它不会遇到git log --follow <file>其他解决方案所遇到的问题。这也是一个非常简单的单行调用,可以为您完成所有工作。祝你好运。

It builds on the excellent work by Lucas Jen?, described in his blog post "Integrating a submodule into the parent repository", but automates the entire process and cleans up a few other corner cases.

它建立在 Lucas Jen? 的出色工作之上,在他的博客文章“将子模块集成到父存储库中”中进行了描述,但自动化了整个过程并清理了其他一些极端情况。

The latest code will be maintained with bugfixes on github at https://github.com/jeremysears/scripts/blob/master/bin/git-submodule-rewrite, but for the sake of proper stackoverflow answer protocol, I've included the solution in its entirety below.

最新的代码将在https://github.com/jeremysears/scripts/blob/master/bin/git-submodule-rewrite上的 github 上通过错误修正进行维护,但为了正确的 stackoverflow 应答协议,我已经包含了完整的解决方案如下。

Usage:

用法:

$ git-submodule-rewrite <submodule-name>

git-submodule-rewrite:

git-submodule-rewrite:

#!/usr/bin/env bash

# This script builds on the excellent work by Lucas Jen?, described in his blog
# post "Integrating a submodule into the parent repository", but automates the
# entire process and cleans up a few other corner cases.
# https://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html

function usage(){
  echo "Merge a submodule into a repo, retaining file history."
  echo "Usage: 
git clone [email protected]:main/main.git
git submodule deinit child
git rm child
git add --all
git commit -m "remove child submodule"
<submodule-name>" echo "" echo "options:" echo " -h, --help Print this message" echo " -v, --verbose Display verbose output" } function abort { echo "$(tput setaf 1)$(tput sgr0)" exit 1 } function request_confirmation { read -p "$(tput setaf 4) (y/n) $(tput sgr0)" [ "$REPLY" == "y" ] || abort "Aborted!" } function warn() { cat << EOF This script will convert your "${sub}" git submodule into a simple subdirectory in the parent repository while retaining all contents and file history. The script will: * delete the ${sub} submodule configuration from .gitmodules and .git/config and commit it. * rewrite the entire history of the ${sub} submodule so that all paths are prefixed by ${path}. This ensures that git log will correctly follow the original file history. * merge the submodule into its parent repository and commit it. NOTE: This script might completely garble your repository, so PLEASE apply this only to a fresh clone of the repository where it does not matter if the repo is destroyed. It would be wise to keep a backup clone of your repository, so that you can reconstitute it if need be. You have been warned. Use at your own risk. EOF request_confirmation "Do you want to proceed?" } function git_version_lte() { OP_VERSION=$(printf "%03d%03d%03d%03d" $(echo "" | tr '.' '\n' | head -n 4)) GIT_VERSION=$(git version) GIT_VERSION=$(printf "%03d%03d%03d%03d" $(echo "${GIT_VERSION#git version}" | tr '.' '\n' | head -n 4)) echo -e "${GIT_VERSION}\n${OP_VERSION}" | sort | head -n1 [ ${OP_VERSION} -le ${GIT_VERSION} ] } function main() { warn if [ "${verbose}" == "true" ]; then set -x fi # Remove submodule and commit git config -f .gitmodules --remove-section "submodule.${sub}" if git config -f .git/config --get "submodule.${sub}.url"; then git config -f .git/config --remove-section "submodule.${sub}" fi rm -rf "${path}" git add -A . git commit -m "Remove submodule ${sub}" rm -rf ".git/modules/${sub}" # Rewrite submodule history local tmpdir="$(mktemp -d -t submodule-rewrite-XXXXXX)" git clone "${url}" "${tmpdir}" pushd "${tmpdir}" local tab="$(printf '\t')" local filter="git ls-files -s | sed \"s/${tab}/${tab}${path}\//\" | GIT_INDEX_FILE=${GIT_INDEX_FILE}.new git update-index --index-info && mv ${GIT_INDEX_FILE}.new ${GIT_INDEX_FILE}" git filter-branch --index-filter "${filter}" HEAD popd # Merge in rewritten submodule history git remote add "${sub}" "${tmpdir}" git fetch "${sub}" if git_version_lte 2.8.4 then # Previous to git 2.9.0 the parameter would yield an error ALLOW_UNRELATED_HISTORIES="" else # From git 2.9.0 this parameter is required ALLOW_UNRELATED_HISTORIES="--allow-unrelated-histories" fi git merge -s ours --no-commit ${ALLOW_UNRELATED_HISTORIES} "${sub}/master" rm -rf tmpdir # Add submodule content git clone "${url}" "${path}" rm -rf "${path}/.git" git add "${path}" git commit -m "Merge submodule contents for ${sub}" git config -f .git/config --remove-section "remote.${sub}" set +x echo "$(tput setaf 2)Submodule merge complete. Push changes after review.$(tput sgr0)" } set -euo pipefail declare verbose=false while [ $# -gt 0 ]; do case "" in (-h|--help) usage exit 0 ;; (-v|--verbose) verbose=true ;; (*) break ;; esac shift done declare sub="${1:-}" if [ -z "${sub}" ]; then >&2 echo "Error: No submodule specified" usage exit 1 fi shift if [ -n "${1:-}" ]; then >&2 echo "Error: Unknown option: ${1:-}" usage exit 1 fi if ! [ -d ".git" ]; then >&2 echo "Error: No git repository found. Must be run from the root of a git repository" usage exit 1 fi declare path="$(git config -f .gitmodules --get "submodule.${sub}.path")" declare url="$(git config -f .gitmodules --get "submodule.${sub}.url")" if [ -z "${path}" ]; then >&2 echo "Error: Submodule not found: ${sub}" usage exit 1 fi if ! [ -d "${path}" ]; then >&2 echo "Error: Submodule path not found: ${path}" usage exit 1 fi main

回答by Marcel Hymanwerth

  1. git rm --cached the_submodule_path
  2. remove the submodule section from the .gitmodulesfile, or if it's the only submodule, remove the file.
  3. do a commit "removed submodule xyz"
  4. git add the_submodule_path
  5. another commit "added codebase of xyz"
  1. git rm --cached the_submodule_path
  2. .gitmodules文件中删除子模块部分,或者如果它是唯一的子模块,则删除文件。
  3. 做一个提交“删除子模块xyz”
  4. git add the_submodule_path
  5. 另一个提交“添加了 xyz 的代码库”

I didn't find any easier way yet. You can compress 3-5 into one step via git commit -a- matter of taste.

我还没有找到更简单的方法。您可以通过git commit -a- 品味问题将 3-5 压缩为一个步骤。

回答by mschuett

Lots of answers here but all of them seem to be overly complex and likely do not do what you want. I am sure most people want to keep their history.

这里有很多答案,但所有答案似乎都过于复杂,并且可能无法满足您的要求。我相信大多数人都想保留他们的历史。

For this example the main repo will be [email protected]:main/main.gitand the submodule repo will be [email protected]:main/child.git. This assumes that the submodule is located in the root directory of the parent repo. Adjust the instructions as needed.

对于此示例,主存储库将是[email protected]:main/main.git,子模块存储库将是[email protected]:main/child.git. 这假设子模块位于父存储库的根目录中。根据需要调整说明。

Start by cloning the parent repo and removing the old submodule.

首先克隆父存储库并删除旧的子模块。

git remote add upstream [email protected]:main/child.git
git fetch upstream
git checkout -b merge-prep upstream/master

Now we will add the child repos upstream to the main repo.

现在我们将上游的子仓库添加到主仓库。

mkdir child

The next step assumes that you want to move the files on the merge-prep branch into the same location as the submodule was above although you can easily change the location by changing the file path.

下一步假设您要将合并准备分支上的文件移动到与上面的子模块相同的位置,尽管您可以通过更改文件路径轻松更改位置。

git add --all
git commit -m "merge prep"

move all folders and files except the .git folder into the child folder.

将除 .git 文件夹之外的所有文件夹和文件移动到子文件夹中。

git checkout master
git merge merge-prep # --allow-unrelated-histories merge-prep flag may be required 

Now you can simply merge your files back into the master branch.

现在您可以简单地将您的文件合并回主分支。

git clone project_uri project_name

Look around and make sure everything looks good before running git push

在运行之前环顾四周并确保一切正常 git push

The one thing you have to remember now is that git log does not by default follow moved files however by running git log --follow filenameyou can see the full history of your files.

您现在必须记住的一件事是 git log 默认情况下不会跟踪移动的文件,但是通过运行git log --follow filename您可以查看文件的完整历史记录。

回答by dvicino

It happened to us that we created 2 repositories for 2 projects that were so coupled that didn't make any sense to have them separated, so we merged them.

我们碰巧为 2 个项目创建了 2 个存储库,这些存储库如此耦合以至于将它们分开没有任何意义,因此我们合并了它们。

I'll show how to merge the master branches in each first and then I will explain how you can extend this to every branches you got, hope it helps you.

我将首先展示如何在每个分支中合并主分支,然后我将解释如何将其扩展到您获得的每个分支,希望对您有所帮助。

If you got the submodule working, and you want to convert it to a directory in place you can do:

如果您让子模块正常工作,并且您想将其转换为适当的目录,您可以执行以下操作:

cd project_name
vim .gitmodules

Here we do a clean clone to work. For this process you don't need to initialize or update the submodules, so just skip it.

在这里,我们做了一个干净的克隆来工作。对于此过程,您不需要初始化或更新子模块,因此只需跳过它。

[submodule "lib/asi-http-request"]
    path = lib/asi-http-request
    url = https://github.com/pokeb/asi-http-request.git

Edit .gitmoduleswith your favorite editor (or Vim) to remove the submodule you plan to replace. The lines you need to remove should look something like this:

编辑.gitmodules用你喜欢的编辑器(或VIM)删除您打算更换子模块。您需要删除的行应如下所示:

git rm --cached directory_of_submodule
git commit -am "Removed submodule_name as submodule"
rm -rf directory_of_submodule

After saving the file,

保存文件后,

git remote add -f submodule_origin submodule_uri
git fetch submodel_origin/master

Here we remove the submodule relation completely so we can create bring the other repo to the project in-place.

在这里,我们完全删除了子模块关系,以便我们可以创建将另一个存储库就地引入项目。

git merge -s ours --no-commit submodule_origin/master

Here we fetch the submodule repository to merge.

在这里,我们获取要合并的子模块存储库。

git read-tree --prefix=directory_of_submodule/ -u submodule_origin/master

Here we start a merge operation of the 2 repositories, but stop before commit.

在这里,我们开始了 2 个存储库的合并操作,但在提交之前停止。

git commit -am "submodule_name is now part of main project"

Here we send the content of master in the submodule to the directory where it was before prefixing a directory name

在这里,我们将子模块中 master 的内容发送到它在目录名称前缀之前的目录

git clone ../main_repo main.tmp
git clone ../main_repo/sub_repo sub.tmp

Here we complete the procedure doing a commit of the changes in the merge.

在这里,我们完成了对合并中的更改进行提交的过程。

After finishing this you can push, and start again with any other branch to merge, just checkout the branch in you repository that will receive the changes and change the branch you bringing in the merge and read-tree operations.

完成此操作后,您可以推送,并重新开始与任何其他分支合并,只需检出存储库中将接收更改的分支并更改您引入合并和读取树操作的分支。

回答by dataless

Here's a slightly improved version (IMHO) of @gyim's answer. He is doing a bunch of dangerous changes in the main working copy, where I think it's much easier to operate on separate clones and then merge them together at the end.

这是@gyim 答案的略微改进版本(恕我直言)。他正在主要工作副本中进行一系列危险的更改,我认为在其中对单独的克隆进行操作然后在最后将它们合并在一起要容易得多。

In a separate directory (to make mistakes easier to clean up and try again) check out both the top repo and the subrepo.

在一个单独的目录中(为了使错误更容易清理并重试),请检查顶部存储库和子存储库。

cd sub.tmp
mkdir sub_repo_path
git mv `ls | grep -v sub_repo_path` sub_repo_path/
git commit -m "Moved entire subrepo into sub_repo_path"

First edit the subrepo to move all files into the desired subdirectory

首先编辑 subrepo 将所有文件移动到所需的子目录中

SUBREPO_HEAD=`git reflog | awk '{ print ; exit; }'`

Make a note of the HEAD

记下 HEAD

cd ../main.tmp
rmdir sub_repo_path
vi .gitmodules  # remove config for submodule
git add -A
git commit -m "Removed submodule sub_repo_path in preparation for merge"

Now remove the subrepo from the main repo

现在从主仓库中删除子仓库

git fetch ../sub.tmp
# remove --allow-unrelated-histories if using git older than 2.9.0
git merge --allow-unrelated-histories $SUBREPO_HEAD

And finally, just merge them

最后,只需合并它们

git rm [-r] --cached submodule_path

And done! Safely and without any magic.

并做了!安全,没有任何魔法。

回答by Luke H

The best answer to this I have found is here:

我找到的最佳答案在这里:

http://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html

http://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html

This article explains the procedure very well.

这篇文章很好地解释了这个过程。

回答by brandones

For when

对于什么时候

fatal: pathspec 'emr/normalizers/' did not match any files

returns

返回

mv submodule_path submodule_path.temp
git add -A .
git commit -m "De-submodulization phase 1/2"
mv submodule_path.temp submodule_path
git add -A .
git commit -m "De-submodulization phase 2/2"


Context: I did rm -r .git*in my submodule folders before realizing that they needed to be de-submoduled in the main project to which I had just added them. I got the above error when de-submoduling some, but not all of them. Anyway, I fixed them by running, (after, of course, the rm -r .git*)

上下文:我rm -r .git*在我的子模块文件夹中做了,然后才意识到它们需要在我刚刚添加到的主项目中取消子模块。在对一些但不是全部进行去子调制时,我​​遇到了上述错误。无论如何,我通过运行修复了它们,(当然,在 之后rm -r .git*

#!/usr/bin/env bash
mv "" "_"
git submodule deinit ""
git rm ""
mv "_" ""
git add "/**"

Note that this doesn't preserve history.

请注意,这不会保留历史记录。

回答by void.pointer

Based on VonC's answer, I have created a simple bash script that does this. The addat the end has to use wildcards otherwise it will undo the previous rmfor the submodule itself. It's important to add the contentsof the submodule directory, and not to name the directory itself in the addcommand.

根据VonC 的回答,我创建了一个简单的 bash 脚本来执行此操作。将add在年底必须使用通配符否则将取消先前rm的子模块本身。添加子模块目录的内容很重要,而不是在add命令中命名目录本身。

In a file called git-integrate-submodule:

在名为 的文件中git-integrate-submodule

##代码##