diff --git a/README.md b/README.md index d1e58fb1ff..13d6059329 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,147 @@ # greenhat greenhat image -greenhat is a quick hack for decorating your GitHub contribution calendar with commits for the past `n` days. It uses the `GIT_AUTHOR_DATE` and `GIT_COMMITTER_DATE` environmental variables to make commits appear in the past. Be warned that greenhat will clobber your repository's commit history. -### How to Use -Place `greenhat.py` in your Git repository. Make sure your [remote repository URL is set](https://help.github.com/articles/adding-a-remote/), and that you have a [public SSH key set up](https://help.github.com/articles/generating-ssh-keys/). Then run the script with the python interpreter, with an integer specifying `n` number of days before today to generate commits for. E.g., +# GreenHat: Simulating Git Commit History - python greenhat.py +**GreenHat** 是一个用于模拟 Git 提交记录的脚本工具,可以通过伪造指定天数内的提交记录来生成直观的 GitHub 提交图表(绿色格子)。支持设置从指定日期开始或结束的提交记录。 -It might take a while to generate all the commits. If greenhat stops before it finishes, you can resume where you last left off by specifying a date before today when you want it to resume, like so: +--- - python greenhat.py +## 功能概述 -`n` is the remaining days you want to generate commits for, and `date` is a date string in the form `yyyy-mm-dd` (e.g., 2013-04-05). +- 模拟每天的多次提交记录。 +- 支持自定义起始日期或结束日期。 +- 自动生成提交历史并推送至远程仓库。 +- 提交历史的时间戳包含本地时区信息。 -#### An Example +--- -The following calendar is the result of running `python greenhat.py 365`: +## 平台限制 -example image +1. **操作系统** + - 支持 **Windows**(使用 `cmd` 和 `set` 设置环境变量)。 + - **Linux** 和 **MacOS** 用户需修改 `set` 命令为 `export`,脚本需做小幅调整。 -The run took a total of eight hours. Beautiful, isn't it? +2. **Git 环境** + - 必须安装 Git。 + - 当前目录必须是一个 Git 仓库,并且已配置远程仓库(运行 `git remote -v` 验证)。 -Enjoy your decorated calendar! +3. **Python 版本** + - 支持 Python 3.6 及以上版本。 -### License -greenhat is distributed under the GNU General Public License v3.0 (GPLv3). +4. **权限** + - 必须有对 Git 仓库的写入权限。 + +--- + +## 使用方法 + +### 1. 准备环境 +- 安装 Python 和 Git,并确保它们已添加到系统 PATH。 +- 初始化或克隆一个 Git 仓库: + ```bash + git init + git remote add origin <远程仓库URL> + ``` + ```bash + git clone <远程仓库URL> + ``` + +### 2. 下载脚本 +将代码保存为 `greenhat.py`。 + +### 3. 执行脚本 +运行以下命令以生成提交记录: + +#### 默认从今天开始,向前推 `n` 天生成提交记录 +```bash +python greenhat.py 365 +``` + +#### 指定起始日期,向前推 `n` 天生成提交记录 +```bash +python greenhat.py 365 2024-01-01 +``` + +#### 指定起始日期,向后推 `n` 天生成提交记录(需要修改代码逻辑) +如需向后推提交记录,请使用调整后的脚本(见上一节),运行如下命令: +```bash +python greenhat.py 100 2024-01-01 +``` + +### 4. 查看生成的提交记录 +使用以下命令查看提交日志: +```bash +git log --pretty=format:"%ad %s" --date=local +``` + +### 5. 推送至远程仓库 +脚本默认会执行以下命令推送更改: +```bash +git push +``` + +--- + +## 注意事项 + +1. **时区问题** + 脚本会动态检测本地时区并应用到提交记录中,请确保系统时区设置正确。 + +2. **文件冲突** + 脚本生成的临时文件 `realwork.txt` 会被自动删除,请确保仓库中没有同名文件以避免冲突。 + +3. **安全性** + 脚本通过 `subprocess` 调用系统命令,运行前请确保代码来源可靠,避免潜在安全风险。 + +4. **Git 仓库状态** + 确保当前分支干净(无未提交的更改),以防止提交冲突。 + +--- + +## 示例 + +### 示例 1:默认从今天开始,生成 365 天的提交记录 +运行: +```bash +python greenhat.py 365 +``` + +输出(部分日志示例): +```text +Processing Day 0: Sun Dec 31 12:00:00 2024 +0800 +Processing Day 1: Sat Dec 30 12:00:00 2024 +0800 +... +Processing Day 364: Tue Jan 01 12:00:00 2023 +0800 +``` + +### 示例 2:从指定日期开始,生成 100 天的提交记录 +运行: +```bash +python greenhat.py 100 2023-01-01 +``` + +--- + +## 已知问题 + +1. **Windows 平台** + 使用 `cmd` 的 `set` 命令设置环境变量,无法直接在 Linux 和 MacOS 上运行。 + +2. **提交频率随机性** + 每天的提交次数是随机的(1 到 10 次),可根据需求修改 `randint` 的范围。 + +3. **多用户环境** + 如果同一仓库有多人提交,伪造的记录可能会影响真实提交历史。 + +--- + +## 修改记录 + +- **版本 1.0**: 初始发布,支持随机生成提交记录。 +- **版本 1.1**: 修复了 Windows 环境变量设置的问题,支持动态检测时区。 + +--- + +## 授权协议 + +本项目基于 GNU General Public License v3.0 (GPLv3) 发布,详情请参阅项目 LICENSE 文件。 diff --git a/greenhat.py b/greenhat.py index bf4caf4b4b..bf3e20e21e 100755 --- a/greenhat.py +++ b/greenhat.py @@ -1,36 +1,54 @@ -# Copyright (c) 2015 Angus H. (4148) -# Distributed under the GNU General Public License v3.0 (GPLv3). - -from datetime import date, timedelta -from random import randint import sys +from datetime import date, timedelta, datetime +from random import randint import subprocess -import os -# returns a date string for the date that is N days before STARTDATE +# 动态获取指定日期的格式化日期字符串,包含本地时区 def get_date_string(n, startdate): - d = startdate - timedelta(days=n) - rtn = d.strftime("%a %b %d %X %Y %z -0400") - return rtn + d = startdate - timedelta(days=n) + # 动态获取本地时区 + local_timezone = datetime.now().astimezone().strftime("%z") + rtn = d.strftime(f"%a %b %d %X %Y {local_timezone}") + return rtn -# main app +# 主程序 def main(argv): - if len(argv) < 1 or len(argv) > 2: - print "Error: Bad input." - sys.exit(1) - n = int(argv[0]) - if len(argv) == 1: - startdate = date.today() - if len(argv) == 2: - startdate = date(int(argv[1][0:4]), int(argv[1][5:7]), int(argv[1][8:10])) - i = 0 - while i <= n: - curdate = get_date_string(i, startdate) - num_commits = randint(1, 10) - for commit in range(0, num_commits): - subprocess.call("echo '" + curdate + str(randint(0, 1000000)) +"' > realwork.txt; sync; git add realwork.txt; GIT_AUTHOR_DATE='" + curdate + "' GIT_COMMITTER_DATE='" + curdate + "' git commit -m 'update'", shell=True) - i += 1 - subprocess.call("git rm realwork.txt; git commit -m 'delete'; git push;", shell=True) + if len(argv) < 1 or len(argv) > 2: + print("Error: Bad input.") + sys.exit(1) + + # 获取输入参数 + n = int(argv[0]) # 天数 + if len(argv) == 1: + startdate = date.today() + if len(argv) == 2: + startdate = date(int(argv[1][0:4]), int(argv[1][5:7]), int(argv[1][8:10])) + + i = 0 + while i <= n: + # 获取当前日期 + curdate = get_date_string(i, startdate) + # 随机生成当天的提交次数 + num_commits = randint(1, 10) + + for commit in range(num_commits): + # 生成一个文件,并添加到 git + subprocess.call(f"echo {curdate}{randint(0, 1000000)} > realwork.txt", shell=True) + subprocess.call("git add realwork.txt", shell=True) + + # 设置 GIT_AUTHOR_DATE 和 GIT_COMMITTER_DATE 并提交 + subprocess.call( + f'set GIT_AUTHOR_DATE="{curdate}" && set GIT_COMMITTER_DATE="{curdate}" && git commit -m "update"', + shell=True, + ) + + print(f"Processing Day {i}: {curdate}") # 调试输出 + i += 1 + + # 删除临时文件并推送 + subprocess.call("git rm realwork.txt", shell=True) + subprocess.call("git commit -m 'delete'", shell=True) + subprocess.call("git push", shell=True) if __name__ == "__main__": - main(sys.argv[1:]) + main(sys.argv[1:])