我有一个仓库,它有很多很多分支,这些分支已经通过github PR进行了rebase合并。即使合并分支到master
是一个快速的过程,github也坚持做一个真正的rebase(将按下"合并"按钮的人作为所有提交的作者)。
我剩下的是这样的:
* (E) [master]
|
* (D')
|
* (C')
|
| * (D) [feat]
| |
| * (C)
|/
|
* (B)
|
* (A)
在feat
被合并之后。
我正在寻找一种通过编程来识别这些"几乎合并"的分支的方法,这样我就可以批量清理它们,就像git branch --all --merged master
显示实际上已经合并(或者,当然,快进到)的分支一样。
使feat
"几乎合并"并符合清理条件的feat
属性包括:
- 在
feat
和master
之间,所有提交都有一个"并行"、"几乎相同"的提交(在这个例子中,C
有C'
,D
有D'
)。 - 几乎相同是指:
- 相同差异
- 相同的提交消息
- 相同的作者和作者日期(提交和提交日期不同)
- 并行意味着:
- 在
feat
和其在master
上的共同祖先(在本例中为B
)之间不存在在master
上没有几乎相同的对的提交 master
上几乎相同的提交以相同的顺序出现,并且紧跟在共同祖先(这里还是B
)之后。
下面的图表表示了在这个定义下我不会认为是"几乎合并"的分支:
x一个一个一个一个x一个一个二个一个x一个一个三个一个
我可能会使用GitPython
编写一个脚本来完成这一任务,但我希望已经有一些东西可以满足我的需要。
限定符
- 我知道github有一个"自动删除头分支"的选项,我现在在这个仓库上启用了这个选项,但是有很长一段时间没有启用,因此有数百个"几乎合并"的分支需要清理
- 如果有人知道有什么方法可以让github在合并公关时实现真正的快进,我将永远感激你(我会在ko-fi上给你买杯咖啡或类似的东西)
2条答案
按热度按时间beq87vna1#
Edit: now that
git range-diff
exists, see sschuberth's answer.实际上,我自己也想要一个这样的命令有一段时间了,所以我最终真的写了它。最终的结果,加上清理和选项处理,是here。它只是刚刚经过测试,可能有bug;正如他们所说,没有任何担保。
它只测试您命名的一个分支,而不是测试所有分支,但是它应该很容易修改。
脚本的解释以及其中的代码
通过比较提交的原始部分,可以很容易地测试"几乎合并"的情况:副本的所有部分都是一样的,除了父提交,当然还有你提到的提交器部分(甚至父提交在第一个/最后一个被复制的提交中也是一样的,第一个/最后一个取决于你对它们的看法)。
即:
我们只是将额外的提交(
E
)堆叠在字面上是彼此的副本的提交之上,除了有时parent
行:D'
=D
,除了父节点,以及C'
=C
(在这种情况下,* 包括 * 父节点)。你有这样一个图表,你称之为 * 非 *"几乎合并":
这里的问题是提交
X
位于B
和C'
之间,如果提交X
字面上为空-或者是一对提交Q
和R
,其中R
是Q
的还原-则C'
将具有与C
相同的树。这在下面的代码中很重要,因为我们可以测试C
的父对象,或者直接查看是否有这样的提交。如果有这样一个提交并且它不是空的,或者如果有提交没有被恢复,那么树就不会匹配,我们会认为这个分支是"非几乎合并的"。如果提交是空的或者被恢复了,那么它就没有任何作用,至少我会很乐意称之为"几乎合并的"。为了测试两个提交是否除了提交者的东西和父哈希值之外都相同,我们只需要在去掉这些行之后比较它们的Git内部对象内容,我们可以使用一个在shell中运行的sed脚本来完成:
这粗暴地使用了硬编码的临时文件名,而它并不清理这些文件名;我稍后在真实的脚本中修正了这个问题。它还有一个小缺陷:它删除了 * 所有 * 父行,而没有检查它是第一个父行还是其他父行。所以在一些不太可能的情况下,这可能会被合并提交所欺骗。不过我不会费心去修复这个bug。
因此,给定两个任意的分支名称M(主线)和F(可以合并到主线中的特性),我们现在可以这样开始:
此时,我们有两个选项,可以通过计算两个文件
/tmp/left
(nl)和/tmp/right
(nr)中剩余的行数来区分,包括$l和$r中的当前提交哈希。注意,因为我们检查了空文件,所以它们都至少为1。X
提交或Q
后接reverts-QR
,在上面的思想过程中)时才能几乎合并。现在,假设我们允许nl〉nr,我们测试每个提交,如下所示:
0md85ypi2#
我刚刚编写了一个利用
git-range-diff
执行检查的脚本: