我在一个名为XXX的文件夹中有一个Git存储库,还有一个名为YYY的Git存储库。
我想将XXX存储库作为名为ZZZ的子目录导入到YYY存储库中,并将所有XXX的更改历史添加到YYY中。
之前的文件夹结构:
├── XXX
│ ├── .git
│ └── (project files)
└── YYY
├── .git
└── (project files)
文件夹结构后:
YYY
├── .git <-- This now contains the change history from XXX
├── ZZZ <-- This was originally XXX
│ └── (project files)
└── (project files)
这可以做到吗,或者我必须使用子模块?
添加另一个答案,因为我认为这有点简单。将repo_dest拉入到repo_to_import中,然后推入——set-upstream url:repo_dest master。
这种方法对我来说很有效,我把几个较小的回购导入一个较大的回购中。
如何将repo1_to_import导入到repo_dest
# checkout your repo1_to_import if you don't have it already
git clone url:repo1_to_import repo1_to_import
cd repo1_to_import
# now. pull all of repo_dest
git pull url:repo_dest
ls
git status # shows Your branch is ahead of 'origin/master' by xx commits.
# now push to repo_dest
git push --set-upstream url:repo_dest master
# repeat for other repositories you want to import
重命名或移动文件和dirs到原始回购所需的位置,然后再进行导入。如。
cd repo1_to_import
mkdir topDir
git add topDir
git mv this that and the other topDir/
git commit -m"move things into topDir in preparation for exporting into new repo"
# now do the pull and push to import
以下链接中描述的方法启发了这个答案。我喜欢它,因为它看起来更简单。但是要小心!有龙!https://help.github.com/articles/importing-an-external-git-repository git push——镜像url:repo_dest将本地的回购历史和状态推送到远程(url:repo_dest)。但是它会删除旧的历史记录和远程状态。乐趣随之而来!: - e
Git-subtree正是为这样的用例设计的脚本:将多个存储库合并为一个,同时保留历史(和/或分割子树的历史,尽管这似乎与这个问题无关)。从1.7.11版开始,它作为git树的一部分发布。
要合并一个<repo> at revision <rev> as subdirectory <prefix>的仓库,使用git子树add,如下所示:
git subtree add -P <prefix> <repo> <rev>
Git-subtree以一种更用户友好的方式实现子树合并策略。
对于您的情况,在存储库YYY中,您将运行:
git subtree add -P ZZZ /path/to/XXX.git master
缺点是在合并的历史中文件没有前缀(不在子目录中)。因此,git log ZZZ/a会显示除了合并历史之外的所有更改(如果有的话)。你可以:
git log --follow -- a
但这不会显示合并历史中其他的变化。
换句话说,如果不更改存储库XXX中的ZZZ文件,则需要指定——follow和一个无前缀路径。如果在两个存储库中都更改它们,则有两个命令,其中没有一个显示所有更改。
这里有更多。
如果您希望保留第二个存储库的确切提交历史,并因此保留将来轻松合并上游更改的能力,那么下面是您想要的方法。它会导致子树的未修改历史被导入到repo中,再加上一个合并提交,将合并的存储库移动到子目录中。
git remote add XXX_remote <path-or-url-to-XXX-repo>
git fetch XXX_remote
git merge -s ours --no-commit --allow-unrelated-histories XXX_remote/master
git read-tree --prefix=ZZZ/ -u XXX_remote/master
git commit -m "Imported XXX as a subtree."
你可以像这样跟踪上游的变化:
git pull -s subtree XXX_remote master
在进行合并之前,Git会自己计算出根的位置,因此您不需要在后续的合并中指定前缀。
缺点是在合并的历史中文件没有前缀(不在子目录中)。因此,git log ZZZ/a会显示除了合并历史之外的所有更改(如果有的话)。你可以:
git log --follow -- a
但这不会显示合并历史中其他的变化。
换句话说,如果不更改存储库XXX中的ZZZ文件,则需要指定——follow和一个无前缀路径。如果在两个存储库中都更改它们,则有两个命令,其中没有一个显示所有更改。
2.9之前的Git版本:你不需要给Git merge传递——allow-unrelated-histories选项。
另一个答案中的方法使用read-tree并跳过merge -s ours步骤,实际上与使用cp复制文件并提交结果没有什么不同。
原始来源来自github的“子树合并”帮助文章。这是另一个有用的链接。
我当时在找-s他们的,当然,这个策略不存在。我的历史是我在GitHub上分叉了一个项目,现在由于某种原因,我的本地master不能与上游/master合并,尽管我没有对这个分支做任何本地更改。(真的不知道那里发生了什么——我猜上游在幕后做了一些肮脏的推动,可能吧?)
我最后做的是
# as per https://help.github.com/articles/syncing-a-fork/
git fetch upstream
git checkout master
git merge upstream/master
....
# Lots of conflicts, ended up just abandonging this approach
git reset --hard # Ditch failed merge
git checkout upstream/master
# Now in detached state
git branch -d master # !
git checkout -b master # create new master from upstream/master
所以现在我的master再次与upstream/master同步(你可以对任何其他分支重复上面的步骤,你也想进行类似的同步)。
简单的方法是使用git format-patch。
假设我们有两个git存储库foo和bar。
foo包含:
福.txt
。去
栏包含:
酒吧.txt
。去
我们希望以foo结束,其中包含bar历史记录和这些文件:
foo . txt。
git。
雷丁酒吧。. txt。
要做到这一点:
1. create a temporary directory eg PATH_YOU_WANT/patch-bar
2. go in bar directory
3. git format-patch --root HEAD --no-stat -o PATH_YOU_WANT/patch-bar --src-prefix=a/foobar/ --dst-prefix=b/foobar/
4. go in foo directory
5. git am PATH_YOU_WANT/patch-bar/*
如果我们想重写所有从bar提交的消息,我们可以这样做,例如在Linux上:
git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD
这将在每条提交消息的开头添加“[bar]”。
根据这篇文章,使用子树对我来说是有效的,只转移了适用的历史。在这里发布,以防有人需要这些步骤(确保将占位符替换为适用于你的值):
在源存储库中将子文件夹拆分为一个新的分支
Git子树拆分——prefix=<source-path-to-merge> -b subtree-split-result
在你的目标repo合并在拆分结果分支
git remote add merge-source-repo <path-to-your-source-repository>
git fetch merge-source-repo
git merge -s ours --no-commit merge-source-repo/subtree-split-result
git read-tree --prefix=<destination-path-to-merge-into> -u merge-source-repo/subtree-split-result
验证您的更改并提交
git status
git commit
别忘了
通过删除子树拆分结果分支进行清理
git branch -D subtree-split-result
删除为从源repo获取数据而添加的远程
Git远程rm merge-source-repo