简体   繁体   English

Git 命令列出合并的分支

[英]Git Command to List Merged Branches

Is there a way to list the branches that have been merged into the current working tree?有没有办法列出已合并到当前工作树中的分支? The following is close:以下是接近的:

git branch -r --merged

However, this also includes empty branches.但是,这也包括空分支。 For example, at some point before the latest commit on the current branch, I ran the following:例如,在当前分支的最新提交之前的某个时间点,我运行了以下命令:

git checkout -b empty_branch
git push -u origin empty_branch

Now, the first command includes empty_branch in the resulting list.现在,第一个命令在结果列表中包含empty_branch I found a related question asking how to find empty branches in git , but the accepted answer doesn't work for branches without commits.我发现了一个相关问题,询问如何在 git 中找到空分支,但接受的答案不适用于没有提交的分支。 Is there any way to detect commit-less branches in git, or to otherwise filter such branches out from the results of git branch --merged ?有什么方法可以检测 git 中的无提交分支,或者从git branch --merged的结果中过滤掉这些分支?

You're working off at least one faulty assumption about Git.您正在解决至少一个关于 Git 的错误假设。 This is not an unreasonable assumption, as Git is weird, but it throws your whole question off a bit.这不是一个不合理的假设,因为 Git 很奇怪,但它会让你的整个问题有点偏离。

In Git, branch names don't really mean as much as most people think they do, at least at first.在 Git 中,分支名称的真正含义并不像大多数人认为的那样,至少一开始是这样。 A branch name simply holds the hash ID of some existing commit.分支名称仅包含一些现有提交的 hash ID。 There's an underlying entity that people also call "a branch", and it consists of some or all of the commits that are reachable from the tip commit as defined by the branch name.有一个人们称之为“分支”的底层实体,它由分支名称定义的从提示提交中可访问的部分或全部提交组成。 For (much) more about this, see What exactly do we mean by "branch"?有关此的(更多)更多信息,请参阅“分支”到底是什么意思? and Think Like (a) Git , but let's try for a quick summary:Think Like (a) Git ,但让我们尝试快速总结一下:

  • What Git is really all about is commits . Git 真正的意义在于提交 Each commit is identified by its own unique hash ID.每个提交都由其自己唯一的 hash ID 标识。 No other commit can ever have this hash ID.没有其他提交可以拥有这个 hash ID。 The contents of a commit include a snapshot—made from the index, rather than from the work-tree, but I will try not to get into all those hairy details here—and include the name and email address of the author of the commit, the same for the committer (usually the same person), and two date-and-time-stamps: one for author, one for committer.提交的内容包括一个快照——由索引而不是工作树创建,但我会尽量不在这里讨论所有这些毛茸茸的细节——并包括提交作者的姓名和 email 地址,提交者相同(通常是同一个人),以及两个日期和时间戳:一个用于作者,一个用于提交者。 They also include the log message the committer supplied at the time he/she/they/pronoun-of-choice made the commit.它们还包括提交者在他/她/他们/选择代词进行提交时提供的日志消息。 Perhaps most importantly, the contents of a commit include the raw hash IDs of any commits that should be considered immediate predecessors of that commit.也许最重要的是,提交的内容包括任何应被视为该提交的直接前身的提交的原始 hash ID。

  • In other words, each commit has some set of parent hash IDs, most commonly just one hash ID.换句话说,每个提交都有一组hash ID,最常见的只有一个 hash ID。 These parent IDs make commits form backwards-looking chains: from a last commit, we can go back to a previous commit.这些父 ID 使提交形成向后看的链:从最后一次提交,我们可以 go 回到之前的提交。 From there, we can go back one more step, and so on.从那里,我们可以 go 再退一步,依此类推。 So if a branch name like master holds the hash ID of the last commit we should consider to be part of the branch, the remaining commits are that commit's parent(s), the parent(s) of the parent(s), and so on.因此,如果像master这样的分支名称持有最后一次提交的 hash ID,我们应该将其视为分支的一部分,那么剩余的提交是该提交的父级、父级的父级,等等上。 If the hash ID of the master tip commit is H and its parent is G and G 's parent is F and so on, we have:如果master tip commit 的 hash ID 是H并且它的 parent 是G并且G的 parent 是F等等,我们有:

     ... <-F <-G <-H <-- master

    and that's what a branch is: it's either the name, or the series of commits ending at H , or both: we tend to have to guess what someone means when they say "the master branch".这就是分支的含义:它要么是名称,要么是以H结尾的一系列提交,或者两者兼而有之:当人们说“ master分支”时,我们往往不得不猜测他们的意思。

