perl – 用git高效重写(rebase -i)很多历史
我有一个git存储库,在最新版本中有大约3500个提交和30,000个不同的文件.它代表了来自多个人的大约3年的工作,我们已经获得了使其全部开源的许可.我正在努力发布整个历史记录,而不仅仅是最新版本.为此,我感兴趣的是“回到过去”并在创建文件时在文件顶部插入许可证标题.我实际上有这个工作,但完全用ramdisk运行大约需要3天,但仍然需要一些手动干预.我知道它可以快得多,但我的git-fu不能完成任务.
问题是:如何更快地完成同样的事情? 我目前做什么(在脚本中自动化,但请耐心等待……): >确定将新文件添加到存储库的所有提交(其中只有500个,fwiw): git whatchanged --diff-filter=A --format=oneline >将环境变量GIT_EDITOR定义为我自己的脚本,在文件的第一行只用一次编辑替换pick(你很快就会明白为什么).这是该操作的核心: perl -pi -e 's/pick/edit/ if $. == 1' $1 >对于上面git以上输出的每个提交,在添加文件的提交之前调用交互式rebase: git rebase -i decafbad001badc0da0000~1 我的自定义GIT_EDITOR(perl one-liner)更改选择进行编辑,我们将被删除到shell以更改新文件.另一个简单的header-inserter脚本在我试图插入的标题中查找已知的唯一模式(仅在已知文件类型中(*.[chS] for me)).如果它不存在,则插入它,然后git添加文件.这种天真的技术不知道在当前提交期间实际添加了哪些文件,但它最终做了正确的事情并且是幂等的(对同一文件多次运行是安全的),并且不是这整个过程瓶颈的地方无论如何. 在这一点上,我们很高兴我们已经更新了当前的提交,并调用: git commit --amend git rebase --continue 反叛 – 继续是昂贵的部分.因为我们为whatchanged的输出中的每个修订调用一次git rebase -i,这就是很多重新定位.这个脚本运行的几乎所有时间都花在观看“Rebasing(2345/2733)”计数器增量上. 它也不仅仅是缓慢的.必须解决定期发生的冲突.至少在这些情况下(但可能更多)会发生这种情况:(1)当“新”文件实际上是现有文件的副本时,对其第一行(例如,#include语句)进行了一些更改.这是一个真正的冲突,但在大多数情况下可以自动解决(是的,有一个处理它的脚本). (2)删除文件时.通过确认我们想要用git rm删除它,这是可以轻易解决的. (3)有些地方似乎差异只是表现不好,例如,改变只是添加一个空行.其他更合理的冲突需要人工干预,但总的来说它们不是最大的瓶颈.最大的瓶颈绝对只是坐在那里盯着“Rebasing(xxxx / yyyy)”. 现在,单个rebase是从较新的提交启动到较旧的提交,即从git输出的顶部开始.这意味着第一个rebase影响了昨天的提交,最终我们将从3年前重新定位提交.从“较新”到“较旧”似乎是违反直觉的,但到目前为止,我并不认为这很重要,除非我们在调用rebase时将多个选项更改为编辑.我害怕这样做是因为冲突确实到来了,而且我不想处理冲突的浪潮,试图一次性改变一切.也许有人知道避免这种情况的方法吗?我无法想出一个. 我开始研究git对象1的内部工作原理!看起来似乎应该有一种更有效的方法来遍历对象图并只进行我想要进行的更改. 请注意,这个存储库来自一个SVN存储库,我们实际上没有使用标签或分支(我已经git过滤器将它们分开),所以我们确实有直线历史的便利.没有git分支或合并. 我确定我已经遗漏了一些关键信息,但是这个帖子似乎已经过了很长时间.我会尽力按要求提供更多信息.最后,我可能需要发布我的各种脚本,这是一种可能性.我的目标是弄清楚如何在git存储库中重写历史;不要讨论其他可行的许可和代码发布方法. 谢谢! 更新2012-06-17:Blog post以及所有血腥细节. 解决方法
运用
git filter-branch -f --tree-filter '[[ -f README ]] && echo "---FOOTER---" >> README' HEAD 本质上会在README文件中添加一个页脚行,历史看起来就像文件创建后一直存在,我不确定它是否足够有效,但这是正确的方法. 制作一个自定义脚本,你可能最终得到一个好的项目历史,做太多“魔术”(rebase,perl,脚本编辑等)可能会以意想不到的方式丢失或改变项目历史. jon(OP)使用这种基本模式来实现显着简化和加速的目标. git filter-branch -d /dev/shm/git --tree-filter 'perl /path/to/find-add-license.pl' --prune-empty HEAD 一些性能关键的观察. >使用-d<目录>指向ramdisk目录的参数(如/ dev / shm / foo)将显着提高速度. git filter-branch -d /dev/shm/git --tree-filter 'find . -name "*.[chS]" -exec perl /path/to/just-add-license.pl {} ;' --prune-empty HEAD 这是OP使用的perl脚本的清理版本: #!/usr/bin/perl -w use File::Slurp; use File::Find; my @dirs = qw(aDir anotherDir nested/DIR); my $header = "Please put me at the top of each file."; foreach my $dir(@dirs) { if (-d $dir) { find(&;Wanted,$dir); } } sub Wanted { /.c$|.h$|.S$/ or return; # *.[chS] my $file = $_; my $contents = read_file($file); $contents =~ s/rn?/n/g; # convert DOS or old-Mac line endings to Unix unless($contents =~ /Please put me at the top of each file./) { write_file( $file,{atomic => 1},$header,$contents ); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 为什么VB不会阻止在现场初始化中使用“Me”,像C#与“this”
- 理解 Delphi 的类(十) - 深入方法[5] - Result 与函数名
- [Perl语法篇] 05 -- 变量作用域:our、local、my、state
- 我如何模拟Perl的内置backticks操作符?
- 如何让NGX LUA模块的POST返回不是Chunk模式,而GET必须是Ch
- 使用power bi cloud (1)
- lua_next函数分析
- lua.c:80:31: fatal error: readline/readline.h: No such
- [VB.NET]getfilenames的问题求助!
- delphi – 单个用户的多个连接