找到git commit来自哪个分支

Eth*_*son 594 git

有没有办法找出一个提交来自哪个分支给它的sha1?

如果您能告诉我如何使用Ruby Grit完成此任务,那么奖励积分.

Cas*_*bel 816

虽然Dav是正确的,信息不是直接存储的,但这并不意味着你无法找到.以下是您可以做的一些事情.

查找提交所在的分支

git branch --contains <commit>
Run Code Online (Sandbox Code Playgroud)

这将告诉您历史记录中具有给定提交的所有分支.显然,如果提交已经合并,这就不太有用了.

搜索reflogs

如果您在提交提交的存储库中工作,则可以在reflog中搜索该提交的行.超过90天的Reflogs由git-gc修剪,所以如果提交太旧,你将找不到它.也就是说,你可以这样做:

git reflog show --all | grep a871742
Run Code Online (Sandbox Code Playgroud)

找到提交a871742.输出应该是这样的:

a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite
Run Code Online (Sandbox Code Playgroud)

表示提交是在分支"完成"上进行的.默认输出显示缩写的提交哈希值,因此请确保不要搜索完整哈希值,否则您将找不到任何内容.

git reflog show实际上只是一个别名git log -g --abbrev-commit --pretty=oneline,所以如果你想摆弄输出格式,为grep提供不同的东西,那就是你的出发点!

如果您不在提交提交的存储库中工作,那么在这种情况下您可以做的最好的事情是检查reflog并查找提交何时首次引入您的repo; 运气好的话,你拿到了它所承诺的分支.这有点复杂,因为您不能同时同时执行提交树和reflog.您需要解析reflog输出,检查每个哈希以查看它是否包含所需的提交.

查找后续合并提交

这是与工作流相关的,但是如果工作流程很好,则会在开发分支上进行提交,然后将其合并.您可以这样做:

git log --merges <commit>..
Run Code Online (Sandbox Code Playgroud)

查看具有给定提交作为祖先的合并提交.(如果提交才被合并一次,第一个应该是你追求的合并,否则你就必须检查的几个,我想.)合并提交信息应包含被合并的分支名.

如果您希望能够依靠这样做,您可能希望使用该--no-ff选项git merge来强制创建合并提交,即使在快进的情况下也是如此.(不要过于急切,如果过度使用,可能会变得模糊不清.)VonC 对相关问题回答有助于详细阐述这一主题.

  • 仅供参考,如果你想找到只存在于遥控器上的提交,请在第一个命令中添加`-a`标志,例如`git branch -a --contains <commit>` (29认同)
  • 我绝对同意 - 分支机构应该是轻量级和灵活的.如果您采用的工作流程中信息变得很重要,您可以使用`--no-ff`选项来确保始终存在合并提交,因此您可以始终跟踪给定提交的路径,因为它已合并到主服务器. (9认同)
  • @JonathanDay:不,那将在任何分支上找到提交.如果你想在遥控器上只使用*,请使用`-r`. (7认同)
  • @SimonTewsi就像我说的,如果真的是一个问题,请在合并时使用`merge --no-ff`可靠地记录分支名称.但除此之外,将分支名称视为临时短标签,并将提交描述视为永久标签."在开发过程中我们提到了什么简称?" 应该真的不是一个重要的问题,如"这个承诺做了什么?" (6认同)
  • +1.完全没有该特定问题的信息会让您怀疑它是否真的存在问题?分支可以随时更改,重命名或删除.可能是`git describe`就足够了,因为(注释)标签可以被视为比分支更重要. (5认同)
  • @Jefromi 票证 ID 是元数据。如果可以在一个中心位置完成,为什么人们要写一百次并在提交消息中占用空间?提交消息仅描述了进行此特定提交的原因,而跟踪票则描述了一组连贯更改背后的想法和背景。 (3认同)
  • @VonC和Jefromi:我认为用于了解创建提交的分支的明显用例是确定更改所属的特征.我们为每个功能使用不同的分支,然后将其合并回发布分支.因为我们无法告诉一个分支来自另一个分支,所以很难一眼就知道提交最初是git的一部分.评论和标签有帮助,但不应该这么难. (2认同)

