提问人:Nederealm 提问时间:10/30/2018 最后编辑:Nederealm 更新时间:10/31/2018 访问量:22
如何以编程方式确定更早或更晚的提交?
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”标识,最好不要将其视为整数,而应视为不透明的二进制值。它不会递增,也不能与另一个提交直接比较。
但是,每个提交中固有的信息都足以确定该提交的历史记录,因此您可以根据历史记录比较提交。关于如何做到这一点,已经有一个非常可靠的问题和答案:我如何判断一个提交是否是另一个提交的后代?
评论
Git 中的提交形式为有向无环图或 DAG。
在任何图中,我们都有一个邻接列表(因为图被定义为 G = (V, E),其中 V 和 E 分别是顶点和边集):图中任何给定的顶点/节点要么与其他顶点相距一跳,穿过某条边,要么距离更远或根本没有连接:
C--D
/
B------E G--H
\ /
A F
节点 A 连接到 B(反之亦然),B 连接到 C 和 E,依此类推。G 和 H 相互连接,但不连接到图形的其余部分,因此该图形由两个不相交的子图形组成。(这些边没有方向。
在有向图中,有一个前继和后继的概念,因为每个连接都有一个箭头:
A->B->C
|
v
D
这里 A 连接到 B,B 同时连接到 C 和 D。所以 B 是 A 的后继者,C 和 D 都是 B 的后继者(但彼此没有联系)。从前辈的角度来看,A是B的前身,B是C和D的前身。
如果图没有循环(是非循环的),我们可以使用前置/后续操作执行传递闭包操作。Git 的图既是有向的,又是无环的——它是一个 DAG——所以我们可以用 Git 来做到这一点。
在 Git 中,箭头实际上是向后(出于实现原因),但我们仍然执行相同的传递闭包。当我们这样做时,我们发现 A 是 B、C 和 D 的祖先:
A <-B <-C
^
|
D
因为我们可以从这些提交中的任何一个开始,然后回到 A.B 是 C 和 D 的祖先。相反的关系是后代:D 是 A 的后代。
这里必须小心一点。C 和 D 之间没有祖先或后代关系。也就是说,C 不是 D 的祖先,但 C 也不是 D 的后代。你不能只是说“不是祖先,而是后代”:两者可能根本就没有关系。如果 DAG 具有不相交的子图,则对于某些提交也是如此,这是允许的:
A <-B <-C <-- master1
D <-E <-- master2
虽然 D 是 E 的祖先,但 D 与 A、B 或 C 中的任何一个都没有关系。
在任何情况下,测试“祖先性”的 Git 命令是:
git merge-base --is-ancestor
它采用两个提交哈希 ID(或其他提交说明符)和答案,作为 true 或 false 查询(通过退出状态,0 表示“是,是祖先”),问题是:由第一个参数命名的提交是否是第二个参数命名的提交的祖先。那是:
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
之所以出现“不相关”的答案,是因为正如我们上面所看到的,我们从前任/后继者的概念中只得到了部分顺序,而不是全部顺序。
(就 Git 而言,提交是它自己的祖先,所以总是正确的。git merge-base --is-ancestor $hash1 $hash1
评论