现象
一条被 rebase 过的功能分支,在 Graph 里会把整条分支的提交「顶」在最上面,堆成一大坨压在 main 的 tip 之上,看不出实际的开发时间顺序。
实例:feat/cli-remote 有 253 个提交、作者时间横跨 09-07 → 09-11,同事把它 rebase 到 main 之后:
72e335150 | A:09-11 19:26 | C:09-11 19:31 | fix(remote): preserve session lists ...
4b3f7005b | A:09-11 17:31 | C:09-11 19:31 | test(agent): scope context reset ...
...
2168c7ac3 | A:09-07 14:09 | C:09-11 19:27 | feat(cli): persist gateway sharing ... ← 最老的一个
253 个提交的 committer date 全部落在 09-11 19:27–19:31 这四分钟内,author date 却散布在四天里。Graph 把它们整整齐齐排在最上面。
根因:排序键和显示键不是同一个
Sources/TheGit/Core/GitClient.swift:80 —— 走图用的是 --date-order:
// --date-order interleaves parallel branches chronologically
// (GitKraken-style) while still keeping children before parents.
var args = ["log", "--date-order"]
--date-order 排的是 committer date。
而 Sources/TheGit/Core/GitClient.swift:65 的 logFormat 取的是 %at —— author date:
private static let logFormat = "%H%x09%P%x09%an%x09%ae%x09%at%x09%D%x09%s"
GitParsers.parseLog 把 %at 装进 Commit.date(Sources/TheGit/Core/Parsers.swift:13),全 UI 显示的都是它。
所以每一行按 committer date 排位置、按 author date 写日期。没 rebase 过的仓库里两者基本相等,看不出问题;一旦 rebase,committer date 被整体刷成「现在」,行的顺序和行上印的日期就对不上了 —— 用户看到的是一列日期乱序的提交挤在顶部,而不是「这条分支被 rebase 过」。
项目内部已有相反的先例
GitClient.activity() 在这件事上已经明确选过一次,注释就写在 GitClient.swift:
Author date, not committer date: the cells are meant to say when the work was done, and a rebase rewrites the other one.
热力图按 author date 算,Graph 却按 committer date 排。同一个仓库里两套口径。
建议
1. 排序方式做成可切换(工具栏或 View 菜单),三个选项直接对应 git 自己的三个 flag:
| 选项 |
flag |
说明 |
| 提交时间 |
--date-order |
现状,保持默认可选 |
| 作者时间 |
--author-date-order |
rebase 后仍按实际开发顺序铺开 |
| 拓扑 |
--topo-order |
分支不交错,整条链连续 |
三者都保证「子提交先于父提交」,换掉不会破坏 Graph 的连线绘制,只是改 args 里那一个字符串。
2. 或者更简单:默认就改成 --author-date-order,让排序和已经在显示的 %at 对齐,跟 activity() 的口径统一。
3. 附带:在 CommitHoverCard / CommitPanelView 里,当 author date 和 committer date 不相等时把两个都显示出来(例如 authored 09-07 14:09 · committed 09-11 19:27)。这样「这个提交被 rebase / cherry-pick 过」是一眼可见的事实,而不用用户自己去命令行里对。logFormat 加一个 %ct 字段即可。
复现
- 建一条功能分支,隔几天提交若干次
git rebase main
- 在 TheGit 里看 Graph —— 整条分支堆在 main tip 之上,行内日期与行序不一致
现象
一条被 rebase 过的功能分支,在 Graph 里会把整条分支的提交「顶」在最上面,堆成一大坨压在 main 的 tip 之上,看不出实际的开发时间顺序。
实例:
feat/cli-remote有 253 个提交、作者时间横跨 09-07 → 09-11,同事把它 rebase 到 main 之后:253 个提交的 committer date 全部落在 09-11 19:27–19:31 这四分钟内,author date 却散布在四天里。Graph 把它们整整齐齐排在最上面。
根因:排序键和显示键不是同一个
Sources/TheGit/Core/GitClient.swift:80—— 走图用的是--date-order:--date-order排的是 committer date。而
Sources/TheGit/Core/GitClient.swift:65的logFormat取的是%at—— author date:GitParsers.parseLog把%at装进Commit.date(Sources/TheGit/Core/Parsers.swift:13),全 UI 显示的都是它。所以每一行按 committer date 排位置、按 author date 写日期。没 rebase 过的仓库里两者基本相等,看不出问题;一旦 rebase,committer date 被整体刷成「现在」,行的顺序和行上印的日期就对不上了 —— 用户看到的是一列日期乱序的提交挤在顶部,而不是「这条分支被 rebase 过」。
项目内部已有相反的先例
GitClient.activity()在这件事上已经明确选过一次,注释就写在GitClient.swift:热力图按 author date 算,Graph 却按 committer date 排。同一个仓库里两套口径。
建议
1. 排序方式做成可切换(工具栏或 View 菜单),三个选项直接对应 git 自己的三个 flag:
--date-order--author-date-order--topo-order三者都保证「子提交先于父提交」,换掉不会破坏 Graph 的连线绘制,只是改
args里那一个字符串。2. 或者更简单:默认就改成
--author-date-order,让排序和已经在显示的%at对齐,跟activity()的口径统一。3. 附带:在 CommitHoverCard / CommitPanelView 里,当 author date 和 committer date 不相等时把两个都显示出来(例如
authored 09-07 14:09 · committed 09-11 19:27)。这样「这个提交被 rebase / cherry-pick 过」是一眼可见的事实,而不用用户自己去命令行里对。logFormat加一个%ct字段即可。复现
git rebase main