繁体   English   中英

Git 记录 2 个标签并过滤特定路径的提交

[英]Git log 2 tags and filter commits for a particular path

我有一个包含许多不同文件夹和标签的存储库。 我想列出特定文件夹的 2 个发布标签之间的提交。

我试过git log --oneline -- ${folder path} tag1 tag2它似乎只过滤到指定文件夹路径中的提交,但它似乎显示的提交比标签 1 和标签 2 之间的差异更多。

有没有办法列出特定指定文件夹路径的 2 个不同标签之间的提交?

这里有很多问题:

  • --选项之后的所有内容都被视为文件名。 (例如,这使您可以查找名为master文件。)因此,此处的tag1tag2被视为文件名——它们不是指任何提交。 解决这个问题很容易,因为您只需将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我们 go K然后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.7v0.8之间? 我想大多数人都会同意它是IMN ,或者可能HIMNO ,或者类似的东西。

但是:哪些提交是“介于”标签v0.7v0.9之间? 哪些在v0.8v0.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的任何分支或标签名称都算作以下之一:

  • 一个起点:一个你想要向后工作的提交,或者
  • 一个停止点:您希望 Git包括的提交,也不包括它的任何祖先

例如,假设我们有第一张图:

     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 PONMIHG等等。 但是,通过告诉 GitL处停止,我们真正的意思是L到达的任何提交处停止:所有LKJG等向后都是停止点。

我们可能用于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指向提交Kv0.9..v0.8将查看以O开头的提交并向后工作,直到它停止在G 0.90.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM