经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件/图像 » Git » 查看文章
如何修剪git reflog历史
来源:cnblogs  作者:亦幻  时间:2023/2/8 8:58:00  对本文有异议

背景:

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
那么步骤为:

  1. 找到.git/objects/12/34567xx...
  2. 删除或者移动它 (建议移动到一个目录下,万一想要查看的时候还能还原)

因为git commit hash有缩写形式、引用形式、完整形式,但是.git/objects/下的文件名都是完整形式,这种事情当然要写个脚本来一劳永逸了。

  1. #!/bin/bash
  2.  
  3. function zlipd() {
  4. printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" | cat - $@ | gzip - dc 2> /dev/null
  5. }
  6.  
  7. function move_intermediate_obj() {
  8. local dst_path
  9. dst_path=$1; shift
  10. while [ -n "$1" ]; do
  11. if [ -f .git /objects/ "${1:0:2}" / "${1:2}" ]; then
  12. mv - v .git /objects/ "${1:0:2}" / "${1:2}" "$dst_path/$1"
  13. fi
  14. shift
  15. done
  16. }
  17. # function migrate_intermediate_obj() {
  18. #     [ ! -d ./.git ] && { echo ".git dir not exist"; return; }
  19. #     [ ! -d ./intermediate_obj ] && mkdir -p intermediate_obj
  20. #     for f in $(git rev-list -n "${2:-1}" "${1:?params not enough}")
  21. #     do
  22. #         # echo "$f"
  23. #         move_intermediate_obj "$f"
  24. #     done
  25. # }
  26.  
  27. migrate_intermediate_obj ()
  28. {
  29. [ ! -d ./.git ] && {
  30. echo ".git dir not exist" ;
  31. return
  32. };
  33.  
  34. local dst_dir
  35. [ -d . /output ] && dst_dir=. /output/intermediate_obj ;
  36. [ -z $dst_dir ] && dst_dir=. /intermediate_obj ;
  37. mkdir -p $dst_dir
  38.  
  39. if [ $ # -eq 1 ]
  40. then
  41. move_intermediate_obj $dst_dir "$1" ;
  42. elif expr $2 + 0 > /dev/null 2>&1 # test $2 whether is number otherwise $? neq 0/1 if $2 non-integer argument
  43. then
  44. for f in $(git rev-list -n "${2:-1}" "${1:?params not enough}" );
  45. do
  46. move_intermediate_obj $dst_dir "$f" ;
  47. done
  48. else
  49. move_intermediate_obj $dst_dir "$@" ;
  50. fi
  51. }

脚本使用方法:
??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

原文链接:https://www.cnblogs.com/Bolia/p/17099288.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号