khi*_*nil 100

这个简单的命令就像一个魅力:

git name-rev <SHA>

例如(test-branch是分支名称):

git name-rev 651ad3a
251ad3a remotes/origin/test-branch
Run Code Online (Sandbox Code Playgroud)

即使这适用于复杂的情况,例如: git name-rev commit<SHA2>

这里git name-rev <SHA>返回branchB

  • 你救了我的一天.这是完美的解决方案. (3认同)
  • 我发现`git name-rev --name-only &lt;SHA&gt;`对于仅获取分支名称更有用。我的问题...在任何情况下都可以返回多个分支吗? (3认同)
  • 如果您只想查找分支名称和标签除外,可以使用以下命令: `git name-rev --refs="refs/heads/*" --name-only &lt;SHA&gt;` (3认同)
  • 这不能正常工作。在某些项目中,我已经在 master 中完成了所有提交,但是我提交上的这个“git name-rev”命令给出了我从未使用过的分支,特别是来自另一个用户的远程分支。这根本没有意义! (3认同)
  • 这个完美的解决方案仅用了8年的时间。谢谢! (2认同)
  • 不幸的是,这只在合并后、引用被垃圾收集之前的短时间内有效。这与 @Cascabel 的答案中的“搜索引用日志”方法具有相同的限制。正如 VonC 所指出的,保留此信息的唯一真正方法是,如果您的工作流程包括将其保存在 git note 或每次合并的带注释标签中。 (2认同)

Von*_*onC 45

2013年12月更新:

sschuberth 评论

git-what-branch(Perl脚本,见下文)似乎不再维护.
git-when-merged是一个用Python编写的替代方案,对我来说非常好用.

它基于" 查找包含特定提交的合并提交 ".

git when-merged [OPTIONS] COMMIT [BRANCH...]
Run Code Online (Sandbox Code Playgroud)

查找何时将提交合并到一个或多个分支中.
找到COMMIT引入指定BRANCH 的合并提交.

具体而言,查找BRANCH包含COMMIT作为祖先的第一父历史中最早的提交.


原答案2010年9月:

塞巴斯蒂安· 杜切(Sebastien Douche)刚刚开玩笑(在这个SO答案前16分钟):

git-what-branch:了解提交的分支,或者它如何到达命名分支

这是一个Perl脚本塞思·罗伯逊,这似乎很有意思:

概要

git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...
Run Code Online (Sandbox Code Playgroud)

概述

告诉我们(默认情况下)提交和合并的最早因果路径,以使请求的提交进入命名分支.
如果直接在命名分支上进行提交,那么这显然是最早的路径.

通过最早的因果路径,我们指的是最早通过提交时间合并到命名分支的路径(除非--topo-order指定).

性能

如果许多分支(例如数百个)包含提交,则系统可能需要很长时间(对于linux树中的特定提交,花费8秒来探索分支,但是有超过200个候选分支)来跟踪路径每次提交.
选择--reference-branch --reference tag要检查的特定内容将快几百倍(如果您有数百个候选分支).

例子

 # git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
   v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May  5 08:59:37 2005)
   v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May  3 18:27:24 2005)
   v2.6.12-rc3-461-g84e48b6 is on master
   v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
   [...]
Run Code Online (Sandbox Code Playgroud)

