这个问题有两个部分。一个非常简单:从 Git 中获取图形的边和顶点。另一个非常困难:绘制“漂亮”(平面,线交叉最少)图。
您似乎在询问简单的部分,所以这是答案:使用git cat-file -p 获取每个 Git 对象的内容,从一些已知的 Git 哈希 ID 或 ID 开始。 (使用git rev-parse获取初始ID。)
例如:
$ git rev-parse HEAD
d35688db19c9ea97e9e2ce751dc7b47aee21636b
$ git cat-file -p HEAD
tree 242af4b1a902347da2ff144516fb40c4a28ca257
parent 43c9e7e365d7a8961767d0bd4a305ca378800a2a
author Junio C Hamano <gitster@pobox.com> 1507361343 +0900
committer Junio C Hamano <gitster@pobox.com> 1507361343 +0900
Prepare for -rc1
Signed-off-by: Junio C Hamano <gitster@pobox.com>
(此处的git cat-file 示例旨在表明您可以使用或者 一个符号名称, 或 一个哈希ID 来启动进程)。检查提交对象将得到一个 tree 行和零个或多个 parent 行,提供父边的哈希 ID(请注意,这是一个 DAG,这些是传出弧,如果你想绘制箭头头脑清醒)。
tree对象的内部形式比较僵硬,同样可以通过git cat-file -p查看:
$ git cat-file -p 242af4b1a902347da2ff144516fb40c4a28ca257
100644 blob 611ab4750bd21e77d0fec41c8b2e115574c692ff .clang-format
100644 blob 8ce9c6b8888fe6c12949d30e3e8b461cb67bb43f .gitattributes
040000 tree 7ba15927519648dbc42b15e61739cbf5aeebf48b .github
100644 blob 833ef3b0b783b8180d0dad1ce336713bddf09b26 .gitignore
100644 blob cbeebdab7a5e2c6afec338c3534930f569c90f63 .gitmodules
100644 blob ab85e0d16d6383b13954220a0b41202bd68d5d73 .mailmap
100644 blob fead995eddd15460b6be81e6a5f7c8f0648368ca .travis.yml
100644 blob 8c85014a0a936892f6832c68e3db646b6f9d2ea2 .tsan-suppressions
100644 blob 536e55524db72bd2acf175208aef4f3dfc148d42 COPYING
040000 tree 3957dfa63966e1efd20481ebd61311397a34e8ab Documentation
100755 blob ab04c977be0cfdb6f282b7911d3fe630d5f70c65 GIT-VERSION-GEN
100644 blob ffb071e9f03a79a052beaa4372fa790ecbabbb7b INSTALL
[more, snipped]
每个输出行都以“模式”开头,如果具有此名称的对象本身是另一棵树,则为 040000,如果是普通文件,则为 100644 或 100755 之一。 (还有另外两种模式,一种用于符号链接,一种用于“gitlink”,这是 Git 存储子模块的子模块哈希 ID 的方式。另请参见 https://github.com/chris3torek/scripts/blob/master/githash.py。)在编码模式之后,git cat-file -p 打印底层 Git 对象类型,然后是哈希 ID,然后是选项卡,然后是要在其下提取 blob 或子树的文件名组件。
每个哈希 ID 都是唯一的,因此如果一个哈希 ID 出现多次,您就有一个共享的子节点。您的示例图中的几个 blob 对象就是这种情况。请注意,顶级树也可以重复使用。例如,如果你有这个提交系列:
A <-B <-C <--master
提交C 是由提交B 的git revert 创建的,A 和C 很可能使用相同的顶级树(这自动意味着它们使用所有相同的子-树和斑点)。