使用Git,显示出在一个分支中但不在其他分支中的所有提交记录

601

我有一个旧分支,想要删除它。但在这样做之前,我想要检查所有提交到该分支的提交是否曾经合并到其他分支中。因此,我想要查看所有提交到当前分支的提交,且这些提交没有被应用到任何其他分支中[或者,如果没有脚本,如何查看一个分支中所有没有应用到另一个指定分支的提交?]。


要列出两个分支之间缺失的提交,可以使用 compare-branches.py 工具 https://bitbucket.org/aakef/compare-git-branches - Bernd Schubert
相关链接:https://dev59.com/onM_5IYBdhLWcg3wWRkF - 0 _
11个回答

736

要查看一个分支上有哪些提交而另一个分支上没有的提交,请使用git log命令:

git log --no-merges oldbranch ^newbranch

也就是说,显示旧分支(oldbranch)的所有提交日志,但排除新分支(newbranch)包含的提交。可以列出多个需要包含或排除的分支。

git log  --no-merges oldbranch1 oldbranch2 ^newbranch1 ^newbranch2

注意:在 Windows 命令提示符(不是 Powershell)中,^ 是一个转义键,因此需要用另一个 ^ 进行转义:

git log --no-merges oldbranch ^^newbranch

42
这正是我在寻找的。但是,在这里使用 ^ 作为前缀让我感到困惑。在这个上下文中,它的意思是排除那个分支。使用 ^ 作为后缀则表示相对于该分支的父提交。 - Joe Flynn
4
非常有用,谢谢。我很好奇,为什么需要使用“--no-merges”标志?毕竟人们也想看到那些合并提交吧? - Max MacLeod
4
谢谢@jimmyor。顺便说一下,在PowerShell中使用PoshGit时,我不需要在Windows中使用^^,只需要使用^即可。 - TheLukeMcCarthy
17
这是一个很好的答案,但是对我来说,“oldbranch”和“newbranch”的命名有些令人困惑。我建议改成像“branch_withcommits”和“branch_missingcommits”这样的名称,即使有点冗长,因为这样命令的意图就能立即清楚了。我可以自己进行编辑,但那感觉像一项相当重大的修改,需要先确认。你介意我做出这个更改吗(或者你可以自己做这个修改)? - Kyle Strand
6
为了澄清“^”的含义,我们可以用“^excludebranch”代替“^newbranch”。 - Kyle Strand
显示剩余17条评论

360

你可能只是想要

git branch --contains branch-to-delete
这将列出包含“要删除的分支”提交的所有分支。如果它报告的不仅仅是“要删除的分支”,则该分支已合并。
您的备选项实际上只是rev-list语法。例如,git log one-branch..another-branch 显示了需要一切another-branch具有的一切one-branch的内容。
您可能还对git show-branch感兴趣,这是一种查看各个分支的方法。

2
请参见 https://dev59.com/0HRA5IYBdhLWcg3wuAYo : +1。 - VonC
1
“如果它报告了什么,该分支已合并”这一行可能会被误解:如果‘git branch --contains some-branch’只返回‘some-branch’,那么它确实返回了某些内容,但它尚未被合并。” - Confusion
5
请注意,git log foo..bar会显示在bar最新版本和foo最新版本之间的提交记录,但不包括较早时间段中缺失的其他提交记录。要查看bar中存在而foo中不存在的所有内容,您应该使用@jimmyorr的解决方法。 - Paul A Jungwirth
1
最好使用git branch --merged,它会显示所有已合并到当前分支的分支(可以安全删除它们)。显然,在进行变基/压缩操作时,这两种方法都会失败。 - undefined

128

1
请参考 Paul A Jungwirth 的评论。据他所说,这种方法可能会漏掉一些旧的提交记录? - Miserable Variable
2
我不确定旧提交是什么意思。双点基本上要求Git解析一系列提交,这些提交可以从一个提交中访问,但无法从另一个提交中访问。这里有一个带有图表说明的文档:http://git-scm.com/book/en/v2/Git-Tools-Revision-Selection#Commit-Ranges - Xuan
1
如果我们在 newbrancholdbranch 中的任意一个,我们可以分别执行 git log ..oldbranchgit log newbranch.. - YakovL
1
Jimmyorr的解决方案对我没有用,但是这个解决方案却行得通了,多亏了在引用名称之间加上两个点“..”。我还使用了“--cherry-pick”选项来隐藏那些存在于两个分支上但哈希值不同的提交,因为它们是从一个分支挑选到另一个分支的。 - Mickäel A.
@Pramod 你确定这是版本问题吗?这个答案早在2014年就存在了,但2.17.1版本是在2018年发布的 https://github.com/git/git/releases?after=v2.17.1 - Xuan
显示剩余3条评论

78

如果您仍在寻找简单的答案,请查看git cherry。它比较实际的差异而不是提交哈希值。这意味着它可以容纳已经挑选或重新设置的提交。

首先检出您想要删除的分支:

git checkout [branch-to-delete]

然后使用 git cherry 将其与您的主开发分支进行比较:

git cherry -v master

示例输出:

+ 8a14709d08c99c36e907e47f9c4dacebeff46ecb Commit message
+ b30ccc3fb38d3d64c5fef079a761c7e0a5c7da81 Another commit message
- 85867e38712de930864c5edb7856342e1358b2a0 Yet another message
注意:使用-v标志会将提交消息与SHA散列一起包括在内。
以'+'开头的行位于要删除的分支中,但不在主分支中。 以'-'开头的行在主分支中有一个等效提交。
仅针对不在主分支中的提交,可以将cherry pick与grep组合使用: git cherry -v master | grep "^\+" 示例输出:
+ 8a14709d08c99c36e907e47f9c4dacebeff46ecb Commit message
+ b30ccc3fb38d3d64c5fef079a761c7e0a5c7da81 Another commit message

我已经尝试过这个方法,但它仍然报告说在 fb(特性分支)中有许多提交不在 mb(主分支)中。然而,如果我在 fb 中执行 git diff mb,则看不到任何差异。我确实使用了 rebase 并压缩了所有内容。我几乎可以确定这就是原因,但我只是想确定一下。如果是这种情况,那么我将尽可能避免压缩;我属于“无信息丢失派”。我想知道是否可能添加一个日志显示模式,以便将合并显示为重新设置,以保持历史记录的清晰,并且不会丢失任何信息。 - Outis Von Nemo
2
不确定您的确切情况,但如果您已将多个提交合并为一个,并将其与另一个分支进行比较,那么这肯定行不通。在这种情况下,您可能只想使用Unix的diff实用程序来比较各个文件。或者,您可以创建一个临时分支,并将所有提交压缩到其中,类似于原始分支所做的操作,然后使用此方法,我认为会起作用。 - Tim S

52
尽管这里发布的一些答案可以帮助您找到所需的内容,但git branch的以下子命令是更适合您任务的解决方案。通过使用--merged,您可以找到所有可以安全删除的分支,因为这些分支完全包含在HEAD中。
master中,您可以运行该命令来列举可以安全删除的分支,如下所示:
git branch --merged
  develop
  fpg_download_links
* master
  master_merge_static

# Delete local and remote tracking branches you don't want
git branch -d fpg_download_links
git push origin :fpg_download_links
git branch -d master_merge_static
git push origin :master_merge_static

# There is also a flag to specify remote branches in the output
git branch --remotes --merged

21

jimmyorr的回答在Windows上不起作用。使用--not代替^会有帮助:

git log oldbranch --not newbranch --no-merges

7
没问题, +1。不过请注意,在Windows系统上支持使用 ^ ,但需要进行转义,因为在Windows中,另外一个转义符就是 ^git log oldbranch ^^newbranch --no-merges - VonC
5
具体来说,在Windows的Powershell控制台中可以使用,但在CMD中需要额外添加"^"。 - Rod

8

如果您只需要检查一个分支,例如如果您想要将分支'B'完全合并到分支'A'中,您可以简单地执行以下操作:

$ git checkout A
$ git branch -d B

git branch -d <branchname> 带有“必须完全合并到HEAD中的分支”的安全性。

注意:如果分支B已经合并到A中,该命令将实际删除该分支。


4

我也想要计算提交次数,以下是如何实现:

统计当前分支 (HEAD) 上的提交次数,但不包括 master 分支:

git log --oneline ^master HEAD | wc -l

wc -l 表示“单词计数”,即统计'l'ines行的数量。

当然,要查看整个日志消息,就像其他答案所提供的那样:

git log ^master HEAD

...或者以简洁的--oneline形式:

git log --oneline ^master HEAD

如果您不想计算合并提交,您可以使用 --no-merges 来排除这些提交:
git log --oneline --no-merges ^master HEAD | wc -l

etc.


3
你可以使用这个简单的脚本来查看未合并的提交。
#!/bin/bash
# Show commits that exists only on branch and not in current
# Usage:
#   git branch-notmerge <branchname>
#
# Setup git alias
#   git config alias.branch-notmerge [path/to/this/script]
grep -Fvf <(git log --pretty=format:'%H - %s') <(git log $1 --pretty=format:'%H - %s')

你可以使用工具git-wtf,它可以显示分支的状态。

3
显示来自other-branch的提交和提交内容,这些内容不在您当前的分支中:
git show @..other-branch

此外,您可以直接将other-branch的提交应用到当前分支:

git cherry-pick @..other-branch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接