问题:
是否有一种方法可以合并另一个仓库中的分支,但是该分支中的最新提交仅添加到了我们的提交历史中?
背景:
我们正在研究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的历史记录视图和基本{{1 }}输出。
我上一次进行合并-上图中的C-是作为壁球合并进行的,这给了我所有的更改,但只进行了一次提交。
不幸的是,在事实(我仍在学习git)之后,我意识到有效地切断了与上游提交的链接。因此,当我合并E时,通用的基本提交是A而不是C。就git而言,我已经独立完成了分支中B和C中的工作。我在B&C中修改了文件,然后在D&E中进一步修改了文件,从而产生成千上万的合并冲突。
非常感谢,我能够很容易地通过重新合并C,保留历史记录然后合并E来恢复。
但是,我回到了最初的问题。我希望能够将导致C的所有更改合并到我们的存储库中,但从本质上讲,只有C出现在我们存储库的提交历史记录中(当我合并E时用作通用基础)。有什么好方法吗?
感谢您的时间!
答案 0 :(得分:2)
简短的回答是:不,你不能那样做。您可以做一些可能就足够的事情。
历史不过是提交。提交是历史。
每个提交都有自己的唯一哈希ID。哈希ID 实际上是提交-尽管从技术上讲,它是该提交内容的加密校验和。内容包括保存的源快照的哈希ID,以及前一次提交的哈希ID。这就是允许Git从 last 提交开始并通过一系列提交来一次向后进行一次提交的原因:提交Z
具有父哈希Y
,因此Git可以找到Y
并发现它具有父哈希X
,依此类推。
合并提交是一种特殊的特殊方式:它们具有多个父哈希。 (通常,它们只有两个;一个以上的是
如您所见,git merge
通过遵循历史记录(向后看的提交链)回到共享提交来工作。您要么拥有提交,然后就可以共享它们;或您没有它们,因此无事可做。然后,对于普通的git merge
,它会进行合并提交,同时记住两个直接的前任,从而可以进行将来的合并。使用git merge --squash
可以剪切掉另一个父对象,这至少有可能,而且在实际中也是如此,这会使将来的合并变得更加困难,因为您要获得远古的祖先而不是所需的现代祖先。
通常,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将遵循合并的两条腿 *
,每次执行一次提交。但是您可以告诉它不要这样做:
git log --first-parent
此--first-parent
选项告诉Git,当它遇到上面的*
之类的合并提交时,它应该仅查看合并的 first 父级。
哪个父母 是第一父母?答案是:合并的第一个父对象是进行合并时 当前提交的提交。因此,在这种情况下,我们有:
o---------o-------o <-- branch (HEAD)
/
...--o--o
\
o--o--o--o--o--o--o <-- other
之前,您运行了git merge
。您已运行git checkout branch
进入此状态。然后,您运行git merge other
进行合并提交*
。因此,提交*
的第一父项是最上面一行的提交,即您运行git merge
时所处的那个。
因此,git log --first-parent
根本不会显示提交的最底行。它们将仍然存在,成为历史的一部分,使将来的合并能够正常工作,当然也可以使您的存储库更大,但是您不会看到。
大量git log
参数是关于看不到的特定提交:清除树木以便您可以看到森林。例如,git log --simplify-by-decoration
跳过显示不具有分支或标记名称的所有提交。使用git log [--follow] -- <path>
,您告诉Git不要显示不要更改给定文件或子树的提交。还有其他选择可以影响这种“历史简化”的工作方式,并且它们变得相当复杂。您可以花几天时间研究git log
手册页。但是从--first-parent
开始。
答案 1 :(得分:1)
是否有一种方法可以合并另一个仓库中的分支,但是该分支中的最新提交仅添加到了我们的提交历史中?
有很多方法可以做到这一点,但从完全意义上来说,却并非如此。抱歉,这听起来很尴尬,但我找不到更简单的方法:合并历史记录必然会合并您合并的历史记录。
因此,您可以将合并的历史记录修剪为仅所需的提交,或者将合并的历史记录的显示修剪为仅所需的提交。两者都是可行的,甚至都很容易。
要了解此处涉及多少实际回购膨胀,可以整理历史记录并比较结果;如所承诺的,这很容易:
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
这就是您所需要的。
答案 2 :(得分:-1)
假设您的上游分支称为上游分支,并且您希望将其合并到开发分支中:
git checkout development
git merge --squash upstream
git commit
这将从上游分支获取所有提交,将它们压缩为1个提交,然后将其与开发分支合并。