有一个简单app的完整源代码,需要根据它制作教材。所以,我在想,从完整的源代码初始化一个 git 存储库,然后开始以相反的顺序简化和删除部分,并提交每个后续更简单的工作版本,直到只有一个“你好,世界!” 遗迹。
问题:如何在 git 存储库中反转提交,保留提交消息等,使其看起来像最初按此顺序提交?
可以使用任何其他 VCS 来完成简化部分,只要最终结果是 git repo。
有一个简单app的完整源代码,需要根据它制作教材。所以,我在想,从完整的源代码初始化一个 git 存储库,然后开始以相反的顺序简化和删除部分,并提交每个后续更简单的工作版本,直到只有一个“你好,世界!” 遗迹。
问题:如何在 git 存储库中反转提交,保留提交消息等,使其看起来像最初按此顺序提交?
可以使用任何其他 VCS 来完成简化部分,只要最终结果是 git repo。
我会使用git format-patch
将补丁放入文件中,按时间顺序对它们进行排序(编号文件名,然后sort -r
是 ),并使用git apply --reverse
. 然后我会使用交互式 rebase ( -i
) 来修复细节并提交消息。
无论如何,git 是很好的工具,因为您可以轻松地操纵历史,但这需要一些工作。
编辑:
当我稍后看到这个时,我对如何做到这一点有了更好的想法。它不改变基本原理,只改变实现:
我希望,您在主分支中有一些历史记录的存储库。因此,在当前 HEAD上镜像提交的最简单方法是:
git checkout -b mirror
git log --format=%H | xargs -n 1 git revert
现在您在 master 分支中有旧的历史记录,并且 master 和 mirror 之间的新提交是来自 master 的反向提交。就像照镜子一样。我猜你会想要删除旧的历史并编辑提交消息,所以玩得开心git rebase -i
。
我编写了一个脚本“git-reverse.sh”,它完全反转了 git repo 的所有分支。
它使用组合git log --pretty="%T"
来提取树哈希,并git commit-tree
针对原始树对象(文件)创建新的提交对象,但父边缘反转。
它似乎被一些回购卡住了。我不知道为什么。
你可以在这里找到它:
https://github.com/gsylvie/git-reverse.sh
示例用法
git clone --mirror [git-clone-url]
cd [repo.git]
./git-reverse.sh
git log --all --date-order --graph --decorate
示例输出
$ ./git-reverse.sh
be0923ece8f73281e5e54906c29debb852894b92 - Reversed 1 of 360 (0%)
061bca59b29e75becbde66d2e510fc2b4059ccb2 - Reversed 2 of 360 (0%)
6a19039e05e3a0186187d0a6943634e8499b5a65 - Reversed 3 of 360 (0%)
7afe25e8caf93eb7107471a1bd078d4adc3f6999 - Reversed 4 of 360 (1%)
8b556f6fe97c5357c2328467a5ba01b77931ff82 - Reversed 5 of 360 (1%)
71fd0883975154f48059ca929db8ccb659c5049a - Reversed 6 of 360 (1%)
[etc...]
Switched to branch 'master'
Your branch and 'origin/master' have diverged,
and have 199 and 159 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
*********************************************
| Git repo successfully reversed!!! :-) (-: |
*********************************************
To push the reversed repo:
rm .git/packed-refs
rm -rf .git/refs/remotes
git push --mirror [new-git-clone-url]
WARNING:
========
Pushing a reversed git repo is a profoundly destructive and confusing operation.
You have a full 'git clone --mirror' backup stored somewhere safe, right?
如果存储库中的提交数量有限(我认为在制作教材时就是这种情况),我认为您可以简单地手动以相反的顺序执行樱桃挑选。
A <- B <- C <- D <- E
^HEAD
假设 A 是第一个空的提交,而 B 是完整的文件集,CDE 正在逐步删除文件,我认为你可以从 A 的另一个分支开始
A <- B <- C <- D <- E
^NewHead ^HEAD
和樱桃挑选 E、D、C、B 到 New Head:
A <- B <- C <- D <- E
^ ^HEAD
\- E' <- D' <- C' <- B'
^NewHead
当然,如果确实有很多提交,那么在导入之前导出补丁并使用脚本来操作它们(如其他答案所建议的那样)可能是更好的选择
首先,我不明白您为什么需要更改提交。您可以按任何顺序签出相应的版本。即git checkout master~1
,显示,git checkout master~2
显示,等等。
如果您确实需要它来获取您的历史记录,请尝试使用revert
which replays history back。例如git revert HEAD~5..HEAD
,将以相反的顺序恢复最后 5 次提交。但是,它会生成提交消息来说明它是Revert "old commit message"
. 但是您可以编写脚本来修改消息。