如何自动实现Git中按文件按日仅保留最后一次提交?
整理Git提交历史:保留每个文件每日最后一次提交并处理文件变更场景
核心思路
要解决自动提交导致的冗余历史问题,关键是按文件+日期维度筛选提交:只保留每个文件当日的最后一次变更提交,同时识别文件重命名、删除的关联关系,避免历史链断裂。
方案一:用git filter-repo自动处理(推荐)
git filter-repo是官方替代git filter-branch的高效历史重写工具,配合自定义脚本可实现批量筛选。
步骤1:编写筛选脚本
创建filter_daily_last_commit.py,逻辑是遍历所有提交,记录每个文件(含重命名路径)每日的最新提交,最终输出需要保留的提交哈希:
from datetime import datetime import git repo = git.Repo(".") file_daily_latest = {} # 从旧到新遍历所有提交 for commit in repo.iter_commits("--reverse"): commit_date = datetime.fromtimestamp(commit.committed_date).date() diff = commit.diff(commit.parents[0]) if commit.parents else commit.diff(None) for change in diff: # 处理文件路径:区分新增/修改/删除/重命名 if change.renamed: old_path = change.a_path new_path = change.b_path # 转移旧路径的记录到新路径,确保重命名后历史关联 if (old_path, commit_date) in file_daily_latest: del file_daily_latest[(old_path, commit_date)] file_daily_latest[(new_path, commit_date)] = commit.hexsha else: file_path = change.a_path if change.deleted else change.b_path file_daily_latest[(file_path, commit_date)] = commit.hexsha # 收集需保留的提交哈希 keep_commits = set(file_daily_latest.values()) # 输出到文件供filter-repo使用 with open("keep_commits.txt", "w") as f: for sha in keep_commits: f.write(f"{sha}\n")
步骤2:执行历史过滤
务必先备份仓库(历史重写不可逆),然后运行:
# 安装依赖(如果没装gitpython) pip install gitpython # 生成保留列表 python filter_daily_last_commit.py # 执行过滤 git filter-repo --commit-callback ' import os keep = set(line.strip() for line in open("keep_commits.txt")) if commit.hexsha not in keep: skip() '
方案二:半自动处理(适合小仓库)
如果仓库规模不大,可结合交互式rebase手动合并:
- 用
git log --follow <file-path>追踪单个文件的完整历史(包括重命名/删除) - 执行
git rebase -i --root进入交互式重写模式 - 对同一文件当日的多次提交,用
squash或fixup合并到最后一次提交上 - 对于重命名的文件,确保合并时保留路径变更的关联记录
关键注意事项
- 强制备份:重写前务必克隆仓库副本,防止数据丢失
- 远程仓库同步:如果已推送到远程,需要
git push --force,但会覆盖远程历史,需提前告知协作者 - 重命名识别:Git默认通过内容相似度识别重命名,脚本已处理该场景,确保同一文件的新旧路径会关联到同一日期的最后提交
- 提交信息调整:如果需要统一提交信息,可在脚本中修改或在交互式rebase时编辑
内容的提问来源于stack exchange,提问作者Maikol Solís
相关产品推荐
相关产品推荐

