git日志版本范围给出不正确的提交范围 [英] git log revision range gives incorrect range of commits
问题描述
我试图使用参数 git log
来列出分支上给定范围内的所有提交。出于某种原因,它似乎并没有给我正确的结果(或者我理解命令错了?)。
下面是我为什么要在做:
-
克隆回购
git clone https://github.com/openstack/nova.git
-
做
git log
这些是最后9次提交:
d5bde44合并使元数据密码例程使用实例对象
6cbc9ee合并修复对象更改检测
39b7875合并修复nova.tests.objects.test_fields.TestObject中的对象泄漏
94d1034合并maint:正确的docstring参数说明
6407f17合并修复live_migration方法的文档字符串
7406661合并修复由于未命中重试信息而导致的无限重新计划实例
9d8a34f合并从test_compute_cells中删除未使用的代码
429cd4b修复对象更改检测
01381b8修复nova.tests.objects.test_fields.TestObject中的对象泄漏
...
-
可以说我想要在<$ c $之后开始所有提交C> 01381b8 。我发行
git log 01381b8..HEAD
,并看到以下输出:
d5bde44合并使元数据密码例程使用实例对象
6cbc9ee合并修复对象更改检测
39b7875合并修复nova.tests.objects.test_fields.TestObject中的对象泄漏
94d1034合并maint:正确的文档字符串参数说明
6407f17合并修复live_migration方法的文档字符串
7406661合并修复由于未命中重试信息而导致的无限重新计划实例
9d8a34f合并 test_compute_cells
429cd4b修复对象更改检测
2214bc0从test_compute_cells中删除未使用的代码
9639b55修复由于未命中重试而导致的无限重新计划实例信息
a5184d3修复live_migration方法的文档字符串
76729a3 maint :正确的docstring参数描述
28224a6使元数据密码例程使用实例对象
哇!当我预计 8 时,我实际上在该输出中获得了 13 提交。这里发生了什么?修订范围是在给定提交之后获得show commit的正确机制吗?或者这是一个错误?
这里的问题在于之后的滑动概念。
$ b
提交并不是之前和之后,因为它们嵌入图中。在这种情况下,由于存储库是可克隆的,我克隆了它。显然它是相当活跃的:
$ git log --oneline -9
77bad25合并删除不建议使用的配置选项名称: Juno Edition
d4d712a合并从指挥中弃用instance_get_by_uuid()
d5bde44合并使元数据密码例程使用实例对象
6cbc9ee合并修复对象更改检测
39b7875合并修复nova.tests.objects.test_fields.TestObject中的对象泄漏
94d1034合并maint:正确的docstring参数描述
6407f17合并修复live_migration方法的文档字符串
7406661合并修复无限
9d8a34f合并从test_compute_cells中删除未使用的代码
这比你最近的9次输出要新。但更有趣的是,如果他们记录在 - graph
添加的记录中(我会将数字加到10):
$ git log --oneline --graph -n 10
* 77bad25合并删除不建议使用的配置选项名称:Juno Edition
| \
| * d0a02fa删除不建议使用的配置选项名称:Juno Edition
* | d4d712a合并从指挥中弃用instance_get_by_uuid()
| \\
| * | 1d340cc从售票
* |中弃用instance_get_by_uuid() | d5bde44合并使元数据密码例程使用实例对象
| \ \\
| | / /
| * | 28224a6使元数据密码例程使用实例对象
* | | 6cbc9ee合并修复对象更改检测
| \ \\
| * | | 429cd4b修复对象更改检测
* | | | 39b7875合并修复对象泄漏在nova.tests.objects.test_fields.TestO
| \\\\\
| | / / /
| * | | 01381b8修复对象泄漏在nova.tests.objects.test_fields.TestObject
(我们得到了一组不同的最高提交因为 - graph
修改遍历,这就是为什么我去了10次提交)。
为了解会发生什么在这里,你需要超越 git log
到 git rev-list
。像许多git命令一样, git log
使用 git rev-list
选择要显示的修订版本(某些git命令字面上运行 git rev-list
,而其他人共享它的源代码,但无论哪种方式,它都可以实现。)
x..y
是 ^ xy
(或 y ^ x 或者 origin / stable / havana $ c $> - 这意味着同样的事情) c>或i像 HEAD
这样的间接名称,或者一个原始提交ID,或者一个简短的原始提交ID如 77bad25
, x
和 y
部分被解析为底层的git对象(在我们的例子中应该是提交)。您可以通过使用 git rev-parse
来观察解析步骤: $ git rev-parse master
77bad252096f7a4a8174340f0f2a3baf1fd52195
$ git rev-parse HEAD
77bad252096f7a4a8174340f0f2a3baf1fd52195
$ git rev-parse origin / stable / havana
0bf0bb4b5df64f7266c903a986d0b90a1f223822
什么 git rev-list
这提交找到它的父提交,然后从那些提交到他们的父母,等等。结果是一个祖先集。
在这一点上, master
的祖先没有特定的顺序:
-
master
本身: 77bad25 ...
-
master
的第一个父元素, git rev-parse master ^ 1
: d4d712a ...
-
master
'第二个父母 git rev-parse master ^ 2
: d0a02fa ...
-
master
的第一个父代的第一个父代, git rev-parse master ^ 1 ^ 1
: d5bde44 ...
-
master
的第一个父元素的第二个父元素 git rev-parse master ^ 1 ^ 2
: 1d340cc ...
当然还有很多,可以追溯到很多提交:
$ git rev-list master | wc -l
27918
所以 git rev-list master
选择所有27万个提交,而 git log master
会显示所有这些提交(按某种顺序,在通过 git log
)传递给 git rev-list
的附加选项上。
为了排除其中的一些,你可以告诉 git rev-list
开始一些特定的修订 - 例如 01381b8 $ (code> 01381b8
本身):
$ git rev-list 01381b8 | wc -l
27901
在这一点上,从 master
开始并向后工作(并且在第二个列表中没有提交,那个提交不在第一个列表中)。所以如果你告诉 git rev-list
给你从 master
开始的所有提交,所有提交从 01381b8
,你应该得到17次提交:
$ git rev-list高手^ 01381b8 | wc -l
17
这就是我们所看到的。 (实际的列表并不是那么有趣,但你可以通过 git rev-list master ^ 01381b8
,或者等价地看到它, git rev-list 01381b8..master
。)
这些提交是 git log
会显示的提交您可以花费数天的时间学习 git rev-list
文档,但仍然会错过项目(例如, - graph
)告诉您它启用父项重写和隐含 - topo-order
,直到我刚刚检查过,我忘记了父母的重写部分。幸运的是,这并不适用于此,只需要 - date-order
即可强制图形版本按日期排序而不是拓扑结构。)
I am trying to use list all commits within a given range on a branch using the argument of git log
. For some reason it doesn't seem to be giving me the right result (or maybe I'm understanding the command wrong?).
Here's the steps for what I'm doing:
Clone the repo
git clone https://github.com/openstack/nova.git
Do git log
and these are the last 9 commits:
d5bde44 Merge "Make metadata password routines use Instance object"
6cbc9ee Merge "Fix object change detection"
39b7875 Merge "Fix object leak in nova.tests.objects.test_fields.TestObject"
94d1034 Merge "maint: correct docstring parameter description"
6407f17 Merge "Fix live_migration method's docstring"
7406661 Merge "Fix infinitely reschedule instance due to miss retry info"
9d8a34f Merge "Remove unused code from test_compute_cells"
429cd4b Fix object change detection
01381b8 Fix object leak in nova.tests.objects.test_fields.TestObject
...
Lets say I want to get all the commits starting after 01381b8
. I issue git log 01381b8..HEAD
and the following output is seen:
d5bde44 Merge "Make metadata password routines use Instance object"
6cbc9ee Merge "Fix object change detection"
39b7875 Merge "Fix object leak in nova.tests.objects.test_fields.TestObject"
94d1034 Merge "maint: correct docstring parameter description"
6407f17 Merge "Fix live_migration method's docstring"
7406661 Merge "Fix infinitely reschedule instance due to miss retry info"
9d8a34f Merge "Remove unused code from test_compute_cells"
429cd4b Fix object change detection
2214bc0 Remove unused code from test_compute_cells
9639b55 Fix infinitely reschedule instance due to miss retry info
a5184d3 Fix live_migration method's docstring
76729a3 maint: correct docstring parameter description
28224a6 Make metadata password routines use Instance object
Wow! I actually got 13 commits in that output when I expected 8. What is going on here? Is the revision range the correct mechanism to get show commits after a given commit? Or is this a bug?
解决方案 The problem here lies with the slippery notion of "after".
Commits are not so much "before" and "after" as they are "embedded in a graph". In this case, since the repository is clone-able, I cloned it. Apparently it's fairly active:
$ git log --oneline -9
77bad25 Merge "Remove deprecated config option names: Juno Edition"
d4d712a Merge "Deprecate instance_get_by_uuid() from conductor"
d5bde44 Merge "Make metadata password routines use Instance object"
6cbc9ee Merge "Fix object change detection"
39b7875 Merge "Fix object leak in nova.tests.objects.test_fields.TestObject"
94d1034 Merge "maint: correct docstring parameter description"
6407f17 Merge "Fix live_migration method's docstring"
7406661 Merge "Fix infinitely reschedule instance due to miss retry info"
9d8a34f Merge "Remove unused code from test_compute_cells"
This is newer than your last-9 output. More interesting, though, is how these look if they are logged with --graph
added (and I'll bump the number to 10):
$ git log --oneline --graph -n 10
* 77bad25 Merge "Remove deprecated config option names: Juno Edition"
|\
| * d0a02fa Remove deprecated config option names: Juno Edition
* | d4d712a Merge "Deprecate instance_get_by_uuid() from conductor"
|\ \
| * | 1d340cc Deprecate instance_get_by_uuid() from conductor
* | | d5bde44 Merge "Make metadata password routines use Instance object"
|\ \ \
| |/ /
| * | 28224a6 Make metadata password routines use Instance object
* | | 6cbc9ee Merge "Fix object change detection"
|\ \ \
| * | | 429cd4b Fix object change detection
* | | | 39b7875 Merge "Fix object leak in nova.tests.objects.test_fields.TestO
|\ \ \ \
| |/ / /
| * | | 01381b8 Fix object leak in nova.tests.objects.test_fields.TestObject
(we get a different set of "topmost" commits because --graph
modifies the traversal, which is why I went to 10 commits).
To understand what's going on here, you need to look beyond git log
to git rev-list
. Like many git commands, git log
uses git rev-list
to pick revisions to display. (Some git commands literally run git rev-list
while others share its source code, but either way it works out the same.)
The git revision notation x..y
is shorthand for ^x y
(or y ^x
—these mean the same thing). Whether you write a name like master
or origin/stable/havana
, or an indirect name like HEAD
, or a raw commit-ID, or a shortened raw commit-ID like 77bad25
, the x
and y
parts are resolved to the underlying git object (which in our case should be a commit). You can observe the resolving step by using git rev-parse
:
$ git rev-parse master
77bad252096f7a4a8174340f0f2a3baf1fd52195
$ git rev-parse HEAD
77bad252096f7a4a8174340f0f2a3baf1fd52195
$ git rev-parse origin/stable/havana
0bf0bb4b5df64f7266c903a986d0b90a1f223822
What git rev-list
does with this is to work backwards from this commit to find its parent commit(s), and then from those commits to their parents, and so on. The result is an ancestor-set.
The ancestors of master
are, at this point, in no particular order:
master
itself: 77bad25...
master
's first parent, git rev-parse master^1
: d4d712a...
master
's second parent, git rev-parse master^2
: d0a02fa...
master
's first parent's first parent, git rev-parse master^1^1
: d5bde44...
master
's first parent's second parent, git rev-parse master^1^2
: 1d340cc...
and of course many more, going back for many commits:
$ git rev-list master | wc -l
27918
So git rev-list master
selects all 27-thousand-and-some commits, and git log master
would show you all of them (in some order, with the order modified based on additional options passed to git rev-list
via git log
).
To exclude some of those, you can tell git rev-list
to start with some particular revision—such as 01381b8
—and find all of its ancestors (including 01381b8
itself):
$ git rev-list 01381b8 | wc -l
27901
At this point, this is 17 fewer commits than are found by starting at master
and working backwards (and there are no commits in this second list that are not already in that first one). So if you tell git rev-list
to give you "all commits starting from master
, minus all commits starting from 01381b8
", you should get 17 commits:
$ git rev-list master ^01381b8 | wc -l
17
and indeed that's what we see. (The actual list is not all that interesting, but you can see it with git rev-list master ^01381b8
, or equivalently, git rev-list 01381b8..master
.)
These commits are the ones git log
will show you, given the same revision range.
You can spend days studying the git rev-list
documentation and still miss items (for instance, --graph
tells you that it "enables parent rewriting" and "implies --topo-order
" and until I checked just now, I had forgotten about the parent rewriting part. Fortunately that does not apply here anyway, just the need for --date-order
to force the graphed version to sort by date rather than topologically.)
这篇关于git日志版本范围给出不正确的提交范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!