[英]Git: How to list all branches that were created from a specific branch?
I need to generate a report with all branch names that were created from develop
branch (which was branched off master
sometime in the past). 我需要生成与创建的所有分支名称的报告
develop
分支(这是分支master
在过去的某个时候)。 My approach was to get the first and last commits in develop
using git log --pretty=format:"%h" master..develop
, then use the range of commits with git branch --contains <hash>
. 我的方法是让第一个和最后犯
develop
利用git log --pretty=format:"%h" master..develop
,然后使用提交的范围与git branch --contains <hash>
。
However, the above approach has a few problems: 但是,上述方法存在一些问题:
git branch --contains
command each hash in the range. git branch --contains
命令范围内的每个哈希。 git branch --contains
commands will contain redundant results for most cases because of the fact that most commits are common between branches. git branch --contains
命令的输出在大多数情况下都会包含冗余结果,因为大多数提交在分支之间是通用的。 I'm hoping there is a better and more direct way of doing this. 我希望有更好,更直接的方式来做到这一点。 Below I'll try to illustrate the case of interest:
下面我将尝试说明感兴趣的案例:
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
You can get awfully close with one command: 你可以用一个命令非常接近:
git log --ancestry-path --branches --not $(git merge-base --all master develop) \
--pretty=%D --simplify-by-decoration --decorate-refs=refs/heads
That's "show me just the branch decorations in all branch-tip histories that trace back to the current merge base of master and develop". 这是“向我展示所有分支历史中的分支装饰,追溯到当前合并基础的大师和开发”。
You can get it prettier by piping the result through anything like awk '{print $NF}' RS=', |\\n'
. 你可以通过
awk '{print $NF}' RS=', |\\n'
类的方式将结果输出来更漂亮。
Note that this (like @torek's answer) assumes you're doing this in a repo administered for archival-level stability like your production master, there's no necessary relation between branch names and commits at all, let alone a permanent, or global or unique one. 请注意,这(就像@ torek的答案)假设你在一个为你的生产大师管理档案级稳定性的仓库中做这件事,根本没有必要的分支名称和提交之间的关系,更不用说永久性,全球性或独特性一。 If you're trying to permanently tie commits to some external administrative record, do it in the commit message, not the branch name.
如果您尝试永久地将提交绑定到某些外部管理记录,请在提交消息中执行,而不是分支名称。
Edit: if you want a quick overview of the current branch structure since the master-develop split, 编辑:如果您想快速了解自master-develop拆分后的当前分支结构,
git log --graph --decorate-refs=refs/heads --oneline \
--branches --simplify-by-decoration \
--ancestry-path --boundary --not `git merge-base master develop`
A branch name simply points to one commit. 分支名称只指向一个提交。 All earlier commits that are part of that branch are found by walking backwards through the graph from that point.
通过从该点向后遍历图表,可以找到属于该分支的所有早期提交。 That's how the
master..develop
part works, for instance: it selects commits that are ancestors of develop
, excluding any commits that are ancestors of master
. 这就是
master..develop
部分的工作原理,例如:它选择了作为develop
祖先的提交,排除了作为master
祖先的任何提交。
(Note that in, eg, this situation: (请注意,例如,在这种情况下:
o--o <-- master
/
...--o--o
\
*--*--* <-- develop
the two-dot master..develop
syntax includes the three starred commits.) 双点
master..develop
语法包括三个已提交的提交。)
I think what you are asking for here is: 我想你在这里要求的是:
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
But any commit that's a descendant of, say, commit i
is by definition a descendant of commit c
. 但是,任何提交,例如,提交
i
的后代,根据定义是提交c
的后代。 So, as tkruse notes in a comment : 所以,正如tkruse在评论中所说 :
git branch --contains <hash-of-c>
should suffice. 应该足够了。 To find the commit to use here, you can run
git rev-list --topo-order master..develop | tail -1
要查找此处使用的提交,您可以运行
git rev-list --topo-order master..develop | tail -1
git rev-list --topo-order master..develop | tail -1
. git rev-list --topo-order master..develop | tail -1
。 (If you use --reverse
and head -1
you can get a broken-pipe failure, so the tail -1
method is better. Annoyingly, you cannot combine --reverse
with -n 1
.) (如果你使用
--reverse
和head -1
你可以得到一个破管失败,所以tail -1
方法更好。令人讨厌的是,你不能将--reverse
与-n 1
结合起来。)
You may be worried about a glitch with this sort of case: 您可能会担心这种情况会出现故障:
o--o <-- master
/
...--o--o--1--o--o <-- branch-X
\ \
2--*--* <-- develop
\
o <-- branch-Y
You may want branch-X
and branch-Y
included, and they are not going to be found by using one single git branch --contains
operation as they're descendants of two different commits in the master..develop
range, denoted here as 1
and 2
. 您可能希望包含
branch-X
和branch-Y
,并且不会通过使用单个git branch --contains
操作找到它们,因为它们是master..develop
范围中两个不同提交的后代,在此表示为1
和2
。 Here, you really do need multiple git branch --contains
-es, or, alternatively: 在这里,你真的需要多个
git branch --contains
-es,或者:
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
(untested and at least one bug fixed so far). (未经测试,至少有一个错误到目前为止)。 But this will be much slower than the simple
git branch --contains
test. 但这比简单的
git branch --contains
测试慢得多。 The logic here is to determine whether any of the commit hash IDs in the rev-list output is an ancestor of the tip of the branch in question. 这里的逻辑是确定rev-list输出中的任何提交散列ID是否是所讨论的分支的尖端的祖先。
(Note that this will print develop
— git merge-base --is-ancestor
considers a commit to be its own ancestor—so you might want to explicitly skip that one.) (注意,这将打印
develop
- git merge-base --is-ancestor
认为提交是它自己的祖先 - 所以你可能想要显式跳过那个。)
(You can speed this up a lot by finding just the appropriate base commits. In the example above, for instance, there are just two. You can then use --contains
on those and union the named branches. The number of bases to use is a function of the number and structure of any merge commits in master..develop
. It may be possible to use git rev-list --boundary
to find just the boundary commits; I have not experimented with this.) (你可以找到公正适当的基础提交。在上面的例子,例如,只有两个。然后,您可以使用加快这很多
--contains
那些和工会指定的分支机构。使用碱基数任何合并的数量和结构的函数犯master..develop
它可能会使用。 git rev-list --boundary
找到刚才边界提交;我没有这个实验)
I realized during lunch that there's an easy way to find the minimal set of commits for --contains
or --is-ancestor
testing. 我在午餐时意识到,有一种简单的方法可以找到
--contains
或--contains
--is-ancestor
测试的最小提交。 Start with the complete list of commits in the range, sorted into topological order with parents first, eg: 从范围中的完整提交列表开始,首先按照父项的拓扑顺序排序,例如:
set -- $(git rev-list --reverse --topo-order master..develop)
Then start with an empty list of "commits that we must inspect": 然后从一个空的“我们必须检查的提交”列表开始:
hashes=
Now, for each hash ID in the list of all possible hashes, test each one, eg: 现在,对于所有可能哈希值列表中的每个哈希ID,测试每个哈希值,例如:
if ! is_descendant $i $hashes; then
hashes="$hashes $i"
fi
where is_descendant
is: 其中
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
}
After the loop is done, $hashes
contains the minimal set of commits that can be used for --contains
or --is-ancestor
testing. 循环完成后,
$hashes
包含可用于--contains
或--contains
--is-ancestor
测试的最小提交集。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.