[英]List all commits in a branch until a tag (including)
在一个分支中,我在4个不同的单独提交中添加了4个文件。 每个提交都有一个文件。 以下是示例提交消息
例如:
Adding file 1
Adding file 2 ---test-tag
Adding file 3
Adding file 4
我使用名为“test-tag”的标记标记了第二次提交。 我想列出此分支中的所有提交,从标记(包括包含标记的提交)开始到分支中的最新提交。 提交列表应包括标记的提交。 通过以下提交,我从标记中获取提交但不包括它。
git log --pretty=oneline test-tag..
对于大多数Git命令,双点..
表示法意味着排除左侧命名的提交,如您所见。 (所有提交的枚举都从右侧命名的提交开始,省略名称意味着“当前提交”,即HEAD
或@
。)因此,有两种方法可以解决这个问题:
后者似乎更简单,在大多数情况下实际上工作正常:
git log --boundary --pretty=oneline test-tag..
但是, - --boundary
在一些更复杂的情况下表现得很糟糕,所以我更喜欢用commit的父代开始排除。
使用后缀^
或后缀~
表示法很容易找到任何提交的第一个父级:
git log --pretty=oneline test-tag^..
git log --pretty=oneline test-tag~..
对于这种特殊情况,两者都会做你想要的,但它们也有轻微的缺陷。 尽管存在轻微缺陷,您可能希望熟悉这种表示法,因为它非常方便。 后缀代字号表示一个可选的数字(默认为1),它会计算出许多第一父母。
您没有显示您的四个提交的实际提交哈希ID,所以让我使用我自己的随机旧存储库:
$ git log --oneline -n 4
11ae6ca (HEAD -> master) add run-checks script
d1574b8 mxgroup.py: sort-of-mutual-exclusive-groups
b9491ea gerrit-review.sh: push to refs/for/
676699a wacky.py - replacing class-member functions
这些提交都没有被标记,所以让我们从HEAD
/ master
/ @
向后计数:
@~1
表示提交d1574b8
,退一步 @~2
b9491ea
表示提交b9491ea
,后退两步 @~3
676699a
表示提交676699a
,退回三步 等等。
hat或caret( ^
)后缀也可以使用数字,但这仅在有问题的提交是合并提交时才有意义。 合并提交是具有多个父级的任何提交,通常是两次使用git merge
来合并两个分支:
I--J <-- branch1
/
...--G--H
\
K--L <-- branch2
这里,名称branch1
和branch2
分别表示提交J
和L
(这里J
和L
依次代表实际的丑陋哈希ID。)
假设我们运行git checkout branch1
然后git merge branch2
。 Git将从两个分支提交向后移动,首先是一步到I
和K
,然后是两步到H
Commit H
在两个分支上,并且是两个分支提示之前的最佳共享提交,因此它是合并操作的合并基础。
然后,Git会将提交H
中的所有文件与提交J
所有文件进行比较,以查看某人在branch1
上branch1
。 另外,Git会将H
所有文件与L
的文件进行比较,以查看某人在branch2
上所做的工作。 然后,合并操作将这些更改组合在一起 ,将组合的更改应用于H
的文件。 如果一切顺利,Git会使用应用了两组更改的文件进行新的提交,即合并了两行开发。 新提交看起来像这样:
I--J
/ \
...--G--H M <-- ??? (what name points to M?)
\ /
K--L
新提交M
获取新的哈希ID,不同于每个现有和将来的提交。 现在必须更新某些分支名称以记住新提交M
更新的实际分支名称取决于您是否执行了git checkout branch1; git merge branch2
git checkout branch1; git merge branch2
,或git checkout branch2; git merge branch1
git checkout branch2; git merge branch1
。 无论您检出哪个分支, 该名称都会被移动,而另一个分支会保留在原位。 我们上面说过,我们假设你做了一个git checkout branch1
所以让我们将名称branch1
移动到指向新的提交M
:
I--J
/ \
...--G--H M <-- branch1
\ /
K--L <-- branch2
由于新提交M
记得两个先前的提交,而不仅仅是一个,我们现在有一些有趣的案例。 其中一个是M
的第一个父类:在这种情况下,它是提交J
因为名称branch1
曾经指向J
1所以M~1
和M^1
表示提交J
: M
的两个父母中的第一个 。
要查找提交L
, M
的第二个父项,则不能使用~
后缀。 您必须改为使用^
后缀,并写入M^2
。 这告诉Git: 找到提交M,然后找到它的第二个父级。
所以这就是^
后缀比~
后缀更有用的地方。 否则, ~
后缀是不是更有益~
后缀,因为你可以指望了。 但请注意,你可以组合后缀: M^2
让你提交L
,而M^2~
让你L
的父K
M^2~2
得到K
的父H
,你也可以使用M^1~2
,或者只是M~3
:从M
开始并返回三步,使用第一个父,只要有一个选择。
1如果我们以相反的方式进行合并,那么branch2
指向M
,其第一个父级为L
,第二个父级为J
除了父项是第一个以及哪个分支名称发生更改之外,合并过程通常是完全对称的。
假设我们继续使用此时的branch1
设置,要么写下M
的哈希ID,要么为我们设置标记以记住M
:
I--J ..... tag: test-merge
/ \ .
...--G--H M <-- branch1
\ /
K--L <-- branch2
然后我们继续做一些提交:
I--J ..... tag: test-merge
/ \ .
...--G--H M--N--O <-- branch1
\ /
K--L <-- branch2
如果我们现在想要git log
提交M
到O
包含该怎么办? 我们通常的写作技巧:
git log test-merge^..
不起作用,因为test-merge^
意味着找到提交M
,然后退回到它的第一个父J
,并排除J
(和更早) 。 结果是你看到KLMNO
:五个提交,你预期三个。
如果你试试:
git log test-merge^2..
你告诉Git 找到提交M
,然后退回到它的第二个父L
,并排除L
(和更早) 。 结果就是你看到了HIMNO
:再次提交了五次提交。
要在视觉上看到这一点,请绘制上面的图表。 使用红色荧光笔标记排除的提交。 让你的红色继续前进,标记你可以通过向后工作获得的所有早期提交。 然后,用绿色荧光笔标记第一个包含的提交。 保持绿色,标记您可以通过向后工作获得的所有早期提交,但在达到红色标记提交时停止。
获得你想要的三个提交的方法 - 除了--boundary
,有时可以工作,但有时不工作 - 告诉Git: 排除提交J
, 并排除提交L
您可以通过不使用双点表示法来执行此操作:
git log ^M^1 ^M^2 HEAD
这里的前缀 ^
告诉Git: 不是 。 所以git log
是从HEAD
开始并向后工作,但是排除 M^1
和M^2
。
当然,这只能起作用,因为M
只有两个父母。 我们列出他们都为“不显示此承诺,也没有任何更早”,我们得到了我们想要的东西。 但是如果我们选择非合并提交,则^<commit>^2
失败,因为没有第二个父级。 我们这里需要的是一个表示提交M
所有父母的符号。
事实证明只有这样的符号。 它(和许多其他的)列在gitrevisions文档中 ,这个特殊的拼写有后缀^@
。 所以我们得到了我们想要的东西:
git log test-merge^@..
无论所选提交的父项有多少,这都有效:我们排除所有提交,同时保留提交本身。
(还有一个相对较新的^-
后缀,也在Git 2.11中引入。这些文档页面偶尔值得重新阅读。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.