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
un-submodule a git submodule
提问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 themv
first), - clean up the
.gitmodules
for 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 (deinit
and git rm
), you can rename the folder back to its original name and add it to the git repo as a regular folder.
一旦子模块的删除完成(deinit
和git rm
),您可以将文件夹重命名回其原始名称,并将其作为常规文件夹添加到 git 存储库中。
Note: if the submodule was created by an old Git (< 1.8), you might need to remove the nested .git
folder 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
.
回答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
git rm --cached the_submodule_path
- remove the submodule section from the
.gitmodules
file, or if it's the only submodule, remove the file. - do a commit "removed submodule xyz"
git add the_submodule_path
- another commit "added codebase of xyz"
git rm --cached the_submodule_path
- 从
.gitmodules
文件中删除子模块部分,或者如果它是唯一的子模块,则删除文件。 - 做一个提交“删除子模块xyz”
git add the_submodule_path
- 另一个提交“添加了 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.git
and 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 filename
you 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 .gitmodules
with 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 add
at the end has to use wildcards otherwise it will undo the previous rm
for the submodule itself. It's important to add the contentsof the submodule directory, and not to name the directory itself in the add
command.
根据VonC 的回答,我创建了一个简单的 bash 脚本来执行此操作。将add
在年底必须使用通配符否则将取消先前rm
的子模块本身。添加子模块目录的内容很重要,而不是在add
命令中命名目录本身。
In a file called git-integrate-submodule
:
在名为 的文件中git-integrate-submodule
: