为什么 git log -- 某个文件 有时候少了一些改过它的提交?这是历史简化。这篇造一个两个分支都改了同一个文件、先后合并的历史,看 --full-history、--simplify-merges、--sparse 各自的结果,再学会读 --graph 的 ASCII 图。
$ git log --graph --format='%s' | sed -E 's/^/ /'
* M3 改 hy
* M2 改 f 为 3
* 合并 y
|\
| * Y2 改 hy
| * Y1 也把 f 改成 2
* | 合并 x
|\ \
| * | X2 改 gx
| * | X1 改 f 为 2
| |/
* / M1 改 g
|/
* R 起点x、y 两个分支各自把 f 改成同样的值 2,先后合并进 main,之后 main 上又有 M2、M3。这是“两条分支做了相同改动”的典型情形。
$ git log --format='%s' -- f M2 改 f 为 3 X1 改 f 为 2 R 起点 (X1 和 Y1 都把 f 改成了 2,但默认只显示 X1:合并 y 的提交的 f 与它的两个 parent 都一样,git 只沿第一个 parent 走,Y 那条分支被整条丢掉了。)
给 git log 加路径后,git 会简化历史:没改动这些路径的提交不显示;遇到合并提交,如果它的路径内容与某一个 parent 完全一样(TREESAME),就只沿那个 parent 走,另一条分支整条被忽略。这能让输出更简洁,但会隐藏掉其它分支里同样改过文件的提交。
git log -- f ( 3 个): M2 改 f 为 3 | X1 改 f 为 2 | R 起点 git log --full-history -- f ( 5 个): M2 改 f 为 3 | 合并 x | Y1 也把 f 改成 2 | X1 改 f 为 2 | R 起点 git log --full-history --simplify-merges -- f ( 5 个): M2 改 f 为 3 | 合并 y | Y1 也把 f 改成 2 | X1 改 f 为 2 | R 起点 git log --full-history --sparse -- f (10 个): M3 改 hy | M2 改 f 为 3 | 合并 y | 合并 x | M1 改 g | Y2 改 hy | Y1 也把 f 改成 2 | X2 改 gx | X1 改 f 为 2 | R 起点
--full-history 不简化合并,所有改动过路径的提交都显示(同时还显示相关的合并)。--simplify-merges 在此基础上去掉对这些路径来说多余的合并;--sparse 把无关的提交也留下。
$ git log --graph --full-history --format='%s' -- f | sed -E 's/^/ /'
* M2 改 f 为 3
* 合并 y
|\
| * Y1 也把 f 改成 2
* | 合并 x
|\ \
| |/
|/|
| * X1 改 f 为 2
|/
* R 起点--graph 用 ASCII 把提交图画出来。与 --full-history 搭配,能看清每条改过文件的支线。
$ echo '--first-parent:'; git log --first-parent --format='%s' | tr '\n' '|'; echo; echo '--ancestry-path R..main:'; git log --ancestry-path --format='%s' $(git rev-list --max-parents=0 HEAD)..main | tr '\n' '|'; echo; echo '--ancestry-path X1..main:'; git log --ancestry-path --format='%s' $(git rev-parse x~1)..main | tr '\n' '|'; echo; echo '--simplify-by-decoration:'; git log --simplify-by-decoration --format='%s (%D)' | sed -E 's/HEAD -> //' | tr '\n' '|'; echo --first-parent: M3 改 hy|M2 改 f 为 3|合并 y|合并 x|M1 改 g|R 起点| --ancestry-path R..main: M3 改 hy|M2 改 f 为 3|合并 y|合并 x|M1 改 g|Y2 改 hy|Y1 也把 f 改成 2|X2 改 gx|X1 改 f 为 2| --ancestry-path X1..main: M3 改 hy|M2 改 f 为 3|合并 y|合并 x|X2 改 gx| --simplify-by-decoration: M3 改 hy (main)|M2 改 f 为 3 (tag: v1)|合并 y ()|Y2 改 hy (y)|X2 改 gx (x)|R 起点 ()|
--first-parent 只沿第一个 parent;--ancestry-path A..B 只显示 A 的后代同时又是 B 的祖先的提交;--simplify-by-decoration 只留带分支/标签的提交以及保持图连通的合并。
$ git log --graph --format='%s' | sed -E 's/^/ /'
*-. 章鱼合并 p q r
|\ \
| | * r1
| * | q1
| |/
* / p1
|/
* base* 是提交,| 是延续的线,\\ 与 / 表示分出与合回,*-. 是有三个 parent 的章鱼合并。