Git:如何列出从特定分支创建的所有分支?

时间:2019-05-30 00:09:54

标签: git

我需要生成一个报告,其中包含从develop分支(过去某个时候从master分支出来)创建的所有分支名称。我的方法是使用develop获取git log --pretty=format:"%h" master..develop中的第一次提交和最后一次提交,然后使用git branch --contains <hash>使用提交范围。

但是,上述方法存在一些问题:

  1. 我需要运行命令以了解要在查询中考虑的提交范围。
  2. 我将不得不对范围内的每个哈希重复执行git branch --contains命令。
  3. 在大多数情况下,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

2 个答案:

答案 0 :(得分:4)

您可以使用一个命令完全关闭:

git log --ancestry-path  --branches --not $(git merge-base --all master develop) \
        --pretty=%D  --simplify-by-decoration --decorate-refs=refs/heads

那是“向我展示所有分支尖端历史中的分支装饰,这些分支装饰可追溯到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`

答案 1 :(得分:3)

分支名称仅指向一次提交。通过从该点向后浏览图形,可以找到属于该分支的所有早期提交。例如,master..develop就是这样工作的:它选择develop祖先的提交,不包括master祖先的所有提交。

(请注意,在这种情况下:

          o--o   <-- master
         /
...--o--o
         \
          *--*--*   <-- develop

两点master..develop语法包括三个加星标的提交。)

我认为您要的是:

for each branch name $branch:
    if $branch identifies a commit that is a descendant of any
               of the commits in the set `master..develop`:
        print $branch

但是,根据定义,属于提交i的任何提交都是提交c的后代。因此,就像tkruse notes in a comment

git branch --contains <hash-of-c>

就足够了。要在此处找到要使用的提交,可以运行git rev-list --topo-order master..develop | tail -1。 (如果您使用--reversehead -1可能会导致管道破裂,因此tail -1方法会更好。烦人的是,您无法将--reverse与{{1}组合使用}。

您可能会担心这种情况下的故障:

-n 1

您可能希望包含 o--o <-- master / ...--o--o--1--o--o <-- branch-X \ \ 2--*--* <-- develop \ o <-- branch-Y branch-X,并且由于它们是两个的后代,因此无法通过使用一个branch-Y操作来找到它们git branch --contains范围内提交,在此表示为master..develop1。在这里,您确实确实需要多个2-es,或者:

git branch --contains

(未经测试,到目前为止已修复至少一个错误)。但这比简单的set -- $(git rev-list master..develop) git for-each-ref --format='%(refname)' refs/heads | while read ref; do branch=${ref#refs/heads/} tip=$(git rev-parse $ref) take=false for i do if git merge-base --is-ancestor $i $tip; then take=true break fi done $take && echo $branch done 测试要慢得多。此处的逻辑是确定rev-list输出中的任何提交哈希ID是否是所讨论分支的尖端的祖先。

(请注意,这将打印git branch --contains-develop认为提交是其自己的祖先,因此您可能要显式地跳过该提交。)

(您可以通过找到 just 适当的基本提交来加快此速度。例如,在上面的示例中,只有两个。您可以在这些示例上使用git merge-base --is-ancestor并合并命名的分支。要使用的基数取决于--contains中任何合并提交的数量和结构。可以使用master..develop来找到 just 边界提交;我还没有尝试过。)

附录

我在午餐时意识到,有一种简便的方法可以找到用于git rev-list --boundary--contains测试的最小提交集。从范围内的提交的完整列表开始,并按父级先后的拓扑顺序进行排序,例如:

--is-ancestor

然后从“我们必须检查的承诺”的空列表开始:

set -- $(git rev-list --reverse --topo-order master..develop)

现在,对于所有可能的哈希列表中的每个哈希ID,测试每个哈希ID,例如:

hashes=

其中if ! is_descendant $i $hashes; then hashes="$hashes $i" fi 是:

is_descendant

循环完成后,# return true (i.e., 0) if $1 is a descendant of any of # $2, $3, ..., $n is_descendant() { local i c=$1 shift for i do # $i \ancestor $c => $c \descendant $i git merge-base --is-ancestor $i $commit_to_test && return 0 done return 1 } 包含可用于$hashes--contains测试的最小提交集。