简体   繁体   English

Git branch merged 列出合并时提交为零的本地分支

[英]Git branch merged list local branches with zero commits as merged

I'm developing a simple script to show local branches (their status, etc) and I'd like to know which of my branches have been already merged to the master branch.我正在开发一个简单的脚本来显示本地分支(它们的状态等),我想知道我的哪些分支已经合并到主分支。 Normally I have several branches (corresponding to fixes/features, etc).通常我有几个分支(对应于修复/功能等)。 Some of them have an associated PR that at some point get merged to the remote origin.其中一些具有关联的 PR,该 PR 在某些时候会合并到远程源。 So I'd like to know which ones have been merged (so I can delete them locally for ie).所以我想知道哪些已经被合并了(这样我就可以在本地为ie删除它们)。 The problem is that when I have new/fresh branches (with 0 commits on them) the following git command lists them as merged which is confusing:问题是,当我有新的/新鲜的分支(其中有 0 个提交)时,以下 git 命令将它们列为合并,这令人困惑:

git branch --merged master

In the following example (took from a candidate answer):在以下示例中(取自候选答案):

          K--L   <-- br1
         /    \
...--F--G--H---M   <-- master, br3
      \
       I--J   <-- br2

I would like to show br1 as merged, but not br3 ( br2 is not merged in this case obviously).我想将br1显示为已合并,但不是br3 (显然在这种情况下br2未合并)。 Please, keep in mind that master is evolving all the time so the above diagram is not realistic, normally master will move quickly and br3 becomes behind master so br1 .请记住,master 一直在进化,所以上图是不现实的,通常master会快速移动并且br3落后于 master 所以br1 The difference between br1 and br3 is that br1 at some point diverged (due to commits) and then it was merged again to master. br1br3之间的区别在于br1在某些时候发生分歧(由于提交),然后再次合并到 master。 However, br3 is just pointing to a rev on master but has never had (so far) any different commits.然而, br3只是指向 master 上的一个 rev 但从未有过(到目前为止)任何不同的提交。

No branch, in Git, ever has no commits on it. Git 中的任何分支都没有任何提交。 This is because a branch name is an entity holding the hash ID of a valid existing commit.这是因为分支名称是一个包含有效现有提交的 hash ID 的实体。 That valid existing commit is a commit, so the branch has at least one commit on it:该有效的现有提交是一个提交,因此该分支至少有一个提交:

...--F--G--H   <-- master, br1, br2

Here the names master , br1 , and br2 all select commit H .这里的名称masterbr1br2都是 select commit H The set of commits that is on each branch is exactly the same as the set of commits that is on the other two branches.每个分支上的提交集与其他两个分支上的提交集完全相同。

People often say that " br1 has no commits" when what they mean is " br1 has no commits that are not also on master ".人们经常br1没有提交”,其实他们的意思是“ br1没有不在master上的提交”。 What you can do is count the number of commits that are different between any two branch names:您可以做的是计算任意两个分支名称之间不同的提交数:

          K--L   <-- br1
         /    \
...--F--G--H---M   <-- master, br3
      \
       I--J   <-- br2

Here, the result of:在这里,结果是:

git rev-list --count --left-right master...br3

will be 0 0 because the two branches are even with each other, while the result of:将为0 0 ,因为两个分支彼此相等,而结果:

git rev-list --count --left-right br1...master

will be 0 1 because br1 is strictly behind master (has no commits that master lacks) but master is strictly ahead of br1 (has commit M , which br1 lacks).将是0 1因为br1严格落后于master (没有master缺少的提交)但是master严格领先于br1 (有提交Mbr1缺少)。 The result of:的结果:

git rev-list --count --left-right br2...master

will be 2 5 , because br2 has two commits ( IJ ) that are not reachable from M , while master has five commits ( GHM and KLM but Git avoids double-counting M ) that are not reachable from J .将是2 5 ,因为br2有两个提交( IJ )无法从M访问,而master有五个提交( GHMKLM但 Git 避免重复计算M )无法从J访问。 (Commits F and earlier are reachable from both and are therefore not counted.) (提交F和更早的提交都可以从两者到达,因此不计算在内。)

Note that this syntax requires the three dots between the two names, and the --left-right option to split out the two counts.请注意,此语法需要两个名称之间的三个点,以及用于拆分两个计数的--left-right选项。 You can also use git branch --merged master to quickly eliminate br2 as a candidate: the result of git branch --merged master will be the list of names that are behind or even with master .您还可以使用git branch --merged master快速排除br2作为候选者: git branch --merged master的结果将是落后于或与master齐名的名称列表。 Having found that list, you can then eliminate any name that is even with master :找到该列表后,您可以删除与master偶数的任何名称:

if [ $(git rev-parse $branch) = $(git rev-parse master) ]; then
    # branch is even with `master` so
    # `git rev-list --left-right --count` would
    # produce 0 0
else
   # branch is behind `master`
fi

Note: do not use git branch in a script;注意:不要在脚本中使用git branch use git for-each-ref instead.请改用git for-each-ref (Use git branch if and only if you have a sufficiently ancient Git that git for-each-ref lacks the --merged option. However, if you have a Git that old, you should consider upgrading it.) (使用git branch当且仅当你有一个足够古老的 Git git for-each-ref缺少--merged选项。但是,如果你有一个那么旧的 Git,你应该考虑升级它。)

