如何将Fork仓库中原项目的所有提交squash为单个提交?
先再明确下当前和期望的提交历史,方便你对照:
当前提交历史(用git log --oneline查看的简化版):
klmno Currently newest commit ... fghij Initial commit of mine abcde Last commit made by them ... vwxyz Initial commit of theirs
期望提交历史:
klmno Currently newest commit ... fghij Initial commit of mine prstu Fresh X installation
接下来是逐行操作步骤,每一步都讲清楚为什么这么做:
第一步:先确保本地仓库干净,没有未提交的改动
打开终端,进入你的项目文件夹,执行命令:git status看输出,如果显示
nothing to commit, working tree clean,就可以继续。如果有红色的未追踪文件或者绿色的已暂存文件,要么把它们提交(git add .+git commit -m "临时保存改动"),要么用git stash暂存起来(之后可以用git stash pop恢复),总之要保证工作区是干净的,不然rebase会出问题。第二步:启动交互式rebase,包含所有根提交
执行命令:git rebase -i --root解释一下:
-i是交互式模式,会让你编辑提交列表;--root表示从仓库的第一个提交(也就是原仓库的vwxyz)开始处理所有提交。执行后会弹出一个文本编辑器(默认是Vim,如果你用不惯,可以先执行git config --global core.editor nano改成更简单的Nano编辑器)。第三步:修改提交列表,把原仓库的提交合并成一个
在弹出的编辑器里,你会看到所有提交按时间从早到晚排列(最上面是最早的vwxyz,最下面是最新的klmno)。你需要做的是:- 保留原仓库第一个提交(vwxyz)前面的
pick不动 - 把原仓库其他所有提交(从vwxyz之后到abcde的每一个)前面的
pick改成squash(或者缩写s也可以) - 你自己的所有提交(fghij及之后的)前面的
pick全部保留不动
举个例子,修改前的列表大概是这样:
pick vwxyz Initial commit of theirs pick 123456 Some commit by them pick abcde Last commit made by them pick fghij Initial commit of mine pick klmno Currently newest commit修改后变成:
pick vwxyz Initial commit of theirs s 123456 Some commit by them s abcde Last commit made by them pick fghij Initial commit of mine pick klmno Currently newest commit解释:
pick是保留这个提交,squash是把当前提交合并到它上面的那个提交里。这样原仓库的所有提交就会被合并成一个,就是最上面的vwxyz那一个。- 保留原仓库第一个提交(vwxyz)前面的
第四步:修改合并后的提交信息
保存并关闭编辑器(Vim里按Esc,然后输入:wq回车;Nano里按Ctrl+O回车保存,再按Ctrl+X退出)。这时候会弹出第二个编辑器,让你编辑合并后的提交信息。把原来的内容删掉,改成你想要的,比如Fresh X installation,然后保存关闭。第五步:检查提交历史是否符合预期
执行命令:git log --oneline看输出,应该能看到原仓库的一堆提交变成了一个,比如
prstu Fresh X installation,紧接着是你的fghij Initial commit of mine,然后是后面的提交,和你期望的完全一致。第六步:如果已经推送到远程,强制更新远程分支
如果你之前已经把这个分支推送到GitHub/GitLab等远程仓库了,因为我们修改了提交历史,普通的git push会失败,需要执行强制推送:git push --force-with-lease解释:
--force-with-lease比直接--force更安全,它会先检查远程分支有没有别人的新提交,避免不小心覆盖别人的工作。如果是你自己的私有仓库,也可以用git push --force,但前者更稳妥。
小提醒
- 如果在rebase过程中搞砸了,比如改错了提交列表,直接执行
git rebase --abort就能回到操作前的状态,重新来就行,不用慌。 - 不要在多人协作的公共分支上做这种修改历史的操作,会给其他同事带来很大麻烦,只在你自己的私有分支上操作哦。
内容的提问来源于stack exchange,提问作者dczajkowski