这个程序没有考虑樱桃选择利益提交的影响,只考虑合并操作.

  • "git-what-branch"似乎不再被维护了.[git-when-merged](https://github.com/mhagger/git-when-merged)是一个用Python编写的替代方案,对我来说效果很好. (3认同)

Eug*_*kov 30

例如,找到c0118fa提交来自redesign_interactions

* ccfd449 (HEAD -> develop) Require to return undef if no digits found
*   93dd5ff Merge pull request #4 from KES777/clean_api
|\  
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| *   a435005 Merge branch 'redesign_interactions' into clean_api
| |\  
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event
Run Code Online (Sandbox Code Playgroud)

你应该运行:

git log c0118fa..HEAD --ancestry-path --merges
Run Code Online (Sandbox Code Playgroud)

然后向下滚动以查找上次合并提交.这是:

commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date:   Sat Oct 1 00:54:18 2016 +0300

    Merge branch 'redesign_interactions' into clean_api
Run Code Online (Sandbox Code Playgroud)

UPD
或只有一个命令:

git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1
Run Code Online (Sandbox Code Playgroud)

  • 这是给我预期结果的唯一解决方案.我尝试了其余的. (4认同)
  • @EugenKonkov 一旦分支遍历了合并,关于它们来自图中的路径的历史记录将保留在引用日志中,但不会保留在 git 对象数据库中。我发布了一个答案试图解释我在说什么 (2认同)

phy*_*att 15

khichar.anil在他的回答中涵盖了大部分内容。

我只是添加了从修订名称列表中删除标签的标志。这给了我们:

git name-rev --name-only --exclude=tags/* $SHA
Run Code Online (Sandbox Code Playgroud)

  • 这正是我来这里的原因。感谢分享。 (2认同)

Col*_*ole 11

我尝试了上述所有解决方案,但没有一个对我有用。

这是迄今为止对我有用的唯一方法(假设HEAD处于合理的位置):

git log --branches --source | grep <sha>

#or if you also care about remotes
git log --branches --remotes --source | grep <sha>
Run Code Online (Sandbox Code Playgroud)

分支的名称应该位于行的末尾。

文档中

- 来源

打印出每次提交所到达的命令行上给出的引用名称。

因此,这可能会根据位置而改变HEAD,但对我来说,HEAD在主分支上放置最新的提交会产生我预期的结果。

目视检查gitk --all也可能有帮助。它为每个提交都有一个“分支”字段,但它显示“可以到达”该提交的所有分支,而不一定显示该提交“在”哪个分支。 看这里


在旁边:

还值得一提的是,这个问题有点用词不当。与其他 SVC 不同,git 分支只是指向提交历史记录/图表中位置的临时指针。他们不“拥有”提交,也不“由”提交“组成”。它们本质上只是标签,在签出标签时更新到您推送的任何提交。因此,分支不是一系列提交,而是指向一系列提交的结尾/尖端的指针。因此,提交不“属于”或“来自”分支,它们只是图中的节点。

那么我们实际上在这里做什么呢?我们正在使用可达性的想法。如果我们从每个分支指向的提交(“分支”的“结束”)开始并向后追溯历史记录,我们可以找到/到达哪些提交?如果找到提交的唯一方法是在该特定分支上开始搜索,则我们说提交位于分支“上”。

请注意,这不是一个稳定的事情。如果我们突然合并、重命名或变基我们的分支,那么我们的分支可以访问(因此“在”上)的提交将会改变。这就是为什么提交在特定分支上“属于”或属于特定分支并不是 git 中的官方概念或始终有意义的概念。(以及为什么这个问题没有明确/明确的答案)


Jef*_*ica 9

git branch --contains <ref>这是最明显的"瓷器"命令.如果你想只用"plumbing"命令做类似的事情:

COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
  if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
    echo $BRANCH
  fi
done
Run Code Online (Sandbox Code Playgroud)

(来自这个SO答案的交叉路口)


小智 5

我处理了同样的问题(Jenkins多分支管道)——只有提交信息并试图找到这个提交最初来自的分支名称。它必须适用于远程分支,本地副本不可用。

这就是我的工作:

git rev-parse HEAD | xargs git name-rev
Run Code Online (Sandbox Code Playgroud)

(可选)您可以剥离输出:

git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Run Code Online (Sandbox Code Playgroud)


Dim*_* C. 5

简短的回答是Git 不存储提交的分支的名称。尝试重建这些信息的技巧似乎并不在所有情况下都有效。

  • 同意,这基本上是 git 设计的限制。它故意不存储分支名称。但我觉得这是了解变化历史的相当重要的信息 (2认同)