[英]How can I merge a branch from another repo without adding the branch's full commit history?
题:
有没有一种方法可以合并另一个仓库中的一个分支,但是只将该分支中的最新提交添加到我们的提交历史中?
背景:
我们正在从事UE4项目。 当Epic发布更新时,我们尝试更新到最新的引擎版本。 我们的工作流程是这样的:
dev: a - b -- c -- d -- e -- f -- g - h - i
/ / /
upstream: A (4.19) - B - C (4.20) - D - E (4.21) - F - G
注意,b和c代表几百次提交,而B通常代表几千次提交。 当我们将C合并到存储库中时,我们“获取”由B表示的所有提交。这些额外的提交使存储库膨胀,并在BitBucket的历史记录视图和基本git log
输出中与我们自己的提交交错显示。
上次我进行合并时(例如上图中的C),我以壁球合并的方式进行了合并,这给了我所有的更改,但只进行了一次提交。
不幸的是,在事实(我仍在学习git)之后,我意识到有效地切断了与上游提交的链接。 因此,当我合并E时,通用的基本提交是A而不是C。就git而言,我已经独立完成了分支中B和C中的工作。 我在B&C中修改了文件,然后在D&E中进一步修改了文件,产生了成千上万的合并冲突。
值得庆幸的是,通过合并C,保留历史记录然后合并E,我能够相当轻松地恢复。
但是,我回到了最初的问题。 我希望能够将导致C的所有更改合并到我们的存储库中,但从本质上讲,只有C出现在我们存储库的提交历史记录中(当我合并E时用作通用基础)。 有什么好方法吗?
谢谢你的时间!
简短的答案是:不,您不能这样做。 你可以做一些事情, 可能就足够了。
历史不过是承诺。 提交是历史。
每个提交都有自己的唯一哈希ID。 从本质上讲,该哈希ID 是提交,尽管从技术上讲,它是该提交内容的加密校验和。 内容包括保存的源快照的哈希ID,以及前一次提交的哈希ID。 这就是让Git从最后一次提交开始并向后工作的一次,通过一系列提交:一次提交Z
具有父哈希Y
,因此Git可以找到Y
并看到它具有父哈希X
,等等上。
合并提交的一种特殊方式是特殊的:它们具有多个父哈希。 (通常它们只有两个;一个章鱼合并超过两个,这些并没有真正实现无法通过多个单独的合并完成的任何事情,尽管它们对于表明合并的目标是将一个一堆修订同时进行,当然是为了炫耀自己的Git-fu。:-))在合并提交时, 除非您不告诉 Git, 否则 Git将遵循两种历史(请参见下文)。
如您所见, git merge
通过遵循历史记录(向后看的提交链)回到共享提交来工作。 您要么拥有提交,然后就可以共享它们; 或您没有它们,因此无事可做。 然后,对于普通的git merge
,它将进行合并提交,同时记住两个直接的前任,从而可以进行将来的合并。 使用git merge --squash
附加的父对象,这至少有可能,而且在实践中也是如此,这会使将来的合并变得更加困难,因为您要获得古老的祖先而不是所需的现代祖先。
通常, git log
通过向后遍历提交图来一次跟踪历史git log
所有历史记录):
...--o--o--o--o <-- branch (HEAD)
如果历史记录是线性的(没有合并),则工作正常,但有合并时:
o---------o-------o
/ \
...--o--o *--o--o <-- branch (HEAD)
\ /
o--o--o--o--o--o--o
Git将遵循merge *
两条腿 ,它会一次提交一次。 但是您可以告诉它不要这样做 :
git log --first-parent
这个--first-parent
选项告诉Git,当它遇到合并提交(例如上面的*
,它应该仅查看合并的第一个父对象。
哪个父母是第一父母? 答案是:合并的第一父提交,这是 目前的承诺,当你做了合并。 因此,在这种情况下,我们有:
o---------o-------o <-- branch (HEAD)
/
...--o--o
\
o--o--o--o--o--o--o <-- other
在您运行git merge
之前 。 您已经运行git checkout branch
进入此状态。 然后,您运行git merge other
进行合并提交*
。 因此,commit *
的第一个父级是最上面一行的提交,即您运行git merge
时所在的提交。
因此, git log --first-parent
根本不会显示提交的最底行。 它们仍将存在,成为历史的一部分,使将来的合并能够正常工作,当然也使您的存储库更大,但是您不会看到它们。
大量的git log
参数是关于看不到特定的提交的:清除树以使您可以看到森林。 例如, git log --simplify-by-decoration
跳过以显示没有分支或标记名称的所有提交。 使用git log [--follow] -- <path>
,告诉Git不要显示不会更改给定文件或子树的提交。 还有其他选择可以影响这种“历史简化”的工作方式,并且它们变得相当复杂。 您可以研究git log
手册页数天。 但是从--first-parent
开始。
有没有一种方法可以合并另一个仓库中的一个分支,但是只将该分支中的最新提交添加到我们的提交历史中?
有很多方法可以做到这一点,但从根本上讲,还不能完全掩饰自己。 抱歉,这听起来很尴尬,但是我找不到简单的表达方式:合并历史记录必然会合并您合并的历史记录。
因此,您可以将合并的历史记录修剪为仅所需的提交,或者将合并的历史记录的显示修剪为仅所需的提交。 两者都是可行的,甚至很容易。
要发现此处涉及多少实际回购膨胀,可以整理历史记录并比较结果。 如所承诺的,这很容易:
git clone --bare . --single-branch --branch upstream `mktemp -d`
cd $_
而简单的du -sh
为您的上游分支在回购中占用多少空间提供合理的基准。
要将历史记录仅突出显示,您可以
git filter-branch --tag-name-filter 's,^,sliced-,' -- upstream --simplify-by-decoration
git clone --no-hardlinks --bare . --single-branch --branch upstream `mktemp -d`
cd $_
du -sh
并查看可以节省多少回购空间。 我在Git分支上运行了该程序,其中703个标记了提交,约55K个提交。 它节省了100MB的磁盘空间。 我的屏幕快照目录所花费的资源不止于此。 Git签出花费了三倍。
如果重要的只是使您的git log
显示杂乱无章,则无需执行任何操作。 在您的仓库中
mkdir .git/info
git rev-list upstream --parents --simplify-by-decoration >.git/info/grafts
这就是您所需要的。
假设您的上游分支称为上游,您想将其合并到开发分支中:
git checkout development
git merge --squash upstream
git commit
这将从上游分支获取所有提交,将它们压缩为1个提交,并将其与您的开发分支合并。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.