2026-05-09 学习日志
今日主题
- Git commit 时间重写原理
- skills CLI 内部机制
新增认知
Git commit 时间重写原理
- Git commit object 包含两个独立时间戳:author date 和 committer date,分别对应 jgit 中 CommitBuilder 的 author 和 committer PersonIdent。git log 默认显示 author date,GIT_COMMITTER_DATE 环境变量控制 committer date,--date 参数控制 author date,两者需同时覆盖才能完整重写时间。
- git rebase -i edit 模式的底层机制是 cherry-pick 链:每次 cherry-pick 后暂停让你 amend,amend 因为动了 commit 内容(时间戳是内容的一部分)必然生成新 object ID,然后 rebase --continue 用新 ID 作为 parent 继续 cherry-pick 下一个。这就是为什么改一个 commit 的时间会导致所有子孙 commit 的 hash 全部重生——内容寻址的必然结果。
- GIT_COMMITTER_DATE 只在当前 shell 进程生效,rebase -i 的 exec 行 fork 出的子进程不一定继承该环境变量,所以用 exec 设时间不可靠。正确做法是用 edit 模式,在 rebase 停住的 shell 里直接设环境变量执行 git commit --amend,保证变量作用于 amend 进程。
- jgit API 中改 commit 时间的等价操作:用 RevWalk 解析旧 commit,创建新 CommitBuilder,通过 setAuthor/setCommitter 传入新的 PersonIdent(带新时间戳),保持 tree/parent/message 不变,ObjectInserter.insert 即可生成新 commit。底层和 CLI 的 amend 一样都是重建 commit object。
skills CLI 内部机制
- skills CLI 的 update 不是 diff 文件内容,而是用 GitHub Trees API 获取 skill 文件夹的 tree SHA(
fetchSkillFolderHash),将其存入~/.agents/.skill-lock.json的skillFolderHash字段。update 时重新请求 API 比对 hash,不一致就执行skills add -g -y重新安装。关键前提:只对 GitHub source、且有skillFolderHash和skillPath记录的 skill 生效;local/git/well-known 类型的 source 会被getSkipReason跳过。 -
skills remove正常情况会调用removeSkillFromLock清理锁文件中的对应条目,但手动删除文件夹、旧版本 bug、remove 过程出错中断都可能导致~/.agents/.skill-lock.json残留脏数据。目前工具没有内置的 check/clean 命令来校验锁文件与实际磁盘状态一致性,只能手动编辑 JSON 或删除重建。排查命令:cat ~/.agents/.skill-lock.json | python3 -m json.tool查看,对比ls ~/.agents/skills/目录。 -
skills add安装时决定的目录名来自 SKILL.md frontmatter 的name字段,而非 SKILL.md 所在目录名。parseSkillMd(gray-matter 解析 frontmatter)→ skill.name → installSkillForAgent 中sanitizeName(skill.name)。只有当 name 为空时才 fallback 到basename(skill.path)。sanitizeName 规则:转小写、非 [a-z0-9._] 替换为 -、去首尾 . 和 -、截断 255 字符。well-known/remote skill 使用 installName 而非 name,同样经过 sanitizeName。