如何修剪git reflog历史
背景:
vscode插件git-graph可以方便查看git-commit-graph,效果很好,关键是交互性很好。
点选任意commit即可预览提交内容,实在是太方便了,比我之前用命令行上git log --graph --oneline强太多了。
但同时带来的困扰是能看到的信息(commit历史)太多了,让我眼花缭绕。
例如,为了修复一个issue,前后进行了10次git commit --amend。也就是一共11次提及历史记录。
git graph大概长这样
初衷:
实际上当我合并这次的修改之后,我只想保留最后一次的记录在reflog里,其他的10次提交历史都不要了。这就涉及到了git reflog修剪了。
实现:
首先,git 是通过HEAD找commit hash ID,然后每个commit都有parent commit,如此组成一条链式结构。
commit是描绘git-graph的主要依据,其实只要删掉一个commit就能改变git-graph的结果。
每一次提交都会在.git/objects目录下生成至少一个commit类型的文件,其完整的文件路径为.git/objects/12/34567xx... (这里假设这个commit hash id 是1234567xx...)
git cat-file -t可以查看.git/objects目录下的文件是tree、commit还是blob类型。
例如:
注意:不能删除当前分支上可达的commit,不然链就断了,git就无法正常工作了。前面提到的"其他的10次提交历史" 因为在当前分支已经不可达,所以可以删除
例如我想从git-graph删除一个hash为 1234567的commit
那么步骤为:
- 找到.git/objects/12/34567xx...
- 删除或者移动它 (建议移动到一个目录下,万一想要查看的时候还能还原)
因为git commit hash有缩写形式、引用形式、完整形式,但是.git/objects/下的文件名都是完整形式,这种事情当然要写个脚本来一劳永逸了。
#!/bin/bash function zlipd() { printf "x1fx8bx08x00x00x00x00x00" | cat - $@ | gzip - dc 2> /dev/null } function move_intermediate_obj() { local dst_path dst_path=$1; shift while [ -n "$1" ]; do if [ -f .git /objects/ "${1:0:2}" / "${1:2}" ]; then mv - v .git /objects/ "${1:0:2}" / "${1:2}" "$dst_path/$1" fi shift done } # function migrate_intermediate_obj() { # [ ! -d ./.git ] && { echo ".git dir not exist"; return; } # [ ! -d ./intermediate_obj ] && mkdir -p intermediate_obj # for f in $(git rev-list -n "${2:-1}" "${1:?params not enough}") # do # # echo "$f" # move_intermediate_obj "$f" # done # } migrate_intermediate_obj () { [ ! -d ./.git ] && { echo ".git dir not exist" ; return }; local dst_dir [ -d . /output ] && dst_dir=. /output/intermediate_obj ; [ -z $dst_dir ] && dst_dir=. /intermediate_obj ; mkdir -p $dst_dir if [ $ # -eq 1 ] then move_intermediate_obj $dst_dir "$1" ; elif expr $2 + 0 > /dev/null 2>&1 # test $2 whether is number otherwise $? neq 0/1 if $2 non-integer argument then for f in $(git rev-list -n "${2:-1}" "${1:?params not enough}" ); do move_intermediate_obj $dst_dir "$f" ; done else move_intermediate_obj $dst_dir "$@" ; fi }
脚本使用方法:
source script.sh
migrate_intermediate_obj 1234567
脚本将会在当前目录下创建一个文件intermediate_obj,并将commit文件移动进去。
PS:在git gc的时候有些commit会被打包到.git/objects/pack文件夹下的pack后缀的文件里,这样的话在.git/objects/下就找不到这些commit文件了。
解决办法是使用git unpack-objects < .git/*.pack文件解压出来。(pack文件和index文件要事先从.git/objects/pack移出去该命令才会有效果)
PS2:git verify-pack -v .git/objects/pack/pack-xx.pack可以查看哪个pack文件包含你要的commit
相关文章
- 金融服务领域的大数据:即时分析
- 影响大数据、机器学习和人工智能未来发展的8个因素
- 从0开始构建一个属于你自己的PHP框架
- 如何将Hadoop集成到工作流程中?这6个优秀实践必看
- SEO公司使用大数据优化其模型的5种方法
- 关于Web Workers你需要了解的七件事
- 深入理解HTTPS原理、过程与实践
- 增强分析:数据和分析的未来
- PHP协程实现过程详解
- AI专家:大数据知识图谱——实战经验总结
- 关于PHP的错误机制总结
- 利用数据分析量化协同过滤算法的两大常见难题
- 怎么做大数据工作流调度系统?大厂架构师一语点破!
- 2019大数据处理必备的十大工具,从Linux到架构师必修
- OpenCV中的KMeans算法介绍与应用
- 教大家如果搭建一套phpstorm+wamp+xdebug调试PHP的环境
- CentOS下三种PHP拓展安装方法
- Go语言HTTP Server源码分析
- Go语言HTTP Server源码分析
- 2017年4月编程语言排行榜:Hack首次进入前五十