如何以编程方式确定较早或较晚的提交?

How to determine earlier or later commits programatically?

是否可以比较 git 以编程方式提交或与其整数十六进制值进行比较?后面的提交是否比前一个提交的整数大? 因此,例如,如果我们可以在伪代码

中获取哈希值
int commit_a = myrepo.getCurrentCommit();
int commit_b = myrepo.getPreviousCommit();

if(commit_a > commit_b)
printf("Commit A is later than Commit B");
else
printf("Commit B is later than Commit A");

注意:我已经编辑了我的问题,询问是否有 git 库可以执行上述示例。或者如何实现我自己的。

提交由它们的 "sha" 标识,最好不要将其视为整数,而应将其视为不透明的二进制值。它不会递增,也不能直接与另一个提交进行比较。

但是,每个提交中固有的信息足以确定该提交的历史,因此您可以想象根据历史比较提交。关于如何做到这一点已经有一个非常可靠的问题和答案:How can I tell if one commit is a descendant of another commit?

Git 中的提交形成有向无环图或 DAG。

在任何图中,我们都有一个邻接表(因为图定义为 G = (V, E) 其中 VE 分别是顶点和边集):图中任何给定的顶点/节点是要么离其他顶点一跳,通过一些边,要么更远,要么根本没有连接:

  C--D
 /
B------E  G--H
 \    /
  A  F

节点 A 连接到 B(反之亦然),B 连接到 C 和 E,依此类推。 G 和 H 相互连接,但不连接到图的其余部分,因此该图由两个不相交的子图组成。 (这些边没有方向。)

有向图中,有predecessorsuccessor的概念连接有一个箭头:

A->B->C
   |
   v
   D

这里A连接到B,B连接到C和D。所以B是A的后继者,C和D都是B的后继者(但彼此不连接)。就前辈而言,A是B的前辈,B是C和D的前辈

如果图没有环——无环——我们可以使用predecessor/successor操作执行传递闭包操作。 Git 的图都是有向 非循环的——它是一个 DAG——所以我们可以用 Git.

来做这个

在Git内部,箭头实际上是向后的(出于实现原因),但我们仍然执行相同的传递闭包。当我们这样做时,我们发现 A 是 B、​​C 和 D 的祖先

A <-B <-C
    ^
    |
    D

因为我们可以从这些提交中的任何一个开始,然后回到 A。B 是 C 和 D 的祖先。相反的关系是 后代: D 是一个A.

的后裔

这里必须要小心一点。 C和D之间没有祖先或后代关系,即C不是D的祖先,但C也不是D的后代。你不能只说 "not ancestor therefore descendant":两者可能根本不相关。如果 DAG 具有不相交的子图,则对于某些提交也是如此,这是允许的:

A <-B <-C   <-- master1

D <-E   <-- master2

虽然 D 是 E 的祖先,但 D 与 A、B 或 C 中的任何一个都没有关系。

无论如何,测试"ancestor-ness"的Git命令是:

git merge-base --is-ancestor

它采用两个提交哈希 ID(或其他提交说明符)和答案,作为真或假查询(通过退出状态,0 表示 "yes, is an ancestor"),问题:是第一个命名的提交参数由第二个命名的提交的祖先。即:

hash1=$(git rev-parse $thing1^{commit}) || die "$thing1 does not name a git commit"
hash2=$(git rev-parse $thing2^{commit}) || die "$thing2 does not name a git commit"
if git merge-base --is-ancestor $hash1 $hash2; then
    echo "$thing1 is an ancestor of $thing2"
else
    if git merge-base --is-ancestor $hash2 $hash1; then
        echo "$thing1 is a descendant of $thing2"
    else
        echo "$thing1 and $thing2 are not relatable"
    fi
fi

出现 "not relatable" 答案是因为,正如我们在上面看到的,我们从 predecessor/successor 的概念中只得到一个 partial order, not a total order

(出于 Git 的目的,提交是它自己的祖先,因此 git merge-base --is-ancestor $hash1 $hash1 始终为真。)