简体   繁体   English

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

[英]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: 但是,上述方法存在一些问题:

  1. I need to run to commands to know the range of commits to consider in my query. 我需要运行命令来了解我的查询中要考虑的提交范围。
  2. I'll have to repeat the git branch --contains command each hash in the range. 我将不得不重复git branch --contains命令范围内的每个哈希。
  3. The output from 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 .) (如果你使用--reversehead -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-Xbranch-Y ,并且不会通过使用单个git branch --contains操作找到它们,因为它们是master..develop范围中两个不同提交的后代,在此表示为12 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 developgit 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找到刚才边界提交;我没有这个实验)

Addendum 附录

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.

相关问题 如何获取从GIT分支创建的所有分支的列表(获取分支的所有子分支) - How to get list of all branches created off a GIT branch (get all sub branches of a branch) 如何列出从特定分支的任何提交创建的所有 git 分支 - How to list all git branches created from any commit of a particular branch 如何从最后一个匹配的提交消息中获取合并到分支中的所有 git 分支 - How can I get all git branches that were merged in a branch from the last matching commit message 是否有命令可以查看从特定分支创建或合并的所有分支? - is there a command to see all the branches created from or merged with a specific branch? 计算从特定分支创建的分支数 - count number of branches created from a specific branch Git:如何列出此分支上的提交而不是合并分支的提交 - Git: How to list commits on this branch but not from merged branches 使用 `git branch -a` 列出所有分支不显示最近获取的分支? - List all branches with `git branch -a` does not show recently fetched branch? 如何在git中列出包含另一个分支的分支 - How to list branches that contain another branch in git Git:为什么“git 分支”没有列出所有分支? - Git: why doesn't "git branch" list all the branches? Git:如何列出从特定日期合并到主控的所有远程分支/按日期排序 - Git : how to list all remote branches which ve been merged to master from a specific date / sorted by date
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM