我已经阅读了类似场景的一些答案,但不是这个答案.
我需要在git上的特定分支上的两个提交之间生成一个提交列表.因此,应忽略对其他分支的任何提交.知道怎么做吗?
"之间"的概念在这里有点模糊,术语"分支"也没有明确定义(一般用git,即).让我看看尽管存在这些问题我是否可以保持这么短(对我来说很难:-)):
我将假设"在"之间,你的意思是git提交图中路径的图论理论.举例来说,假设我们有这样的图形片段(我不能画箭头的节点之间的弧线,而是假装每个-
,/
或\
在左侧的箭头头,这样的提交点直左,下,和左,或上下左右,给他们的前任):
o - o / \ ... - A - o - o - o - B <-- branch-x \ / o - o - C <-- branch-y
我已经确定了三个具体commits- A
,B
和C
-和提供了两个分支尖端的名称branch-x
和branch-y
指向提交B
和C
分别.为了git-usefulness-purpose,我们还假设有一个A
指向commit 的标记A
,这样我们就不必拼出它的SHA-1.
您可以通过三种方式A
从提交中获取提交B
.一开始B
,上升到顶线,下降到中间,然后向左移动A
.一开始B
,直接离开,最终到达A
.最后一个开始B
,向后退一步,向下,向左,向上和向左,再向左走一步A
.
Git的为您提供了特殊的双点语法A..branch-x
(或替代实际SHA-1的节点A
,如果你没有一个标签命名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
是为了保持两个最低提交而创建的.(如果有另一个分支名称指向单独的第三行提交,则更有可能,因为您的原始问题语句表示要排除所有其他分支 - 不仅仅是分支branch-y
- 在这种情况下并不重要.)
无论如何,虽然我不太清楚你的意思是"分支",也不知道你想要给出这个图的哪些提交,让我们来看看git实际提供的选择器.有一个重要的可能正是你的意思.
我之前提到"大多数"git命令使用相同的语法说明符.实际上,大多数git命令要么包含来自git rev-list
程序的代码,要么只是运行程序,其作用是选择对象(通常是提交对象)以获取要使用的提交ID列表.它也是您想要用于任何类型脚本的命令.
该rev-list
命令有许多令人眼花缭乱的选项,其中许多可以帮助进行各种图形遍历.我认为,这里最有趣的两个是--first-parent
和--not
.
--first-parent
我们--first-parent
先考虑一下.检查上面的图表(布局:它们可能看起来不同,但拓扑结构,它们是相同的).请注意,它是在合并提交时,如节点B
本身和节点左侧的节点B
,即路径fork.这是因为它只是具有多个传出弧的合并提交(这实际上是合并提交的定义:它是具有两个或更多父节点的节点).
当git进行合并提交时,它会将各个传出弧编号为多个父节点.第一个弧是特殊的:它是提交时的当前分支.也就是说,当你这样做时git merge
,你当时在某个分支上,1和当前提交的SHA-1成为新合并提交的"第一个父".额外的父母(合并的ID,通常只有一个,但git允许更多)是第二个,第三个,依此类推.
使用该--first-parent
标志告诉git仅遍历第一父弧.所以git rev-list --first-parent branch-x
将从commit开始B
,然后找到它的第一个父项(我们无法分辨哪个是上面的图中的第一个),遵循第一个(也是唯一的)父项,依此类推,一直回到root提交.
这可能是你想要的,也可能不是你想要的(尽管它对"之间"的概念没有帮助).
--not
现在让我们来看看--not
旗帜.2 通常,git rev-list
生成从给定SHA-1可到达的所有提交的集合(根据需要首先将名称解析为ID).也就是说,它遵循回到所有根的所有路径.结果是一组SHA-1 ID.使用--not
make会rev-list
排除这些ID.就其本身而言,这个否定集是没有用的,但是当与正常(非否定)集合结合时,它是有用的.事实上,它首先是如何A..B
工作的:rev-list
首先生成可以访问的所有提交的集合B
,然后减去可以从中访问的所有提交的集合A
.
因此,根据您的意思"排除其他分支上的所有提交",可能是您想要的是:
git rev-list branch1 --not branch2 branch3 ... branchN
你只需列出除了branch1
之后的每个分支--not
.
如果我们最后一次查看我们的图表,让我们看看选择了哪些提交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命令会说你不在任何分支上,但你仍然在使用构建分支的相同git内部.在这种情况下,您当前的分支根本没有名称.
2技术上--not
只是翻转一点,标记后续的SHA-1或标识符参数被否定.如果它们已经有前缀^
符号,它们将成为"正面"引用,否则它们将成为否定引用.因此x ^y z
意味着"是x,没有y,是z"而x --not y z
意味着"是x,没有y,没有z"并且x --not y ^z
意味着"是x,没有y,是z".
您可以使用以下命令轻松找到提交列表,
git log branch_name commit_x..commit_y
例如,
git log dev HEAD~20..HEAD~10
会告诉你10名单日至20 日为分支提交dev
。
您还可以通过的参数过滤所需的任何内容git log
。
您还可以使用以下命令将该日志存储到文件中 git log dev HEAD~20..HEAD~10 >> logs.txt