如何将本地Git仓库仅保留最后一次提交?
一、什么是grafted提交?
grafted是Git浅拷贝仓库里的特殊标记,用来标识本地没有该提交完整父提交链的快照。正常情况下,每个Git提交都包含指向父提交的指针,以此形成完整的历史追溯链。但在--depth=1的浅克隆中,我们只拉取了最新的一次提交,它的父提交并没有被下载到本地仓库,Git无法找到父提交对象,就会用grafted标记这个提交,明确表示历史在这里被截断,并非完整的仓库历史。
二、无需重新克隆,将本地仓库转为仅保留最后一次提交的浅拷贝
如果你的本地仓库已经有庞大的.git文件夹,可以通过以下步骤截断历史,实现和git clone --depth=1一致的效果:
确保工作区干净
先检查是否有未提交的修改,避免操作丢失内容:git status如有未提交文件,要么提交快照,要么用
git stash暂存或git checkout .丢弃修改,确保工作区处于"clean"状态。拉取远程最新的浅拷贝提交
以远程名为origin、主分支为main为例,仅拉取最新的一次提交:git fetch --depth=1 origin main重置本地分支到远程最新提交
将本地主分支强制重置到刚拉取的浅拷贝HEAD上:git reset --hard origin/main清理本地旧历史对象
彻底删除本地仓库中残留的旧历史数据,缩小.git文件夹体积:git reflog expire --expire=now --all git gc --prune=now --aggressive
执行完以上步骤后,你的本地仓库就只会保留最后一次提交,.git文件夹体积会大幅缩小,且该提交会被标记为grafted。
三、另一种实现方式:创建孤立分支
如果你不想依赖远程仓库,也可以通过创建孤立分支的方式截断历史:
创建无历史的孤立分支
git checkout --orphan temp_branch提交当前工作区的所有内容
git add -A git commit -m "Truncated history to latest state"替换原有主分支
删除原来的主分支(比如main),并将临时分支重命名为主分支:git branch -D main git branch -m main清理旧历史
同样执行垃圾回收命令清理残留数据:git reflog expire --expire=now --all git gc --prune=now --aggressive
这种方式创建的提交也会显示grafted标记,因为它没有任何父提交记录。
内容的提问来源于stack exchange,提问作者Billy