What git branch --merged does is: git branch --merged所做的是:

  • Find the hash ID of the current branch ( HEAD ).找到当前分支 ( HEAD ) 的 hash ID。
  • For all branch names B skipping over the current branch (as read from HEAD ) oops: Git doesn't skip the current branch, which is sort of annoying:对于所有分支名称B跳过当前分支(从HEAD读取)哎呀: Git不会跳过当前分支,这有点烦人:
    • Is the commit identified by B an ancestor of the commit identified by HEAD ? B标识的提交是否是HEAD标识的提交的祖先? 1 If so, print the name B . 1如果是,打印名称B In any case, move on to the next name.无论如何,请继续使用下一个名称。

So if part of the graph looks like:因此,如果图表的一部分如下所示:

             I--J   <-- feature2
            /
...--F--G--H   <-- master (HEAD)
      \
       K--L   <-- feature1

the two commits that git branch --merged will test are J and L , as compared to the current commit H .与当前提交H相比, git branch --merged将测试的两个提交是JL If J is an ancestor of H —but it's not—this would print feature2 .如果JH的祖先——但它不是——这将打印feature2 If L is an ancestor of H —but it's not—this would print feature1 .如果LH的祖先——但它不是——这将打印feature1 Of course, H is an ancestor of H , so this does print master (with a prefix * to indicate that it is the current branch).当然, HH的祖先,所以这打印master (带有前缀*表示它是当前分支)。

If there's a fourth name that points to any of F , G , H , or any of the commits "behind" F , git branch --merged will print that name, too.如果有第四个名称指向FGH中的任何一个,或者F后面的任何提交, git branch --merged也将打印名称。

I think what you want is to print all names that point to any of the commits that are truly ancestors, and not any names that point directly to commit H .认为您想要的是打印所有指向任何真正祖先的提交的名称,而不是直接指向提交H的任何名称。 The simplest way to do that is probably to let git branch --merged print everything, then remove from the list any name whose hash ID matches that of HEAD .最简单的方法可能是让git branch --merged打印所有内容,然后从列表中删除 hash ID 与HEAD匹配的任何名称。

To remove such names, use git rev-parse on each name.要删除此类名称,请对每个名称使用git rev-parse Use git rev-parse HEAD to find the hash ID of the current branch, ie, the actual hash ID for H in the drawing above.使用git rev-parse HEAD查找当前分支的hash ID,即上图中H的实际hash ID。 Then, using git rev-parse again on each name from git branch --merged , if the result is the same as the first git rev-parse , discard that name.然后,对git branch --merged中的每个名称再次使用git rev-parse ,如果结果与第一个git rev-parse相同,则丢弃该名称。 Otherwise, keep that name.否则,请保留该名称。

(You will have to write a little bit of code for this. If git for-each-ref could do --not and combine some boolean expressions, it could probably be done with that, but it doesn't do --not and combining.) (您将不得不为此编写一些代码。如果git for-each-ref可以做--not并结合一些 boolean 表达式,它可能可以用它来完成,但它不做--not和结合。)


1 The is-ancestor test that Git uses allows equality, ie, it's ≤ rather than < (or more precisely, precedes-or-equals, ≼, vs ≺). 1 Git 使用的 is-ancestor 测试允许相等,即它是 ≤ 而不是 <(或更准确地说,是先于或等于,≼,vs ≺)。 This is also true for git merge --is-ancestor . git merge --is-ancestor也是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM