给定一个提交ID,如何确定当前分支是否包含该提交?

380

我想要做的是版本检查。我希望确保代码始终保持在最低版本之上。因此,我需要一种方法来确定当前分支是否包含指定的提交。


7
可能是如何列出包含特定提交的分支?的重复问题。 - kowsky
15
请参考建议的重复项,了解如何查找包含特定提交的所有分支。要查找当前分支是否包含提交C,请使用“plumbing”命令git merge-base --is-ancestor。如果CHEAD的祖先,则当前分支包含C,因此:if git merge-base --is-ancestor $hash HEAD; then echo I contain commit $hash; else echo I do not contain commit $hash; fi - torek
1
嗨,请将此作为答案提交,以便选择为正确答案 =) - Ben
1
@Ben - 我将其添加为社区维基答案。 - Zitrax
1
@torek 我发现一个奇怪的事情是关于 --is-ancestor 的文档:检查第一个 <commit> 是否是第二个 <commit> 的祖先,如果是则以状态 0 退出,否则以状态 1 退出。 这让我觉得你代码片段中的 if 方向可能是错误的,因为它对于 true 时会以 0 退出,但实际上它似乎可以工作... 是文档有误还是我理解有误呢? - Remover
2
@Remover:在shell脚本中,零为真,非零为假:这与C语言的惯例相反。/bin/true最初是实现为exit 0,而/bin/false则是实现为exit 1。(现代shell已经内置了这些功能)。 - torek
10个回答

446

有多种方法可以实现这个结果。第一个朴素的选项是使用 git log 并使用 grep 搜索特定提交,但这并不总是准确的。

git log | grep <commit_id>

直接使用git branch查找包含给定COMMIT_ID的所有分支更好。

git branch --contains $COMMIT_ID

下一步是找出当前分支,这可以使用git 1.8.1及以上版本完成。

git symbolic-ref --short HEAD

并组合在一起为

git branch $(git symbolic-ref --short HEAD) --contains $COMMIT_ID

但是上面的命令并不返回 true 或 false,有一种更短的版本,如果提交在当前分支中,则返回退出码 0,否则返回退出码 1。


但是上述命令没有返回true或false,而有一种更短的版本,如果提交在当前分支中,则返回退出码0;如果不在当前分支中,则返回退出码1。
git merge-base --is-ancestor $COMMIT_ID HEAD

退出代码很好,但是如果你想要字符串truefalse作为答案,你需要再添加一些内容,然后与bash的if结合使用。

if [ 0 -eq $(git merge-base --is-ancestor $COMMIT_ID HEAD) ]; then echo "true"; else echo "false"; fi

22
如果 git log 中提到提交 SHA 的原因是其他的,例如在提交消息中作为从另一个分支移植的结果,那么 grep 命令可能会产生误报,因此这句话不正确。请修改。 - Adam Spiers
3
请查看问题下的评论,其中使用了内置的git工具集。https://dev59.com/F1cP5IYBdhLWcg3w-Oxz#r7KiEYcBWogLw_1bHiLU - Ben
3
我喜欢第一个选项,但为了排除亚当的反对意见,我会在“git log”命令中添加选项“--format=format:%H”。 - PJSCopeland
你如何在远程分支中进行搜索?问题是 git branch -r != git branch --list - Geoff Langenderfer
如果你担心这个问题,那么可以使用 git branch --contains $COMMIT_ID | grep "$(git branch --show-current)" - aderchox
显示剩余2条评论

117

获取包含特定提交的分支列表。

# get all the branches where the commit exists
$ git branch --contains <commit-id>

检查一个分支是否包含特定的提交。

# output the branch-name if the commit exists in that branch
$ git branch --contains <commit-id> | grep <branch-name>

搜索具有完全匹配的分支(例如,feature)。

$ git branch --contains <commit-id> | grep -E '(^|\s)feature$'

比如说,如果你有三个本地分支叫做featurefeature1feature2,那么

$ git branch --contains <commit-id> | grep 'feature'

# output
feature
feature1
feature2

$ git branch --contains <commit-id> | grep -E '(^|\s)feature$'

# output
feature     

你也可以搜索 localremote 分支(使用 -a),或者只搜索 remote 分支(使用 -r)。

# search in both 'local' & 'remote' branches  
$ git branch -a --contains <commit-id> | grep -E '(^|\s)feature$'

# search in 'remote' branches  
$ git branch -r --contains <commit-id> | grep -E '(^|\s)feature$'

1
如果其他分支的名称也包含 <branch-name> 子字符串,则此处的 grep 也可能导致假阳性。 - Adam Spiers
1
是的@AdamSpiers,已更新答案,使用grep -E '(^|\s)branchname$'精确匹配分支名称。 - Sajib Khan
2
根据相关问题的这条评论,在git branch命令中添加-r("remote")或-a("all")选项可能很有用,以查找可能未在本地存储库克隆中复制的分支。 - sxc731
这对我没有用,我需要 git branch --all --contains <commit-id> - Arthur Tacca
如果我在主分支上,它实际上并没有显示所有的分支 - 它只显示它及其远程分支;如果我在我的特性分支上 - 它会显示该分支及其远程分支,但不包括主分支。 - Alexander Telegin

19

请参考提出的重复问题以查找包含指定提交的所有分支。为了找到当前分支是否包含提交C,请使用"plumbing"命令git merge-base --is-ancestor。如果C是HEAD的祖先,则当前分支包含C,因此:

if git merge-base --is-ancestor $hash HEAD; then
    echo I contain commit $hash
else
    echo I do not contain commit $hash
fi

(顺便提一下,在shell脚本中,退出状态码为零的命令被认为是“真”,而退出状态码为非零的命令被认为是“假”。)


13

仅检查已签出的本地分支。

git branch --contains $COMMIT_ID

检查所有分支(包括本地和已获取的远程分支)

git branch -a --contains $COMMIT_ID

确保获取远程内容

git fetch origin

12
列出包含特定提交的本地分支: git branch --contains <commit-id> 列出包含特定提交的所有分支,包括仅远程的分支: git branch -a --contains <commit-id> 检查提交是否位于某个分支上: git log <branch> | grep <commit_id> 如果本地不存在分支,则在分支名称前加上前缀origin/

对于关于-a的评论点赞。谢谢你的建议! - Thorkil Værge

9

是的,还有另一种选择:

git rev-list <branch name> | grep `git rev-parse <commit>`

对我来说这是最好的方法,因为它还适用于本地缓存的远程分支,例如remotes/origin/master,在此分支上git branch --contains将不起作用。

这涵盖了比OP问题更多的内容,仅与“当前分支”有关,但我认为问一个“任何分支”的版本很愚蠢,所以我决定在这里发布。


3
git branch --contains <commit-id> --points-at <target branch name>

如果提交ID存在于目标分支中,它将返回目标分支的名称。否则该命令将失败。

不行... 错误:分支名称格式不正确 - bbodenmiller
1
你可能会在以下两种情况下遇到该错误:
  1. 给定的<分支名称>不包含给定的<提交ID>
  2. checkout <分支名称>与给定的<分支名称>不同
- DreamUth
1
我认为它已经改变了,现在如果目标分支没有提交,你将得到空值;如果目标分支不存在,则会出现错误。 - Philippe

0

由于这个问题有一些不错的脚本答案,我要添加我的最爱。

这个脚本将显示最近$n次提交中,每个分支包含哪些$br

br=mybranch
n=10
git log --oneline -n$n $br | awk '{print; system("git branch --contains "$1)}'

这个与之类似,但是针对分支列表执行相同的操作:

br="mybranch yourbranch herbranch"
n=4
for br in $brs; do git log --oneline -n$n $br | awk '{print; system("git branch --contains "$1)}'; done

0

在Windows/CMD终端上的Windows机器上,您可以执行以下操作:

> git log | findstr "commit-id"

例如:

> git log | findstr "c601cd6366d"

-1

Git checkout 命令会将你返回到当前 HEAD(当前文件)所在的分支,但它不会检出所有分支。例如,如果你执行 git checkout master 命令,代码将被检出,就好像你在 master 分支上一样,但它不会检出该分支之外的任何文件进行更改。


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