[英]Git log 2 tags and filter commits for a particular path
我有一个包含许多不同文件夹和标签的存储库。 我想列出特定文件夹的 2 个发布标签之间的提交。
我试过git log --oneline -- ${folder path} tag1 tag2
它似乎只过滤到指定文件夹路径中的提交,但它似乎显示的提交比标签 1 和标签 2 之间的差异更多。
有没有办法列出特定指定文件夹路径的 2 个不同标签之间的提交?
这里有很多问题:
--
选项之后的所有内容都被视为文件名。 (例如,这使您可以查找名为master
的文件。)因此,此处的tag1
和tag2
被视为文件名——它们不是指任何提交。 解决这个问题很容易,因为您只需将tag1
和/或tag2
移动到--
的另一侧。
之间的整个概念很棘手,因为提交不一定都排在整齐的一排。 解决这个问题可能要困难得多:您必须确定之间的含义。
当您为git log
提供路径名称时,这将启用它所谓的历史简化。 对于您的特定用途而言,这是否真的是一个问题也是一个难题,但如果它是一个问题,解决它实际上很容易:只需添加--full-history
以禁用历史简化。
所以你可能想要:
git log --oneline --full-history <something with the tags> -- <folder-name>
仅当结果中似乎缺少某些提交时才需要--full-history
。
something
首先,请记住,Git 中的每个提交都包含所有文件的完整快照,以及有关该快照的一些元数据:谁制作了它(作者姓名,email,以及日期和时间戳加上相同的committer),一条日志消息,以及——对我们来说最重要的——一些先前提交的原始 hash ID,Git 将其称为此提交的父级或父级。
每个提交都有一个独特的、又大又丑的 hash ID。 这实际上是提交的真实名称。 所有其他名称,无论是像master
这样的分支名称、像v2.1
这样的标签名称,还是像HEAD~3
这样的相对名称,都只是让 Git 找到原始 hash ID 的一种方式。 同时,每个名称(包括分支名称和标签名称)仅包含一个hash ID。 当一个 hash ID 是一个特定的提交时, 1就是由分支或标签命名的提交。 我们说名称指向提交。
但由于提交还包含提交 hash ID,因此提交也指向提交。 事实上,这正是 Git 存储库中历史的发生方式。 一个名称——通常是像master
这样的分支名称——通过持有其 hash ID 指向最后一次提交。 如果我们让H
代表实际的 hash ID,我们可以这样画:
H <-- master
同时,提交H
包含其父提交的 hash ID。 我们称其为G
,因此H
指向G
:
G <-H <-- master
当然G
有它自己的父级。 我们称之为F
,它也有自己的父级,依此类推:
... <-F <-G <-H <-- master
这是一个很好的简单线性提交链。 如果存储库中只有八个提交,都像这样连续排列,我们可以将它们绘制为:
A--B--C--D--E--F--G--H <-- master
由于懒惰和缺乏角度方向的箭头,我现在使用线条而不是箭头来连接提交,但请记住它们实际上都是向后指向的箭头。 我们可以使用内部箭头将 go 从提交H
返回到A
,但不能从A
转发到H
。
(提交A
很特殊:作为某人的第一个提交,它不能有父提交,所以它没有。Git 将此称为根提交。每个非空 Git 存储库都有至少一个根提交。这就是当我们回顾历史时,我们可以停止追溯。)
要将新提交添加到某个分支,Git 只需用指向当前提交的箭头写出新提交,然后将新提交的实际 hash ID 写入分支名称。 例如,从:
...--G <-- master
至:
...--G--H <-- master
Git 刚刚用父 hash G
编写了新的提交H
,然后将H
的实际 hash 写入名称master
。
但 Git 的历史往往不是这样的线性。 人们创建新的分支,然后在这些分支上进行新的提交,这会导致如下图:
I--J <-- br1
/
...--G--H--L <-- master
\
K <-- br2
随后有人可能会做git checkout master; git merge br1
git checkout master; git merge br1
以将分支 1 重新合并到master
中,这会产生:
I--J <-- br1
/ \
...--G--H--L---M <-- master
\
K <-- br2
新的合并提交M
指向L
(作为它的第一个父节点)和J
(作为它的第二个父节点)。
技巧问题:在哪个分支上提交
H
?答:实际上是在所有三个分支上。 Git 在这里很特别:许多版本控制系统保存提交是在哪个分支上进行的,而这就是提交所在的分支,永远。 Git 不会将此信息保存在任何地方。 如果您可以从分支名称指向的提交开始到达该提交,则该提交位于分支上。 因此,从
master
开始,我们可以在从L
的一跳中返回H
,或者在添加M
后从M
的两跳中返回 H 。 从br1
开始,我们可以分两跳回到H
:从J
开始,go 到I
,然后是H
。 从br2
我们 goK
然后H
。 所以H
在所有三个分支上。
1分支名称被限制为仅包含提交 hash ID,因此分支名称自动指向提交。 标签名称的限制较少:它们可以直接指向提交,在这种情况下,Git 称它们为轻量级标签。 或者,他们可以指向一个标签 object ,它有自己唯一的 hash ID。 然后标记 object 指向另一个对象(通常是提交),因此标记仍然指向提交,但通过标记 object 间接指向。 这就是您可以使用额外信息(例如发行说明或 GPG 签名)制作带注释的标签的方法。
让我们使用其中一种图表并添加一些标签名称,它们像分支一样指向特定的提交,但不一定位于分支的末尾。 (特别是,一旦你创建了一个标签名称,你应该让它永远指向同一个提交,通过它的 hash ID。)所以我们可能有:
tag:v0.7 tag:v0.8
| |
v v
...--G--H--I--M--N--O--P <-- branch1
\
J--K--L <-- branch2
^
|
tag:v0.9
哪些提交是“介于”标签v0.7
和v0.8
之间? 我想大多数人都会同意它是IMN
,或者可能HIMNO
,或者类似的东西。
但是:哪些提交是“介于”标签v0.7
和v0.9
之间? 哪些在v0.8
和v0.9
之间? 我想很多人会不同意。
如果事实证明提交M
实际上是一个合并,而不是常规提交,那么绘图应该看起来像这样:
tag:v0.7 tag:v0.8
| |
v v
...--G--H--I---M--N--O--P <-- branch1
\ /
J--K--L <-- branch2
^
|
tag:v0.9
现在哪些提交在各个标签“之间”?
Git 给你的东西——Git 给你的所有东西——是使用各种修饰符来遍历实际图形的能力。 Git 通过从结尾开始(例如,在像P
这样的提交处)并向后工作,在它可以实际工作的唯一方向上,使用连接提交的那些向后指向的箭头来做到这一点。
您提供给git log
的任何分支或标签名称都算作以下之一:
例如,假设我们有第一张图:
tag:v0.7 tag:v0.8
| |
v v
...--G--H--I--M--N--O--P <-- branch1
\
J--K--L <-- branch2
我们告诉 Git:从P
开始,但在L
停止。 显然,从P
开始实际上不会让我们提交L
,因为我们 go P
、 O
、 N
、 M
、 I
、 H
、 G
等等。 但是,通过告诉 Git在L
处停止,我们真正的意思是在从L
到达的任何提交处停止:所有L
、 K
、 J
、 G
等向后都是停止点。
我们可能用于从P
开始但在L
停止的语法是:
branch2..branch1
这意味着从branch1
的尖端(即P
)可到达的所有提交,不包括从branch2
的尖端(即L
)可到达的所有提交。
相同的语法适用于标签名称。 实际上,它的工作方式完全相同:仅提及标签名称,如git log v0.8
中,意味着将此标签指向的提交视为起点。 提到两个标签名称,它们之间有两个点,意味着将此标签指向的提交视为停止点。 所以:
v0.7..v0.8
将从O
开始并在H
停止。 这将排除提交H
,即它只会查看提交O
,然后是N
,然后是M
,然后是I
。
如果名称v0.9
指向提交K
, v0.9..v0.8
将查看以O
开头的提交并向后工作,直到它停止在G
。 0.9
在0.8
之后并不重要。 Git 根本没有使用这些数字。 Git 专门使用图表来包含或排除各种提交。
当图表中有合并时,事情就会变得棘手。 在这里,您有时可能需要一个额外的标志--ancestry-path
。 但就像--full-history
一样,这开始变得有点复杂,所以我们可能应该到此为止。
不过,我忍不住要提到第三种选择,因为有些人在说“介于”时会想要这个。 除了两点语法stop..start
,还有一个三点语法。 这意味着可以从任一名称访问的所有提交,除了可从两个名称访问的所有提交。 也就是说,给定:
...--G--H--I--M--N--O--P <-- branch1
\
J--K--L <-- branch2
语法branch1...branch2
表示提交HIMNOP
并提交JKL
(但不是按此顺序,因为 Git 必须向后工作)。 排除的提交从G
开始并向后工作,因为G
在两个分支上。
你的语法几乎是正确的。
要列出一系列提交,请使用tag1..tag2
,并将所有提交放在--
之前。 因此,您的命令应如下所示:
git log --oneline tag1..tag2 -- path
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.