问题描述
我试图使用参数 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 的祖先没有特定的顺序:
当然还有很多,可以追溯到很多提交:
$ 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日志版本范围给出不正确的提交范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!