tl;dr: Since your goal is to know which local branches you are done working on and can be deleted, the command you tried isn't sufficient. tl;dr:由于您的目标是了解您已完成哪些本地分支的工作并且可以将其删除,因此您尝试的命令是不够的。 You'll need to do something else first, or use a different method entirely.您需要先做其他事情,或者完全使用不同的方法。

Explanation:解释:

I think the source of your question really comes from the wording used by the branch option --merged , which is confusing since "merged" means something slightly different in Git than it does in English.我认为您问题的来源实际上来自branch选项--merged使用的措辞,这令人困惑,因为“合并”在 Git 中的意思与英语略有不同。

The documentation for --merged states (emphasis mine): --merged states 的文档(强调我的):

With --merged, only branches merged into the named commit ( ie the branches whose tip commits are reachable from the named commit ) will be listed.使用--merged,只会列出合并到命名提交中的分支(即其尖端提交可从命名提交访问的分支)。

For example, after you merge my-branch into master , my-branch is going to appear as "merged" when you run the command git branch --merged master , but it doesn't appear in the list because you merged it in, it appears because after you merged it in the branch is now reachable from master .例如,在您将my-branch合并到master之后,当您运行命令git branch --merged master时, my-branch将显示为“已合并”,但它不会出现在列表中,因为您已将它合并到,它出现是因为在你将它合并到分支之后现在可以从master访问 Any new branch you create from master without adding new commits is of course also reachable, and consequently will also be considered "merged" by Git. Note, after merging my-branch into master , if you add a new commit to my-branch , it will no longer appear as "merged" from Git's POV even though you previously did "merge" it.您从master创建的任何新分支而不添加新提交当然也是可访问的,因此也将被 Git 视为“合并”。请注意,在将my-branch合并到master之后,如果您向my-branch添加新提交,它不会再从 Git 的 POV 中显示为“合并”,即使您之前确实“合并”过它。 The point here is whether or not you actually ran git merge somewhere to merge a branch in, isn't necessarily relevant to whether or not Git considers the branch "reachable".这里的要点是你是否真的在某处运行git merge合并一个分支,不一定与 Git 是否认为分支“可达”有关。

Possible Alternatives:可能的选择:

Simple: There is a very simple solution that would enable you to keep doing what you're doing.简单:有一个非常简单的解决方案可以让您继续做您正在做的事情。 Any time you create a new branch, add an empty commit to it, perhaps with some comment that may be useful.任何时候你创建一个新分支,向它添加一个空提交,也许有一些可能有用的注释。 For example:例如:

git fetch
# make your branch...

# Add an empty commit:
git commit --allow-empty -m "wip: Improve performance by refactoring"

By adding a blank commit it will no longer be reachable from master .通过添加一个空白提交,它将不再可以从master访问。 When you're ready to work on that branch just amend (and remove the "wip: " prefix in the subject), or reset back a commit before you make your first commit on that branch.当您准备好在该分支上工作时,只需修改(并删除主题中的“wip:”前缀),或者在您对该分支进行首次提交之前重置提交。

Better?更好的? If you use a SCM tool to merge your branches into master rather than doing it locally, and if your workflow is to delete your remote branches after they are merged in (which really ought to be the default and most tools offer this as a selectable option when completing a PR), then you can (and probably should) prune your remote tracking branches, and then you can identify which local branches used to have a remote tracking branch but no longer do.如果您使用 SCM 工具将您的分支合并到master中而不是在本地进行,并且如果您的工作流程是在合并后删除远程分支(这实际上应该是默认设置,并且大多数工具都将其作为可选选项提供当完成 PR 时),那么你可以(并且可能应该)修剪你的远程跟踪分支,然后你可以确定哪些本地分支曾经有一个远程跟踪分支但不再有。 Here's an example of this.这是一个例子。

Simplest?最简单? What if you just delete all "merged" branches, and use some other mechanism to determine what you have to work on (eg issue tracker or project management tool).如果您只是删除所有“合并的”分支,并使用其他机制来确定您必须处理的内容(例如问题跟踪器或项目管理工具)会怎样? Having a bunch of branch names sitting there with no new commits on them isn't necessarily helping you, other than to remind you that you need to do it.一堆分支名称放在那里而没有新的提交并不一定对你有帮助,除了提醒你你需要这样做。

Creative with a Caveat: Of all the solutions, I think this one is probably what you are envisioning in your head, but it has a pretty specific caveat in that it will only work if every one of your feature branch merges uses --no-ff and creates a merge commit.有创意的警告:在所有解决方案中,我认为这个可能是您脑海中的设想,但它有一个非常具体的警告,因为它只有在您的每个功能分支合并都使用--no-ff并创建合并提交。 So, if you always use --no-ff (or if master moves so quickly that you'll always need a merge commit and you don't rebase your feature branch), then you should be able to filter the branches by those who's tip commit is reachable by master , and also if a merge commit exists on master with that tip commit as one of it's parents.所以,如果你总是使用--no-ff (或者如果master移动得太快以至于你总是需要合并提交并且你不重新设置你的功能分支),那么你应该能够通过那些谁是master可以访问 tip 提交,并且如果master上存在合并提交,并且该 tip 提交是它的父项之一。 This might take a minute to script out but once you have it, you can re-use it indefinitely.这可能需要一分钟来编写脚本,但一旦您拥有它,您就可以无限期地重复使用它。

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

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