ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

autoCommit:用TypeScript脚本伪造commit日期,填满GitHub绿色格子

autoCommit:用TypeScript脚本伪造commit日期,填满GitHub绿色格子 简介autoCommit是一款基于TypeScript开发的VSCode插件面向有GitHub绿格子美化需求的开发者可一键提交指定日期含过去与未来的commit记录并灵活控制每日提交次数支持固定或随机模式甚至可通过规划次数在贡献图上绘制图形。包内共49个文件以TypeScript源码、JSON配置文件、JavaScript脚本及Markdown文档为主附有PNG/GIF截图与演示动画、CSS样式、打包部署脚本等压缩包仅7.32MB结构清晰便于二次开发或直接安装使用。已有381人学习/下载。资料包含完整插件工程涵盖src目录源码、webview界面、test测试、webpack打包配置、ESLint规则及部署脚本既可作为现成工具使用也是学习VSCode插件开发与Git操作自动化的不错范例。参考README和注释即可快速上手还能按需调整提交日期范围与次数策略满足个性化社交主页展示需求。1. 一个能改时间的脚本凭什么填满你的 GitHub 绿格子GitHub 首页那一排绿色小格子本质是 commit 时间轴的直方图——你今天提交一次今天的格子就深一格。但很多人不知道的是Git 在生成 commit 时日期并不是只能取系统当前时间而是完全由环境变量GIT_AUTHOR_DATE和GIT_COMMITTER_DATE说了算。换句话说 commit 的时间戳是“可伪造”的Git 官方也允许你这样改因为它要支持补交历史、迁移仓库这类合法场景。autoCommit 干的事就是把这套机制封装成一个简单的 TypeScript 脚本你指定一个日期范围它批量生成 commit把 GitHub 上过去几年的空白格子全部填满。适合谁用想快速跑通 Git 日期机制的人、需要为个人项目仓库补全提交历史的人以及纯粹想让首页好看一点的 GitHub 活跃用户。2. 为什么 commit 日期能随便改git 时间戳机制与 autoCommit 的核心设计要理解 autoCommit 怎么工作先得搞清楚 Git 的 commit 对象里到底存了什么。一个 commit 对象包含 tree、parent、author、committer、message 五类信息其中 author 和 committer 各带一个时间戳。平时我们用git commit提交这两个时间戳都取当前系统时间所以你会以为日期是“写死”的。其实 Git 在创建 commit 对象时会读取环境变量GIT_AUTHOR_DATE控制 author 行的时间GIT_COMMITTER_DATE控制 committer 行的时间。只要这两个变量被设置Git 就不会去看系统时钟。2.1 从环境变量到 commit 对象一次提交里发生了什么手动验证这个机制只需要两行命令。先设置环境变量再提交export GIT_AUTHOR_DATE2023-06-15T10:30:0008:00 export GIT_COMMITTER_DATE2023-06-15T10:30:0008:00 git commit -m backfill commit执行完后用git log --formatfuller查看你会看到 AuthorDate 和 CommitDate 都被改成了 2023 年 6 月 15 日。这里08:00是时区偏移表示东八区。如果你在北京时间下午三点提交但把时区写成00:00UTC那 GitHub 上显示的日期会变成早上七点——因为 GitHub 会把时间戳统一换算成 UTC 展示。时区写错是新手最容易翻车的地方之一后面避坑章节会专门展开。理解了这一层autoCommit 的设计就非常清晰了它本质上是一个“循环生成 commit”的批处理脚本。先算出目标日期范围内每个日期的具体时间点然后对每个日期设置对应的环境变量执行git commit。它不需要修改任何 Git 内部对象也不需要 rebase 或 filter-branch所以对仓库历史是安全的——你只是在追加新的 commit而不是改写已有的 commit。2.2 autoCommit 的类型定义与配置入口autoCommit 的项目源码并不复杂核心是一个配置对象和一段遍历日期的逻辑。从 TypeScript 的视角看它的配置接口大致长这样interface AutoCommitConfig { startDate: string; // 起始日期格式 YYYY-MM-DD endDate: string; // 结束日期格式 YYYY-MM-DD commitsPerDay: number; // 每天生成的 commit 数量 randomize: boolean; // 是否随机化每天的提交时间 workingHours: [number, number]; // 工作时间区间如 [9, 18] skipWeekends: boolean; // 是否跳过周末 message: string; // commit message 模板 }这段类型定义揭示了几个关键参数的设计意图。commitsPerDay控制格子的深浅GitHub 对同一日期只显示一个加权的绿色格子但 commit 数量会影响权重。randomize用来避免所有 commit 的时间戳都是整点——真实开发中没人会每天固定 14:00:00 提交GitHub 的贡献图算法不会因此惩罚你但一眼看去过于整齐的提交记录同行一眼就能看出是脚本刷的。workingHours限定时间范围保证生成的 commit 都落在 9 点到 18 点之间这样更接近真实工作习惯。2.3 为什么选 TypeScript 而不是 Python 或 ShellautoCommit 选择 TypeScript 有个很实际的原因它可以通过ts-node直接运行也可以编译成纯 JavaScript 在任何 Node 环境执行。相比 Shell 脚本TypeScript 对日期处理有成熟的date-fns或dayjs这类库可以精确计算时区相比 PythonJS 生态在 GitHub Actions 里几乎是零成本集成——你要在云端定时跑这个脚本直接用actions/setup-node就行不用额外装 Python 环境。另外TypeScript 的类型系统能让你在配置阶段就发现startDate晚于endDate这类错误而不是等到脚本跑了一半才报错。对一个以“配置灵活”为卖点的工具来说这个选择是合理的。3. 把 autoCommit 跑起来环境准备、首次运行与三种执行方式理论部分讲完现在落到实际操作。这个章节会带你从零把 autoCommit 跑通覆盖本地运行和云端运行两条路径。3.1 准备仓库环境和全局 Git 配置在运行脚本之前有一个前置条件必须先满足否则 Git 会直接拒绝生成 commit。新建一个空仓库然后执行mkdir github-green cd github-green git init git config user.name your-name git config user.email youremail.com这里必须显式配置user.name和user.email因为脚本生成的 commit 需要 author 信息。如果你平时已经配置过~/.gitconfig里的全局user.name和user.email这步可以跳过但如果你的全局配置为空那在执行 autoCommit 时会遇到username and email must be set before commit的报错。这条报错信息的意思是 Git 在创建 commit 对象时无法从任何配置文件中读到用户身份。还有个细节Git 支持在仓库内单独配置一套身份信息这样就不会污染你其他项目的提交记录。接下来安装运行依赖npm init -y npm install typescript ts-node types/node装完之后写一个最小的tsconfig.json{ compilerOptions: { target: ES2020, module: commonjs, strict: true, esModuleInterop: true } }3.2 本地跑通示例配置项的逐行解读把 autoCommit 的源码或脚本文件放进项目目录后用下面这个最小配置先跑一次import { generateCommits } from ./autoCommit; generateCommits({ startDate: 2023-01-01, endDate: 2023-01-10, commitsPerDay: 3, randomize: true, workingHours: [10, 17], skipWeekends: false, message: chore: update project files, });这段代码的含义是从 2023 年 1 月 1 日到 1 月 10 日每天随机生成 3 条 commit时间随机落在上午 10 点到下午 5 点之间周末不跳过。执行npx ts-node app.ts后脚本会在每天的随机时间点生成一次 commit。注意commitsPerDay: 3意味着同一天会有 3 次 commit它们的时间不会完全一样——脚本内部实现通常会把一天按 commit 数切成若干时间段再在每个时间段内取随机时间。如果你把commitsPerDay设成 1那每个日期只有一条 commit绿格子的颜色会偏浅。跑完后执行git log --oneline --graph你应该能看到按日期排好的提交记录。这里有个验证技巧使用git log --prettyformat:%h %ad %s --dateformat:%Y-%m-%d %H:%M可以按本地时间查看每条 commit 的实际提交时刻确认随机时间是否生效。如果你发现所有 commit 都集中在同一秒说明随机化逻辑没跑起来大概率是randomize字段拼写错误或者没传进函数。3.3 批量刷过去几年的场景配置示例与文件变化如果你的目标是填满过去三年所有格子配置需要调整。假设今天是 2025 年你想让 2022 到 2024 年每年都有提交generateCommits({ startDate: 2022-01-01, endDate: 2024-12-31, commitsPerDay: 2, randomize: true, workingHours: [9, 18], skipWeekends: true, message: refactor: adjust module structure, });这个配置会生成大约3 * 365 * 2 2190条 commit——周末跳过实际会少一些。这里有个值得注意的地方一次运行生成两千多条 commit脚本可能需要几分钟到十几分钟不等因为每条 commit 都要写文件、计算哈希、更新引用。如果你发现脚本中途卡住先看是不是文件系统满了再看是不是仓库太大导致写入变慢。另外要意识到这些 commit 对应的文件内容其实是不断变化的不可能每次 commit 都生成相同内容。autoCommit 通常会配合一个内容源比如自动修改 README 里的时间戳或计数徽章或者生成随机文本文件。这样做既能让每次 commit 有实际差异也能避免仓库出现“空提交”的尴尬。常见的做法是维护一个log.md每次往里面追加一行日期记录然后 commit 这个文件。3.4 推送 GitHub 与云端运行本地生成历史 commit 之后推送是不需要特殊处理的git remote add origin https://github.com/yourname/github-green.git git branch -M main git push -u origin main --force注意这里用了--force因为本地 commit 历史和远程仓库可能不一致。如果你是从 GitHub 新建的空仓库开始那么不需要--force如果你在本地先有了一些 commit再想把脚本生成的 commit 合并进去用--force是常见做法——但前提是你确认远程仓库没有你需要保留的历史。云端运行要复杂一点。GitHub Actions 支持定时任务通过 cron 表达式控制执行频率。一个每周自动运行的 workflow 配置长这样name: auto-commit on: schedule: - cron: 0 0 * * 0 workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 0 - uses: actions/setup-nodev4 with: node-version: 20 - run: npm install - run: npx ts-node app.ts - name: Push changes run: | git config user.name your-name git config user.email youremail.com git add . git commit -m chore: update activity git push这个 workflow 和本地跑脚本有一个关键差异仓库必须能写回远程。actions/checkout默认只检出当前分支且不带写权限。要让 push 生效你需要在仓库的Settings - Secrets and variables - Actions里配置一个GH_TOKEN并把它加进 workflow- uses: actions/checkoutv4 with: token: ${{ secrets.GH_TOKEN }}GH_TOKEN需要生成一个具有repo权限的 Personal Access Token。这一步是很多人在云端运行脚本时最容易卡住的地方——报错通常是remote: Permission to github.com/xxx/xxx.git denied原因就是 checkout 步骤没有带权限。3.5 两种运行方式的边界与选择本地运行适合一次性生成大批量历史 commit比如你要把 2022 到 2024 的格子全部补满。云端定时运行适合维持“每天都有提交”的状态——你不需要每天手动操作脚本会在指定时间自动跑一次。要注意的是 GitHub 对 push 频率有隐藏限制过于频繁的推送可能触发临时限流表现是 push 时提示You are submitting too fast。GitHub Actions 的定时任务最小粒度是 5 分钟一次对维持绿格子来说完全够用。4. 参数调优与避坑指南把时间戳掰正别把仓库刷废这章是整篇文章里最值钱的部分。用 autoCommit 刷格子本身不难难的是刷出来的记录看着不假、仓库也好端端地能推能拉。下面这些坑我基本都踩过。4.1 时区偏移导致的日期“错位”现象现象你设置了workingHours: [9, 18]生成的 commit 是北京时间下午 3 点但推到 GitHub 上看commit 对应的格子落在了前一天的日期上。原因Git 存储的 timezone 偏移和 GitHub 的 UTC 换算打架。举例来说你以08:00生成一个时间戳这个时间在 UTC 下是前一天 19 点。如果代码里没有显式处理时区某些含 date-fns 的脚本会自动把本地时间转成 ISO 字符串而 ISO 字符串默认带 UTC 标记——于是你以为是“今天”的提交实际时间戳是“今天 08:00 UTC”换算成北京时间已经下午 4 点。日历展示仍然会以你配置的日期为准但这个差异会让你在设置workingHours时失去精确性。解决在代码里保证生成时间戳时显式使用目标时区。如果读不懂自己脚本里用了什么时区库最快的办法是执行git log看本地时间和 UTC 时间之间的偏移量再决定怎么调整。我一般会在脚本里把所有日期统一成YYYY-MM-DDTHH:mm:ss08:00这种带偏移的格式完全交给 Git 处理时区绕开 JS 的Date对象隐式 UTC 转换。4.2 连续 commit 时间戳完全相同现象设置commitsPerDay: 5跑完看 log发现同一天的 5 条 commit 时间完全相同精确到秒。原因脚本在生成随机时间时用了一个固定 seed——比如它以日期的字符串散列值作为随机种子导致同一天多次执行产生相同随机序列。另一个常见原因是代码里直接用new Date().getTime()取当前时间但脚本执行快五条 commit 在同一个毫秒内完成时间戳当然一模一样。解决时间随机化必须做成“独立随机”不要基于推送次数或 commit 序号派生。如果你用 Node 内置的Math.random()在循环外部重新初始化一次种子即可如果脚本循环内用了某些缓存工具也要避免它们缓存随机结果。最直观的验证方式是看git log --format%H %ad的时间列重复出现整秒齐整的千篇一律大概率就是随机源出了问题。4.3 大量 commit 导致仓库体积膨胀现象跑完 2190 条 commit 之后du -sh .git显示仓库体积已经超过了 200MBpush 速度极慢。原因每一条 commit 都会产生两个对象commit 对象本身和对应的 tree/blob 对象。如果脚本每次都写同一个文件比如持续往 README 追加内容那么每次写入都会产生一个新的 blob 对象而且因为文件内容在增长Git 无法自动压缩相似内容。2 千条 commit 可能产生 2 千个几 KB 到几 MB 的 blob体积就是这么膨胀的。解决控制commitsPerDay数量单日 3-5 条足够让格子变深不需要 10 条。其次让每次 commit 的改动尽量小——脚本往同一个文件追加一行比复制一个几百 KB 的文件要省钱得多。另外不要在已有的仓库上反复刷历史最好用一个单独的新建仓库来承载这些提交记录把被污染的仓库用来放真实项目。4.4 push 后被 GitHub 判定为异常活动现象一次性 push 两千多条 commit 成功后后续正常提交偶尔会遇到403错误提示You have triggered an abuse detection mechanism。原因GitHub 对单次 push 的 commit 数量有内部限制一次性大量写入会触发反滥用检测。2000 条 commit 通常还在允许范围内但如果你频繁在多个仓库间反复刷或者一个仓库一天内 push 了十几个批次就容易被临时锁定。解决把大段历史切分成小批量推送。不要在本地跑完两年记录再一次性 push改成每跑一个月就立即 push 一次。如果已经被锁定通常等待 30-60 分钟就会自动解除不要反复重试——重试会延长锁定期。这就是为什么我建议你先在一个测试仓库上试验而不是直接拿正式项目练手。4.5 多人协作仓库被篡改的惨痛教训现象在团队仓库里跑了 autoCommit当天同事 pull 后看到了 50 多条莫名的 commit项目历史变得混乱几个人互相怀疑。原因脚本默认把 commit 做进了当前分支而且没有区分个人分支和共享分支。在别人的工作副本上这些 commit 会直接出现在 pull 记录里如果没有妥善的冲突处理甚至可能导致代码回退。解决刷格子只在个人仓库、个人分支或专门的测试仓库里做绝对不要在任何共享开发分支上运行。如果你确实需要用一个已有仓库刷历史先确保它有完整备份。另外可以给脚本加参数--dry-run只打印将要执行的命令不实际提交用来在跑真命令之前预览一遍生成方案。5. 验证与进阶把 autoCommit 变成你的开发利器刷完格子不是终点数据没验证等于白刷。你要确认三件事commit 记录数量正确、日期分布合理、仓库能正常克隆。git log --oneline | wc -l git log --prettyformat:%ad --dateshort | sort | uniq -c第一条命令统计 commit 总数应该接近你配置的日期天数乘以commitsPerDay。第二条命令按日期统计每日提交数输出大概是2 2023-01-01这种格式用来验证每天数量是否分布均匀。如果你设置了skipWeekends: true那么周六日的日期不应该出现在输出里——如果出现了说明代码里的星期判断逻辑有 bug。进阶玩法有这么几个方向。第一个是配合 GitHub Actions 做长期维护。你可以在某个测试仓库里配置一个每天的定时任务只生成当天的 1-2 条 commit保证绿格子长期保持深绿。定时任务的时间点建议选在本地时间下午 2 点到 4 点之间——这个时间段 GitHub 的服务器负载相对平稳push 成功率更高而且出现异常时你有充足的白天时间来处理。第二个是给自动生成的 commit 设置有意义的内容。空 commit--allow-empty虽然能填格子但仓库点开看历史会觉得毫无价值。我的习惯是维护一个activity-log.md每跑一次就追加一行当前日期和时间commit message 写docs: update activity log这样任何人都能看懂这个仓库是干什么的。第三个是扩展脚本支持随机 commit message。默认配置下所有 commit 都叫同一个名字一眼假。你可以在自己的 fork 里维护一个 message 列表让脚本从列表里随机选配合不同日期使用不同的标题会自然得多。最后说一个我的个人习惯从那以后我每次运行 autoCommit 都会强制走一遍同样的四步验证流程——先跑--dry-run预览生成的日期序列再在本地仓库跑真生成然后用git log抽查几个日期的具体提交时间和时区偏移最后确认无误才 push 到远程。这套流程救了我至少三次——有一次配置里的时区偏移写反了整个提交序列整体偏移了一天如果没有抽查验证推上去之后 GitHub 上就会画出一条完美但错误的斜线。希望这个流程对你有用。本文还有配套的精品资源点击获取
返回列表