【问题标题】:Git: get commits between two commits on a specific branchGit:获取特定分支上两次提交之间的提交
【发布时间】:2015-12-31 04:36:52
【问题描述】:

我已经阅读了许多类似场景的答案,但不是这个精确的答案。

我需要生成在 git 上特定分支上的两次提交之间发生的提交列表。所以任何对其他分支的提交都应该被忽略。知道怎么做吗?

【问题讨论】:

  • 如果你选择了一个合并提交和一个分支提交,你需要澄清你想要什么。另一方面,您是在寻找一些 bash 脚本来过滤来自 git 的输出,还是在寻找 git 下的一些命令?
  • 嗨@orb,谢谢!是的,我正在寻找一个 bash 命令。分支,即使是从过去昏暗的某个地方的 master 创建的,也是非常不同的,所以在其他分支上发生的任何提交都与我的场景无关。
  • 在你推送一个分支后,提交上表明它在一个分支中的签名被删除,所以你(git)无法判断以前的提交是否在分支主控中,比如说,或者不是.它的分支活动仅由有关每个提交的父提交哈希的信息记录。您可以通过命令git rev-list --parents -n <number of commits to track> <commit hash> 跟踪父提交

标签: git


【解决方案1】:

“之间”的概念在这里有点模糊,“分支”一词也没有很好的定义(通常是 git)。让我看看尽管有这些问题,我是否可以保持简短(对我来说很难:-)):

我将假设“之间”是指 git 提交图中的 path 的图论概念。例如,假设我们有这个图形片段(我不能为节点之间的弧线绘制箭头,但假设每个 -/\ 在左侧都有一个箭头,以便提交指向直线左、下和左,或上和左,到他们的前任):

              o - o
            /       \
... - A - o - o - o - B   <-- branch-x
            \   /
              o - o - C   <-- branch-y

我已经确定了三个特定的提交——ABC——并提供了两个分支提示名称 branch-xbranch-y 分别指向提交 BC。出于 git 实用性的目的,我们还假设有一个标签 A 指向提交 A,这样我们就不必拼出它的 SHA-1。

您可以通过三种可能的路径从提交B 到达提交A。一个从B 开始,上升到顶线,下降到中间,然后向左移动到A。一个从B 开始,直接向左走,最终到达A。最后一个从B开始,后退一步,向下向左,向上向左,再向左到达A

Git 为您提供了特殊的两点语法 A..branch-x(如果您没有名为 A 的标签,则用实际的 SHA-1 替换节点 A),对于大多数命令,这表示他们应该访问所有B回到A所有可能路径上的节点,通常包括节点B本身,不包括节点A。这几乎是您想要的,但不完全是,因为您想排除在其他分支上进行的提交。

这带来了一个无法回答的(通常)问题“哪些提交是在哪个分支上进行的?”

Git 试图告诉你这个问题是无效的:你不应该关心;您应该只关心所有这些提交都可以从节点B 访问。 Git 实际上通常对此是正确的,但“通常”不是“总是”。不幸的是,我还没有找到任何好的方法来描述您何时应该(或应该)关心(实际的好例子对我正在尝试编写的文本很有帮助)。

与此同时,让我们继续前进。从上图中可以清楚地看出,下一行的提交都是“在branch-y 上进行的”。这里有一个问题,因为它看起来很清楚,但实际上可能不是正确。考虑一下如果我们重新绘制图表会发生什么:

              o - o
            /       \
... - A - o - o - o - B   <-- branch-x
            \   /
              o
                \
                  o - C   <-- branch-y

