Git 祖先跳表

2025年5月4日 介绍一下 Bushi 所使用的祖先跳表

目标

快速判断 Commit A 是否是 Commit B 的祖先

  • git-ref-contains-commit
  • git-log-path-filter

限制

本项目仅考虑提交的第一个 Parent Commit

原理

判断

验证

选择 Aports 仓库中 Commit-ID 分别为 100 和 20000 的两个提交,对应的 Commit-OID 如下

sqlite> SELECT * FROM commits WHERE commit_id = 100 OR commit_id = 20000;
commit_id  commit_hash                               commit_mark  parent_id  depth  repo_id
---------  ----------------------------------------  -----------  ---------  -----  -------
100        44a369d15ac69464584099d339a0e1ec1ec7fa66  100          99         99     1
20000      89d3e577e9a10d8f75b87d5ec44d801efbb7f3c7  20000        19999      13920  1

查看网页确实在同一分支中,两者 depth 之差为 13821,转为二进制数得到 2 的 N 次幂

>>> bin(13821)
'0b11010111111101'

即为 13、12、10、8、7、6、5、4、3、2、0 这些序列,下面开始在祖先表中查找

sqlite> SELECT * FROM ancestors WHERE commit_id = 20000 AND level = 13;
commit_id  level  ancestor_id
---------  -----  -----------
20000      13     7618
sqlite> SELECT * FROM ancestors WHERE commit_id = 7618 AND level = 12;
commit_id  level  ancestor_id
---------  -----  -----------
7618       12     2133
sqlite> SELECT * FROM ancestors WHERE commit_id = 2133 AND level = 10;
commit_id  level  ancestor_id
---------  -----  -----------
2133       10     777
sqlite> SELECT * FROM ancestors WHERE commit_id = 777 AND level = 8;
commit_id  level  ancestor_id
---------  -----  -----------
777        8      372
sqlite> SELECT * FROM ancestors WHERE commit_id = 372 AND level = 7;
commit_id  level  ancestor_id
---------  -----  -----------
372        7      244
sqlite> SELECT * FROM ancestors WHERE commit_id = 244 AND level = 6;
commit_id  level  ancestor_id
---------  -----  -----------
244        6      161
sqlite> SELECT * FROM ancestors WHERE commit_id = 161 AND level = 5;
commit_id  level  ancestor_id
---------  -----  -----------
161        5      129
sqlite> SELECT * FROM ancestors WHERE commit_id = 129 AND level = 4;
commit_id  level  ancestor_id
---------  -----  -----------
129        4      113
sqlite> SELECT * FROM ancestors WHERE commit_id = 113 AND level = 3;
commit_id  level  ancestor_id
---------  -----  -----------
113        3      105
sqlite> SELECT * FROM ancestors WHERE commit_id = 105 AND level = 2;
commit_id  level  ancestor_id
---------  -----  -----------
105        2      101
sqlite> SELECT * FROM ancestors WHERE commit_id = 101 AND level = 0;
commit_id  level  ancestor_id
---------  -----  -----------
101        0      100

最终得到 Commit-ID 与目标 ID 相同,两者位于同一分支中。