在一个分支中,我在4个不同的单独提交中添加了4个文件。每个提交都有一个文件。下面是示例提交消息
例如:
Adding file 1
Adding file 2 ---test-tag
Adding file 3
Adding file 4
我用名为“ test-tag”的标签标记了第二次提交。我想列出该分支中所有的提交,从标记(包括包含该标记的提交)到分支中的最新提交。提交列表也应包括已标记的提交。使用下面的提交,我将从标记中获得提交,但不包括它。
git log --pretty=oneline test-tag..
答案 0 :(得分:0)
对于大多数Git命令,两点..
表示不包括左侧命名的提交,如您所见。 (所有提交的枚举均从右侧命名的提交开始,省略名称意味着“当前提交”,也就是HEAD
或@
。)因此,有两种方法可以解决此问题:
后者似乎更简单,并且实际上在大多数情况下都可以正常工作
git log --boundary --pretty=oneline test-tag..
但是,--boundary
在某些更复杂的情况下表现较差,因此我更喜欢从提交的父项开始排除。
使用后缀^
或后缀~
表示法,很容易找到任何提交的第一个父级:
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
,后退两步@~3
表示提交676699a
,后退三步以此类推。
帽子或插入符号(^
)后缀也可以带有数字,但这仅在所涉及的提交是 merge commit 时才有意义。合并提交是指具有个以上父级的任何提交,通常是两个使用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
。提交H
在两个分支上,并且是两个分支技巧之前的最佳共享提交,因此它是合并操作的合并基础。>
Git然后将提交H
中的所有文件与提交J
中的所有文件进行比较,以查看某人在branch1
上所做的工作。另外,Git将H
中的所有文件与L
中的所有文件进行比较,以查看某人对branch2
所做的工作。然后,合并操作合并这些更改,将合并的更改应用于H
中的文件。如果一切顺利,Git将使用应用了两组套变更的文件(即,已合并了两条开发线)进行新的提交。新的提交如下所示:
I--J
/ \
...--G--H M <-- ??? (what name points to M?)
\ /
K--L
新提交M
获得一个新的哈希ID,该ID与每个现有和将来的提交都不同。现在必须更新 Some 分支名称,以记住新的提交M
。更新后的实际分支名称取决于您执行的是git checkout branch1; git merge branch2
还是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
的两个父对象的 first 。 / p>
要查找提交{{1}的父级 second 的提交L
,则不能使用后缀M
。您必须改用~
后缀,并写成^
。这告诉Git:找到提交M,然后找到其第二父级。
因此,这是M^2
后缀比^
后缀更有用的地方。否则,后缀~
比后缀~
更有用,因为您可以倒数。不过请注意,您可以组合后缀:~
使您提交M^2
,而L
使您成为M^2~
的父项L
。 K
让您成为M^2~2
的父母K
,也可以通过使用H
或仅仅使用M^1~2
来达到:M~3
然后返回三个步骤,只要有选择就使用第一位父母。
1 如果相反进行合并,则M
指向branch2
,它的第一个父级是M
,第二个父级是L
。除了哪个父节点是第一父节点和哪个分支名称发生更改之外,合并过程通常是完全对称的。
假设我们现在继续进行J
设置,要么记下branch1
的哈希ID,要么设置一个标记为我们记住M
:>
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
:五次提交,您期望三次提交。
如果您尝试:
K-L-M-N-O
您正在告诉Git 找到提交git log test-merge^2..
,然后退回到第二个父M
,并排除L
(及更早版本)。结果是您看到L
:再次提交了5次。
要直观地查看,请在上方绘制图形。用红色荧光笔标记已排除提交。保持前进状态,标记所有可以通过向后工作而到达的较早提交。然后,用绿色荧光笔标记第一个 included 提交。保持绿色前进,标记所有可以通过向后工作而到达的较早的提交,但是当您到达带有红色标记的提交时就停止。
只获得您想要的三个提交的方法(除了H-I-M-N-O
有时有效,但有时无效)是告诉Git:排除提交--boundary
,并排除提交J
。您可以通过不使用两点符号来实现:
L
此处的前缀 git log ^M^1 ^M^2 HEAD
告诉Git:不是。因此,^
将从git log
开始并向后工作,但是排除 HEAD
以及M^1
。
当然,这仅是因为M^2
正好有两个父母。我们将其中的 都列为“不显示此提交,也没有更早的显示”,我们得到了想要的东西。但是,如果我们选择非合并提交,则M
会失败,因为没有第二亲。我们需要的是一种表示提交^<commit>^2
的所有父母的符号。
事实证明只有这样一种表示法。它(以及许多其他)在the gitrevisions documentation中列出,并且此特定字符的后缀为M
。这样我们就能得到想要的东西:
^@
无论选择的提交有多少父母,此方法都有效:我们将所有 排除在外,同时保留提交本身。
(Git 2.11中也引入了一个相对较新的git log test-merge^@..
后缀。这些文档页面值得偶尔阅读。)