我需要生成一个报告,其中包含从 分支(过去某个时候develop分支出来)创建的所有分支名称。我的方法是获取usingmaster中的第一个和最后一个提交,然后使用 的提交范围。developgit log --pretty=format:"%h" master..developgit branch --contains <hash>
然而,上述方法存在一些问题:
git branch --contains范围内的每个哈希重复该命令。git branch --contains将包含冗余结果,因为大多数提交在分支之间是常见的。我希望有一种更好、更直接的方法来做到这一点。下面我将尝试说明感兴趣的案例:
master
^
| develop
a---b ^
\ |
--c--d---e---f---g--h--i
\ \ \ \
k-l m n o--p
^ ^ ^ ^
| | | |
branch_1 | branch_3 |
branch_2 branch_4
// Desired output:
branch_1
branch_2
branch_3
branch_4
Run Code Online (Sandbox Code Playgroud)
分支名称仅指向一次提交。通过从该点向后遍历图表可以找到属于该分支的所有早期提交。这就是该master..develop部分的工作原理,例如:它选择作为 的祖先的提交develop,排除作为 的祖先的任何提交master。
(请注意,例如在这种情况下:
\n\n o--o <-- master\n /\n...--o--o\n \\\n *--*--* <-- develop\nRun Code Online (Sandbox Code Playgroud)\n\n两点master..develop语法包括三个带星号的提交。)
我想你在这里要求的是:
\n\nfor each branch name $branch:\n if $branch identifies a commit that is a descendant of any\n of the commits in the set `master..develop`:\n print $branch\nRun Code Online (Sandbox Code Playgroud)\n\n但是,任何属于 commit 后代的提交i根据定义都是 commit 的后代c。因此,正如tkruse 在评论中指出的那样:
git branch --contains <hash-of-c>\nRun Code Online (Sandbox Code Playgroud)\n\n应该足够了。要查找此处使用的提交,您可以运行git rev-list --topo-order master..develop | tail -1. (如果使用的--reverse话head -1会出现断管故障,所以这个tail -1方法更好。烦人的是,你不能--reverse与结合使用-n 1。)
您可能担心这种情况会出现故障:
\n\n o--o <-- master\n /\n...--o--o--1--o--o <-- branch-X\n \\ \\\n 2--*--* <-- develop\n \\\n o <-- branch-Y\nRun Code Online (Sandbox Code Playgroud)\n\n您可能需要branch-X和branch-Y,但使用单个操作无法找到它们git branch --contains,因为它们是该范围内两个不同提交的后代master..develop,此处表示为1和2。在这里,您确实需要多个git branch --contains-es,或者,或者:
set -- $(git rev-list master..develop)\ngit for-each-ref --format=\'%(refname)\' refs/heads | while read ref; do\n branch=${ref#refs/heads/}\n tip=$(git rev-parse $ref)\n take=false\n for i do\n if git merge-base --is-ancestor $i $tip; then\n take=true\n break\n fi\n done\n $take && echo $branch\ndone\nRun Code Online (Sandbox Code Playgroud)\n\n(未经测试,到目前为止至少修复了一个错误)。但这会比简单的git branch --contains测试慢很多。这里的逻辑是确定 rev-list 输出中的任何提交哈希 ID 是否是相关分支尖端的祖先。
(请注意,这将打印develop\xe2\x80\x94git merge-base --is-ancestor认为提交是其自己的祖先\xe2\x80\x94,因此您可能需要显式跳过该提交。)
(您可以通过查找适当的基础提交来加快速度。例如,在上面的示例中,只有两个。然后您可以使用--contains它们并联合命名分支。要使用的基础数量是一个函数中任何合并提交的数量和结构master..develop。也许可以用来git rev-list --boundary查找边界提交;我还没有尝试过这一点。)
我在午餐期间意识到有一种简单的方法可以找到最小的提交--contains或--is-ancestor测试集。从范围内提交的完整列表开始,按拓扑顺序排序,首先是父级,例如:
set -- $(git rev-list --reverse --topo-order master..develop)\nRun Code Online (Sandbox Code Playgroud)\n\n然后从“我们必须检查的提交”的空列表开始:
\n\nhashes=\nRun Code Online (Sandbox Code Playgroud)\n\n现在,对于所有可能的哈希列表中的每个哈希 ID,测试每个哈希 ID,例如:
\n\nif ! is_descendant $i $hashes; then\n hashes="$hashes $i"\nfi\nRun Code Online (Sandbox Code Playgroud)\n\n哪里is_descendant:
# return true (i.e., 0) if $1 is a descendant of any of\n# $2, $3, ..., $n\nis_descendant() {\n local i c=$1\n shift\n for i do\n # $i \\ancestor $c => $c \\descendant $i\n git merge-base --is-ancestor $i $commit_to_test && return 0\n done\n return 1\n}\nRun Code Online (Sandbox Code Playgroud)\n\n循环完成后,$hashes包含可用于--contains或--is-ancestor测试的最小提交集。
您可以通过一个命令非常接近:
git log --ancestry-path --branches --not $(git merge-base --all master develop) \
--pretty=%D --simplify-by-decoration --decorate-refs=refs/heads
Run Code Online (Sandbox Code Playgroud)
那就是“只向我显示所有分支尖端历史中的分支装饰,这些历史可追溯到 master 和development 的当前合并基础”。
您可以通过将结果通过类似awk '{print $NF}' RS=', |\n'.
请注意,这(就像@torek的答案)假设您在像生产主机一样为存档级别稳定性而管理的存储库中执行此操作,分支名称和提交之间根本没有必要的关系,更不用说永久的、全局的或唯一的关系一。如果您尝试将提交永久绑定到某些外部管理记录,请在提交消息中执行此操作,而不是在分支名称中执行此操作。
编辑:如果您想快速概述自主开发拆分以来的当前分支结构,
git log --graph --decorate-refs=refs/heads --oneline \
--branches --simplify-by-decoration \
--ancestry-path --boundary --not `git merge-base master develop`
Run Code Online (Sandbox Code Playgroud)