Git日志算法

Git日志算法,git,algorithm,Git,Algorithm,我使用“git log^”命令是为了确保两个分支(比如说当前版本和以前的版本)之间没有不属于当前版本的提交(我们在提交消息中使用记录编号,这是比较的基础) 我基本上想知道命令背后的算法是什么。有人知道它是如何工作的吗? 我想您可以获得两个分支的所有提交,并逐一比较它们。但是,如果历史很长,这可能是一个漫长的过程。 但我认为有一种更聪明的方法可以做到这一点。想法是找到共同的祖先,但不确定这是否可行以及如何实现 如果有人能告诉我,那就太好了:)您可以使用cherry命令来查找缺少的提交 e、 假设您

我使用“git log^”命令是为了确保两个分支(比如说当前版本和以前的版本)之间没有不属于当前版本的提交(我们在提交消息中使用记录编号,这是比较的基础)

我基本上想知道命令背后的算法是什么。有人知道它是如何工作的吗?
我想您可以获得两个分支的所有提交,并逐一比较它们。但是,如果历史很长,这可能是一个漫长的过程。
但我认为有一种更聪明的方法可以做到这一点。想法是找到共同的祖先,但不确定这是否可行以及如何实现


如果有人能告诉我,那就太好了:)

您可以使用
cherry
命令来查找缺少的提交

e、 假设您的第一个分支是r1,最新的分支是r2

git签出r1

吉特樱桃r2

这将报告r2分支中不存在的所有提交


以下是评论中的文档,您注意到:

我说的确实是插入符号

以及:

。。我本应该明确我的目的是在以后使用Bitbucket API(而不是标准git命令)完成这项工作

这将使您的工作非常困难,除非您使用的API部分是
git clone
:-)到底有多困难取决于您是否能够仅获得关于每个提交对象的信息,或者是否需要与之相当的
git cherry

是正确的:
git log
git rev list
要实现
^branch\u exclude branch\u include
branch\u exclude..branch\u include
syntax from,需要在提交图上运行广度和/或深度优先搜索。(根据中的代码,它主要是广度优先。)

当然,这需要构造提交图,或者至少构造足够的提交图

在Git内部,每个提交都由其散列ID命名。每个提交都由一个小文本对象组成,其中包括提交的父散列ID(每个父散列ID一个)。这两个部分,加上一个起始点,如
头的ID
提交或某个分支名称的ID,就是我们需要进行最简单类型的遍历,即标准
git rev list
图遍历

请注意,大多数提交只有一个父级:这些是普通提交。图中至少有一个提交没有父级,是“根”提交。在存储库中进行的第一次提交始终是根提交(您可以使用git checkout--orphan或使用git的管道命令创建更多根)。有些提交是合并:它们有两个或多个父级

简单图游动 有许多图形漫游算法(请参阅Sedgewick、Aho和Knuth的各种书籍),但Git从一个非常简单的算法开始:为迄今为止遇到的每个提交保留一个内存中的数据结构(
struct commit
),并在“看到”对象后对其进行标记。为了遍历一个图,给定一些提交散列H,我们将H放在“提交访问”队列中。然后,在not-quite-C中:

while (there are commits in the queue) {
    struct commit *c = lookup_by_id(remove_first_id_from_queue());
    if (c->flags & SEEN)
        ... we already saw this, so do nothing ...
    else {
        ... print this commit ...
        c->flag |= SEEN; /* now we've seen it! */
        for (h in all C's "parent" hashes)
            append_hash_to_queue(h);
    }
}
队列是处理合并提交的,它使这成为一个广度优先的搜索。当我们从一个空队列开始,并将一个普通的提交放入其中时,我们访问该提交并将该提交的单亲添加到队列中,然后立即从队列中删除该父队列并访问该父队列,将其父队列添加到队列中,依此类推。这只是直线行走。当我们点击根提交时,进程停止。但是,当我们点击合并提交时,我们将双亲添加到队列中,然后开始“两侧”行走,依次访问“第一个双亲”并将其双亲排队,然后访问“第二个双亲”并将其双亲排队,依此类推。在某个时刻,我们将对已经在队列中或已经看到的提交进行排队。当我们稍后到达重新排队或重新查看提交时,我们只是跳过它

要实现“可从标识符
包含
而不是从标识符
排除
访问的提交”,我们可以使用相同的算法,但经过修改:首先,我们遍历所有可从
排除
查找的提交,设置SEEN标志,但不打印任何内容;然后,我们将
include
的散列放入队列中,再次遍历,并打印我们这次访问的提交,这些提交我们还没有通过排除访问过

第一步是排除提交,我们可以称之为“负步”,第二步是包括提交,我们可以称之为“正步”

(这个算法是次优的,因此不是Git使用的。如果你阅读代码,你会看到专门排除的提交实际上得到了
无趣的| BOTTOM
标志集,而通过walks排除的提交得到了
无趣的
集。有一些有趣的(啊哼)在
related_commit
函数及其调用者中编写代码,这有助于在负遍历期间修剪图形的大片,而不必经过它们。诀窍是我们必须知道是否有多种方法可以达到我们现在想要修剪的点。如果没有,则可以安全地标记一个commit,这将避免在正向行走过程中遍历它及其所有父对象。)

吉特樱桃
git cherry
(或
git rev list--cherry mark
,或任何类似项目)所做的事情比上面简单的散步更复杂。要实现
git cherry
或等效工具,我们不仅需要提交图,还需要存储库中的其余对象,因为现在我们希望标记“在”一个集中但不“在”另一个集中的提交

在此之前,我们需要定义对称差异,在Git语法中表示为
A…B
(三个点而不是两个点)。对称差异的核心是,”