我有一个使用 GitFlow 的git存储库(即,它具有master
,develop
,release-*
和feature-*
分支)。但是,协作者尚未使用显式合并(即git merge --no-ff
),例如git log --first-parent
没有提供到目前为止的合并历史记录的简单汇总。
向前迈进,合作者将使用显式合并。但是,在执行此操作之前,我想确保历史记录是“干净的”,以便在调用git log --first-parent
时不会显示以前的历史记录。但是,显然,我想在调用未过滤的git log
时保持 actual 提交历史。
我的意愿是执行以下操作:
$ git checkout develop
$ git checkout --orphan CleanSlate
$ git rm . -r -f
$ git commit --allow-empty -m "Establish a clean slate for the develop branch"
$ git merge --no-ff --allow-unrelated-histories develop -m "Introduce all legacy files"
$ git checkout develop
$ git merge CleanSlate
基本上,我们的想法是:
--orphan
)分支--no-ff
分支执行显式合并(即develop
),并确认不相关的历史记录develop
到我们刚刚执行的显式合并,以表示历史记录我的问题:在将这种方法应用于生产环境之前,应该注意这种方法的后果吗?是否存在替代或更简单的方法来实现这种情况?
(在测试中,这似乎实现了我的目标,而对现有分支或工作流没有不利影响。但是,使用git时,我总是对不知道的东西保持警惕。)
答案 0 :(得分:2)
我想我在这里理解了这个主意。
让我们一步一步地画出实际发生的情况。出于初始绘图的目的,假设分支develop
终止于普通提交D
:
...--B--C--D <-- develop
第一个命令似乎并不相关;第二个将我们带入一个未出生的(“孤立”)分支,第三个将索引和工作树清空:
$ git checkout develop $ git checkout --orphan CleanSlate $ git rm . -r -f
使第四个命令创建一个没有父项的空提交E
:
$ git commit --allow-empty -m "Establish a clean slate for the develop branch"
为我们提供了这张图:
E <-- CleanSlate (HEAD)
...--B--C--D <-- develop
现在:
$ git merge --no-ff --allow-unrelated-histories develop -m "Introduce all legacy files"
merge命令进行新的合并提交;从逻辑上讲,F
是下一个字母,但我陷入了诱惑,在这里将其称为M
:
E--M <-- CleanSlate (HEAD)
/
...--B--C--D <-- develop
重要的是,M
的 first 父级是空的提交E
。 M
的 second 父级是提交D
。因此,回到git log --first-parent
的未来M
将到达E
,然后停下来。
最后两个命令将HEAD
附加到develop
并移动develop
指向M
:
$ git checkout develop $ git merge CleanSlate
给予:
E--M <-- develop (HEAD), CleanSlate
/
...--B--C--D
(您现在可以安全删除名称CleanSlate
。)
考虑此食谱(未经测试,但在发布之前我再次盯着它,看起来不错):
et=$(git hash-object -t tree /dev/null)
e=$(git commit-tree -m "dummy empty commit at which --first-parent stops" $et)
m=$(git commit-tree -p $e -p develop -m "begin strict no-ff merges" develop^{tree})
git checkout -B develop $m
使用两个-p
(提交的父对象)参数,我们按照喜欢的顺序选择合并提交M
的父哈希:第一个-p
是被跟踪的父对象git log --first-parent
和第二个-p
是第二个父级,它使M
成为合并提交。
存储在两个新提交中的实际树(或快照)是$et
(empty tree)和develop^{tree}
(提交快照)中的D
)。现在,您可以根据需要轻松地选择使提交E
与D
共享树。
最后一个git checkout -B develop
使Git切换到提交M
并指向名称develop
。这是一个快速合并的事实,意味着您可以使用:
git checkout develop; git merge --ff-only $m
但是用一个更晦涩的命令来做到这一点。 ?注意:由于提交E
和M
在保护develop
之前没有保护它们的 name ,因此您必须在提交后的14天内完成最后一步开始该过程,以确保Git的垃圾收集器不会删除它们。
两种方法的结果相同。 Git的大部分内容与 commits 及其形成的图形有关。剩下的大部分是关于在遍历图表时使用名称(分支和/或标签名称和/或其他名称)来入门的。