这一次,branch-y 似乎只是为了保存两个最低的提交而创建的。 (如果有另一个分支名称指向唯一的第三行提交,则更有可能,尽管因为您最初的问题陈述说要排除 all 其他分支 - 而不仅仅是分支 branch-y - 那不会'在这种情况下真的很重要。)

不管怎样,虽然我不太清楚你所说的“分支”是什么意思,也不知道根据这张图你想要哪些提交,让我们来看看 git 实际提供的选择器。有一个重要的可能正是你的意思。

我之前提到“大多数” git 命令使用相同的语法说明符。事实上,大多数 git 命令要么包含来自 git rev-list 程序的代码,要么只是运行,该程序的工作是选择对象(通常是提交对象)以获得您想要使用的提交 ID 列表。它也是任何类型的脚本都需要的命令。

rev-list 命令has a dizzying number of options,许多用于协助各种图形遍历。我认为这里最有趣的两个是--first-parent--not

使用--first-parent

让我们首先考虑--first-parent。检查上面的图表(两种布局:它们可能看起来不同,但在拓扑上它们是相同的)。请注意,它是在 merge 提交时,如节点 B 本身和 B 左边一步的节点,路径分叉。这是因为它只有合并提交具有多个传出弧(这实际上是合并提交的定义:它是一个具有两个或多个父节点的节点)。

当 git 进行合并提交时,它会将各个传出弧编号到多个父级。第一条弧很特别:它是提交时的当前分支。也就是说,当您执行git merge &lt;sha-1-or-equivalent&gt; 时,您当时在某个分支上,1 并且当前提交的 SHA-1 成为新合并提交的“第一个父级”。额外的父母(合并的 ID,通常只有一个,但 git 允许更多)是第二个、第三个等等。

使用--first-parent 标志告诉 git 只遍历第一父弧。所以git rev-list --first-parent branch-x 将从提交B 开始,然后找到它的第一个父级(我们无法从上图中分辨出哪个是第一个),然后是第一个(也是唯一的)父级,依此类推,一直返回到根提交。

这可能是也可能不是您想要的(尽管它对“介于”的概念没有帮助)。

使用--not

现在让我们看一下--not 标志。2 通常,git rev-list &lt;SHA-1-ID-or-name&gt; 会生成从给定 SHA-1 可访问的所有提交的集合(根据需要首先将名称解析为 ID) .也就是说,它遵循所有路径返回所有根。结果是一组 SHA-1 ID。使用--not 会使rev-list 排除这些ID。这个否定集本身没有用,但是当与正常(非否定)集结合使用时,它有用的。事实上,A..B 首先是这样工作的:rev-list 首先生成从 B 可访问的所有提交的集合,然后减去从 A 可访问的所有提交的集合。

因此,根据您所说的“排除其他分支上的所有提交”的含义,可能您想要的是:

git rev-list branch1 --not branch2 branch3 ... branchN

您只需在--not 之后列出除branch1 之外的所有分支。

如果我们最后看一下我们的图表,让我们看看branch-x --not branch-y选择了哪些提交:

              o - o
            /       \
... - A - o - o - o - B   <-- branch-x
            \   /
              o - o - C   <-- branch-y

提交C 显然可以从branch-y 访问,最下一行的所有提交也是如此。 A 右侧的提交也是可访问的,提交 A 本身和所有早期提交也是如此。其余提交可从branch-y 访问,但branch-x 提交B 可访问,因此结果图为:

              o - o
            /       \
            - o - o - B   <-- branch-x

请注意,rev-list 具有 --boundary 以包含“剪切点”(如果我可以这样称呼它们);添加--boundary 在原始图中将节点放回A 之后(但A 本身仍然被剪掉)。

(根据您修改后的问题,--not 可能是您想要的,您只需要获取所有分支的列表,其中git for-each-ref --format '%(refname:short)' refs/heads 是正确的脚本命令。分离出其节点的一个分支你想保留,把剩下的放在--not后面,然后运行git rev-list。)


1即使您在匿名分支上(换句话说,在“分离 HEAD”模式下),这实际上也是正确的。一些 git 命令会说您不在任何分支上,但您仍在使用与 build 分支相同的 git 内部结构。在这种情况下,您当前的分支根本没有名称。

2从技术上讲,--not 只是翻转了一点,将随后的 SHA-1-or-identifier 参数标记为被否定。如果它们已经有前缀^ 符号,它们将成为“正”引用,否则它们将成为负引用。例如,x ^y z 表示“是 x,没有 y,是 z”,而 x --not y z 表示“是 x,没有 y,没有 z”,x --not y ^z 表示“是 x,没有 y,是 z”。

【讨论】:

  • 我只想说谢谢你如此详细而透彻的解释。这对于理解 git 的工作原理非常有用。
【解决方案2】:

您可以使用以下命令轻松找到提交列表,

git log branch_name commit_x..commit_y

例如,

git log dev HEAD~20..HEAD~10 将向您显示分支 dev 的第 10th 到 20th 次提交的列表。

您还可以通过git log 的参数过滤您想要的任何内容。

您也可以使用git log dev HEAD~20..HEAD~10 &gt;&gt; logs.txt将此日志存储到文件中

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-29
    • 2017-06-19
    • 2015-11-18
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 2019-11-12
    • 2012-07-24
    相关资源
    最近更新 更多