如何将现有的 Git 存储库导入到另一个存储库中?
我在名为 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)
可以这样做吗,或者我必须求助于使用子模块吗?
I have a Git repository in a folder called XXX, and I have second Git repository called YYY.
I want to import the XXX repository into the YYY repository as a subdirectory named ZZZ and add all XXX's change history to YYY.
Folder structure before:
├── XXX
│ ├── .git
│ └── (project files)
└── YYY
├── .git
└── (project files)
Folder structure after:
YYY
├── .git <-- This now contains the change history from XXX
├── ZZZ <-- This was originally XXX
│ └── (project files)
└── (project files)
Can this be done, or must I resort to using sub-modules?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
这是立即生效的脚本。
运行脚本。转到您想要合并其他存储库的存储库,然后运行脚本。
现在将 master 分支上的更改推送到远程/原点。根据您想要执行的操作,可能不需要执行此步骤。
Here is the script that will work right off the bat.
To run the script. Go to the repo where you want the other repo to be merged, and run the script.
Now push the changes on the master branch to remote/origin. This step may not be required depending on what you are trying to do.
在我的例子中,我只想从其他存储库(XXX)导入一些文件。子树对我来说太复杂了,其他解决方案不起作用。这就是我所做的:
这为您提供了一个以空格分隔的所有提交列表,这些提交影响我想要以相反顺序导入的文件(ZZZ)(您可能还需要添加 --follow 来捕获重命名)。然后我进入目标存储库(YYY),将另一个存储库(XXX)添加为远程存储库,从中进行提取,最后:
将所有提交添加到您的分支,因此您将拥有所有文件及其历史记录和可以对它们做任何您想做的事情,就像它们一直在这个存储库中一样。
I wanted to import only some files from the other repository (XXX) in my case. The subtree was too complicated for me and the other solutions didn't work. This is what I did:
This gives you a space-separated list of all the commits that affect the files I wanted to import (ZZZ) in reverse order (you might have to add --follow to capture renames as well). I then went into the target repository (YYY), added the other repository (XXX) as remote, did a fetch from it and finally:
which adds all the commits to your branch, you'll thus have all the files with their history and can do whatever you want with them as if they've always been in this repository.
请参阅本文中的基本示例< /a> 并考虑存储库上的此类映射:
A
<->YYY
,B
<->XXX
在本章描述的所有活动之后(合并后),删除分支
B-master
:然后,推送更改。
这对我有用。
See Basic example in this article and consider such mapping on repositories:
A
<->YYY
,B
<->XXX
After all activity described in this chapter (after merging), remove branch
B-master
:Then, push changes.
It works for me.
我当时的情况是在寻找
-s thoses
但当然,这种策略不存在。我的历史是,我在 GitHub 上分叉了一个项目,现在由于某种原因,我的本地master
无法与upstream/master
合并,尽管我没有进行本地更改到这个分支。 (真的不知道那里发生了什么——我猜上游可能在幕后做了一些肮脏的推动?)我最终做的是
所以现在我的
master
再次与同步>upstream/master
(您可以对您也想类似同步的任何其他分支重复上述操作)。I was in a situation where I was looking for
-s theirs
but of course, this strategy doesn't exist. My history was that I had forked a project on GitHub, and now for some reason, my localmaster
could not be merged withupstream/master
although I had made no local changes to this branch. (Really don't know what happened there -- I guess upstream had done some dirty pushes behind the scenes, maybe?)What I ended up doing was
So now my
master
is again in sync withupstream/master
(and you could repeat the above for any other branch you also want to sync similarly).我可以建议另一个解决方案(替代 git-submodules)针对您的问题 - gil(git 链接)工具
它允许描述和管理复杂的 git 存储库依赖项。
它还提供了 git 递归子模块依赖问题的解决方案。
考虑您有以下项目依赖项:
示例 git 存储库依赖关系图
然后您可以使用以下命令定义
.gitlinks
文件存储库关系描述:每行描述 git 链接,格式如下:
存储库分支到 checkout
最后,您必须更新根示例存储库:
因此,您将克隆所有必需的项目并以正确的方式将它们相互链接。
如果您想提交某个存储库中的所有更改以及子链接存储库中的所有更改,您可以使用单个命令来完成:
拉取,推送命令的工作方式类似:
Gil(git links)工具支持以下命令:
更多关于< a href="https://github.com/chronoxor/gil#recursive-submodules-problem" rel="nofollow noreferrer">git 递归子模块依赖问题。
I can suggest another solution (alternative to git-submodules) for your problem - gil (git links) tool
It allows to describe and manage complex git repositories dependencies.
Also it provides a solution to the git recursive submodules dependency problem.
Consider you have the following project dependencies:
sample git repository dependency graph
Then you can define
.gitlinks
file with repositories relation description:Each line describe git link in the following format:
Repository branch to checkout
Finally you have to update your root sample repository:
As the result you'll clone all required projects and link them to each other in a proper way.
If you want to commit all changes in some repository with all changes in child linked repositories you can do it with a single command:
Pull, push commands works in a similar way:
Gil (git links) tool supports the following commands:
More about git recursive submodules dependency problem.
没有足够的代表来为 x-yuri 的答案添加评论,但它工作得很好并且保留了历史。
我正在使用两个工作本地存储库并收到此错误:
我没有担心
--force
标志的含义,而是首先使用以下命令在本地克隆存储库:并将这个新克隆的副本用于 x-yuri 列出的一系列命令。
最后,在:
git filter-repo --to-subdirectory-filter a
中,a
是您为要导入的存储库的根文件夹指定的名称。Don't have enough rep to add a comment to x-yuri's answer, but it works beautifully and preserves history.
I was working with two working local repo's and received this error:
Rather than worry about the implications of the
--force
flag, I cloned the repo locally first with:and used this freshly cloned copy for the series of commands that x-yuri laid out.
Lastly, in:
git filter-repo --to-subdirectory-filter a
,a
is the name you are giving to the root folder for the repo that you will be importing.我不知道有什么简单的方法可以做到这一点。您可以这样做:
如果听起来很吸引人,我可以编辑细节。
I don't know of an easy way to do that. You COULD do this:
I can edit with details if that sounds appealing.
我认为你可以使用“git mv”和“git pull”来做到这一点。
我是一个公平的 git noob - 所以要小心你的主存储库 - 但我只是在临时目录中尝试过这个,它似乎有效。
首先 - 重命名 XXX 的结构,以匹配您希望它在 YYY 中的外观:
现在 XXX 看起来像这样:
现在使用“git pull”来获取更改:
现在 YYY 看起来像这样:
I think you can do this using 'git mv' and 'git pull'.
I'm a fair git noob - so be careful with your main repository - but I just tried this in a temp dir and it seems to work.
First - rename the structure of XXX to match how you want it to look when it's within YYY:
Now XXX looks like this:
Now use 'git pull' to fetch the changes across:
Now YYY looks like this:
可能最简单的方法是将 XXX 内容拉入 YYY 中的分支,然后将其合并到 master 中:
在 YYY 中:
我实际上只是用我的几个存储库尝试过这个,它有效。与 Jörg 的答案不同,它不会让您继续使用其他存储库,但我认为您无论如何都没有指定这一点。
注意:由于本文最初是在 2009 年编写的,因此 git 添加了下面答案中提到的子树合并。我今天可能会使用这个方法,当然这个方法仍然有效。
Probably the simplest way would be to pull the XXX stuff into a branch in YYY and then merge it into master:
In YYY:
I actually just tried this with a couple of my repos and it works. Unlike Jörg's answer it won't let you continue to use the other repo, but I don't think you specified that anyway.
Note: Since this was originally written in 2009, git has added the subtree merge mentioned in the answer below. I would probably use that method today, although of course this method does still work.
如果您想保留第二个存储库的确切提交历史记录,并因此保留将来轻松合并上游更改的能力,那么这就是您想要的方法。它会导致子树的未修改历史记录被导入到您的存储库中,再加上一次合并提交以将合并的存储库移至子目录。
您可以像这样跟踪上游更改:
Git 在进行合并之前自行计算出根在哪里,因此您无需在后续合并中指定前缀。
缺点是,在合并的历史记录中,文件没有前缀(不在子目录中)。因此,
git log ZZZ/a
将向您显示除合并历史记录之外的所有更改(如果有)。您可以这样做:但这不会显示合并历史记录中的其他更改。
换句话说,如果您不更改存储库
XXX
中ZZZ
的文件,那么您需要指定--follow
和一个不带前缀的小路。如果您在两个存储库中更改它们,那么您有 2 个命令,其中没有一个命令显示所有更改。2.9 之前的 Git 版本:您不需要将
--allow-unlated-histories
选项传递给git merge
。另一个答案中使用 read-tree 并跳过 merge -s ours 步骤的方法实际上与使用 cp 复制文件并提交结果没有什么不同。
原始来源来自 github 的“子树合并”帮助文章。还有另一个有用的链接。
If you want to retain the exact commit history of the second repository and therefore also retain the ability to easily merge upstream changes in the future then here is the method you want. It results in unmodified history of the subtree being imported into your repo plus one merge commit to move the merged repository to the subdirectory.
You can track upstream changes like so:
Git figures out on its own where the roots are before doing the merge, so you don't need to specify the prefix on subsequent merges.
The downside is that in the merged history the files are unprefixed (not in a subdirectory). As a result
git log ZZZ/a
will show you all the changes (if any) except those in the merged history. You can do:but that won't show the changes other then in the merged history.
In other words, if you don't change
ZZZ
's files in repositoryXXX
, then you need to specify--follow
and an unprefixed path. If you change them in both repositories, then you have 2 commands, none of which shows all the changes.Git versions before 2.9: You don’t need to pass the
--allow-unrelated-histories
option togit merge
.The method in the other answer that uses
read-tree
and skips themerge -s ours
step is effectively no different than copying the files with cp and committing the result.Original source was from github's "Subtree Merge" help article. And another useful link.
git-subtree
是一个专门针对将多个存储库合并为一个同时保留历史记录(和/或分割子树历史记录,尽管这似乎与这个问题无关)的用例而设计的脚本。自 1.7.11 版本起,它作为 git 树的一部分发布。要将版本
处的存储库
合并为子目录
,请使用git subtree add< /code> 如下:
git-subtree 实现 子树以更加用户友好的方式合并策略。
对于您的情况,在存储库 YYY 内,您将运行:
缺点是在合并的历史记录中,文件没有前缀(不在子目录中)。因此,
git log ZZZ/a
将向您显示除合并历史记录之外的所有更改(如果有)。您可以这样做:但这不会显示合并历史记录中的其他更改。
换句话说,如果您不更改存储库
XXX
中ZZZ
的文件,那么您需要指定--follow
和一个不带前缀的小路。如果您在两个存储库中更改它们,那么您有 2 个命令,其中没有一个命令显示所有更改。更多信息请此处。
git-subtree
is a script designed for exactly this use case of merging multiple repositories into one while preserving history (and/or splitting history of subtrees, though that seems to be irrelevant to this question). It is distributed as part of the git tree since release 1.7.11.To merge a repository
<repo>
at revision<rev>
as subdirectory<prefix>
, usegit subtree add
as follows:git-subtree implements the subtree merge strategy in a more user friendly manner.
For your case, inside repository YYY, you would run:
The downside is that in the merged history the files are unprefixed (not in a subdirectory). As a result
git log ZZZ/a
will show you all the changes (if any) except those in the merged history. You can do:but that won't show the changes other then in the merged history.
In other words, if you don't change
ZZZ
's files in repositoryXXX
, then you need to specify--follow
and an unprefixed path. If you change them in both repositories, then you have 2 commands, none of which shows all the changes.More on it here.
Git 存储库本身有一个众所周知的实例,它在 Git 社区中统称为“有史以来最酷的合并"(在发送给 Git 的电子邮件中使用的主题行 Linus Torvalds 之后)描述此合并的邮件列表)。在这种情况下,gitk Git GUI 现在是 Git 本身的一部分,实际上曾经是一个单独的项目。 Linus 设法将该存储库合并到 Git 存储库中,其方式
git pull
编辑即可。该电子邮件包含重现所需的步骤,但它不适合胆小的人:首先,Linus 编写了 Git,所以他可能比你或我更了解它,其次,这几乎是 5 年前的事了,从那时起,Git 已经有了很大的改进,所以也许现在更容易了。
特别是,我想现在在这种特定情况下人们会使用 gitk 子模块。
There is a well-known instance of this in the Git repository itself, which is collectively known in the Git community as "the coolest merge ever" (after the subject line Linus Torvalds used in the e-mail to the Git mailinglist which describes this merge). In this case, the
gitk
Git GUI which now is part of Git proper, actually used to be a separate project. Linus managed to merge that repository into the Git repository in a way thatgit pull
ed.The e-mail contains the steps needed to reproduce, but it is not for the faint of heart: first, Linus wrote Git, so he probably knows a bit more about it than you or me, and second, this was almost 5 years ago and Git has improved considerably since then, so maybe it is now much easier.
In particular, I guess nowadays one would use a gitk submodule, in that specific case.
让我使用名称
a
(代替XXX
和ZZZ
)和b
(代替YYY
),因为这使得描述更容易阅读。假设您想要将存储库
a
合并到b
(我假设它们彼此相邻):为此,您需要
git-filter-repo
已安装(filter-branch
是 不鼓励)。合并 2 个大存储库,将其中一个存储库放入子目录的示例: https://gist.github .com/x-yuri/9890ab1079cf4357d6f269d073fd9731
更多信息此处。
Let me use names
a
(in place ofXXX
andZZZ
) andb
(in place ofYYY
), since that makes the description a bit easier to read.Say you want to merge repository
a
intob
(I'm assuming they're located alongside one another):For this you need
git-filter-repo
installed (filter-branch
is discouraged).An example of merging 2 big repositories, putting one of them into a subdirectory: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731
More on it here.
最简单的方法是使用 git format-patch。
假设我们有 2 个 git 存储库 foo 和 bar。
foo 包含:
bar 包含:
我们希望最终 foo 包含 >bar 历史记录和这些文件:
所以要这样做:
如果我们想重写 bar 的所有消息提交,我们可以这样做,例如在 Linux 上:
这将添加“[ bar] " 在每个提交消息的开头。
The simple way to do that is to use git format-patch.
Assume we have 2 git repositories foo and bar.
foo contains:
bar contains:
and we want to end-up with foo containing the bar history and these files:
So to do that:
And if we want to rewrite all message commits from bar we can do, eg on Linux:
This will add "[bar] " at the beginning of each commit message.
该功能将远程仓库克隆到本地仓库目录,合并后所有提交将被保存,
git log
将显示原始提交和正确的路径:如何使用:
如果做一点更改,您甚至可以将合并的存储库的文件/目录移动到不同的路径,例如:
通知
路径通过
sed
替换,因此请确保合并后它移动到正确的路径中。--allow-unlated-histories
参数仅自 git >= 2.9 起存在。This function will clone remote repo into local repo dir, after merging all commits will be saved,
git log
will be show the original commits and proper paths:How to use:
If make a little changes you can even move files/dirs of merged repo into different paths, for example:
Notices
Paths replaces via
sed
, so make sure it moved in proper paths after merging.The
--allow-unrelated-histories
parameter only exists since git >= 2.9.基于本文,使用子树对我有用,并且只传输了适用的历史记录。如果有人需要这些步骤,请在此处发布(请确保将占位符替换为适用于您的值):
在源存储库中将子文件夹拆分为新分支
git subtree split --prefix=-b subtree-split-result
目标存储库中的合并拆分结果分支
验证您的更改并提交
不要忘记
通过删除
subtree-split-result
分支进行清理< code>gitbranch -D subtree-split-result
删除您添加的用于从源存储库获取数据的远程
git remote rm merge-source-repo
Based on this article, using subtree is what worked for me and only applicable history was transferred. Posting here in case anyone needs the steps (make sure to replace the placeholders with values applicable to you):
in your source repository split subfolder into a new branch
git subtree split --prefix=<source-path-to-merge> -b subtree-split-result
in your destination repo merge in the split result branch
verify your changes and commit
Don't forget to
Clean up by deleting the
subtree-split-result
branchgit branch -D subtree-split-result
Remove the remote you added to fetch the data from source repo
git remote rm merge-source-repo
添加另一个答案,因为我认为这更简单一些。将 repo_dest 拉取到 repo_to_import 中,然后完成推送 --set-upstream url:repo_dest master 。
这种方法对我来说很有效,可以将几个较小的存储库导入到一个较大的存储库中。
如何导入:repo1_to_import 到 repo_dest 在
导入之前重命名或将文件和目录移动到原始存储库中的所需位置。例如,
以下链接中描述的方法启发了这个答案。我喜欢它,因为它看起来更简单。但要小心!那里有龙! https://help.github.com/articles/importing-an-external -git-repository
git push --mirror url:repo_dest
将本地存储库历史记录和状态推送到远程 (url:repo_dest)。但它会删除遥控器的旧历史记录和状态。乐趣随之而来! :-EAdding another answer as I think this is a bit simpler. A pull of repo_dest is done into repo_to_import and then a push --set-upstream url:repo_dest master is done.
This method has worked for me importing several smaller repos into a bigger one.
How to import: repo1_to_import to repo_dest
Rename or move files and dirs into desired position in original repo before you do the import. e.g.
The method described at the following link inspired this answer. I liked it as it seemed more simple. BUT Beware! There be dragons! https://help.github.com/articles/importing-an-external-git-repository
git push --mirror url:repo_dest
pushes your local repo history and state to remote (url:repo_dest). BUT it deletes the old history and state of the remote. Fun ensues! :-E