考虑以下场景:
我在自己的Git repo中开发了一个小型实验项目a。它现在已经成熟,我希望A成为更大的项目B的一部分,该项目有自己的大仓库。现在我想将A添加为B的子目录。
我如何将A合并为B,而不丢失任何方面的历史?
考虑以下场景:
我在自己的Git repo中开发了一个小型实验项目a。它现在已经成熟,我希望A成为更大的项目B的一部分,该项目有自己的大仓库。现在我想将A添加为B的子目录。
我如何将A合并为B,而不丢失任何方面的历史?
当前回答
当您希望在一次提交中合并三个或更多项目时,请执行其他答案中所述的步骤(远程添加-f,合并)。然后,(软)将索引重置为旧头(没有合并)。添加所有文件(git-Add-A)并提交它们(消息“将项目A、B、C和D合并到一个项目中”)。这现在是master的提交id。
现在,使用以下内容创建.git/info/places:
<commit-id of master> <list of commit ids of all parents>
运行gitfilter分支--head^。。头头^2.头头^3.头。如果你有三个以上的分支,就加上同样多的头。。当你有树枝的时候,就把头伸过去。要更新标记,请追加--tag-namefilter cat。不要总是添加,因为这可能会导致某些提交的重写。有关详细信息,请参阅过滤器分支的手册页,搜索“移植物”。
现在,你的最后一次承诺与正确的父母相关。
其他回答
如果两个存储库都有相同类型的文件(就像两个Rails存储库用于不同的项目),您可以将辅助存储库的数据提取到当前存储库中:
git fetch git://repository.url/repo.git master:branch_name
然后将其合并到当前存储库:
git merge --allow-unrelated-histories branch_name
如果您的Git版本小于2.9,请删除--允许不相关的历史记录。
在此之后,可能会发生冲突。例如,可以使用gitmergetool来解析它们。kdiff3只能与键盘一起使用,因此在读取代码时仅需几分钟,就会产生5个冲突文件。
记住完成合并:
git commit
与@Smar类似,但使用在PRIMARY和SECONDARY中设置的文件系统路径:
PRIMARY=~/Code/project1
SECONDARY=~/Code/project2
cd $PRIMARY
git remote add test $SECONDARY && git fetch test
git merge test/master
然后手动合并。
(改编自阿纳尔·马纳福夫的帖子)
我遇到了类似的挑战,但在我的情况下,我们在回购协议a中开发了一个版本的代码库,然后将其克隆到新的回购协议B中,用于新版本的产品。修复了回购协议A中的一些错误后,我们需要将更改FI到回购协议B中
向指向回购a的回购B添加远程(git remote add…)拉动当前分支(我们没有使用master修复错误)(git pull-remoteForRepabugFixBranch)将合并推送到github
工作愉快:)
我在使用merge时不断丢失历史记录,所以我最终使用了rebase,因为在我的情况下,两个存储库的不同程度足以避免每次提交时合并:
git clone git@gitorious/projA.git projA
git clone git@gitorious/projB.git projB
cd projB
git remote add projA ../projA/
git fetch projA
git rebase projA/master HEAD
=>解决冲突,然后根据需要继续。。。
git rebase --continue
这样做会导致一个项目具有来自projA的所有提交,然后是来自projB的提交
如果您想将来自存储库B分支的文件放在存储库a的子树中,并保留历史记录,请继续阅读。(在下面的示例中,我假设我们希望回购协议B的主分支合并为回购协议A的主分支。)
在回购协议A中,首先执行以下操作以使回购协议B可用:
git remote add B ../B # Add repo B as a new remote.
git fetch B
现在我们在回购a中创建了一个全新的分支(只有一个提交),我们称之为new_b_root。生成的提交将包含在repo B的主分支的第一次提交中提交的文件,但这些文件放在名为path/to/B-files/的子目录中。
git checkout --orphan new_b_root master
git rm -rf . # Remove all files.
git cherry-pick -n `git rev-list --max-parents=0 B/master`
mkdir -p path/to/b-files
git mv README path/to/b-files/
git commit --date="$(git log --format='%ai' $(git rev-list --max-parents=0 B/master))"
解释:checkout命令的--孤儿选项从A的主分支检出文件,但不创建任何提交。我们可以选择任何提交,因为接下来我们无论如何都要清除所有文件。然后,在尚未提交(-n)的情况下,我们从B的主分支中选择第一个提交。(cherry pick保留了原始的提交消息,而直接签出似乎无法做到这一点。)然后我们创建一个子树,将所有来自repo B的文件放在那里。然后我们必须将cherry stick中引入的所有文件移动到子树中。在上面的示例中,只有一个README文件可以移动。然后我们提交B-repo根提交,同时,我们还保留原始提交的时间戳。
现在,我们将在新创建的new_B_root上创建一个新的B/master分支。我们称新分支为b:
git checkout -b b B/master
git rebase -s recursive -Xsubtree=path/to/b-files/ new_b_root
现在,我们将b分支合并为A/master:
git checkout master
git merge --allow-unrelated-histories --no-commit b
git commit -m 'Merge repo B into repo A.'
最后,您可以删除B个远程和临时分支:
git remote remove B
git branch -D new_b_root b
最终图形的结构如下: