Git 救了这个 Blog
Git 命令千万条,安全第一条,操作不规范,Commit 全丢完。
首先,不要犯懒;其次,不要随便 git reset --hard 和 push --force;再次,操作之前想清楚;最后 git reflog 救我狗命。
TL; DR:git reflog 找到丢失的 commit 的 SHA-1,然后 git reset <commit> --hard 恢复原始状态。
之前写过我在 jekyll/minima 的基础上进行一些魔改,与之而来的问题就是与官方仓库进行同步时可能会有冲突:同一个文件的同一段内容,既被上游更改了又被我魔改了。而这次的问题就出在试图与上游同步中我的一系列弱智操作。
弱智操作回顾
前面说了背景了,这里 jekyll/minima 就是上游(upstream),我自己的修改作为 main。
- 初始状态
a -> b -> c -> d (upstream) \ r (main)初始的状态很好理解,图中每一个字母是一次提交,我从
b之后开始魔改,即r;与此同时upstream也在进行自己的开发c和d。 - 同步上游
a -> b -> c -> d (upstream) \ r (main) | r (sync)这是第一次同步上游的时候,从
main分支分出来一个sync分支用来和upstream进行同步。a -> b -> c -> d (upstream) \ / r -> s_m (sync) | s_m (main)在
sync解决冲突问题之后(形成s_m提交),再和main合并。到这里还是一切正常,那么我继续魔改就会变成下面这样,但问题的种子在这里埋下了:
sync分支其实应该用完就删,但我懒了一下。a -> b -> c -> d -> e -> f (upstream) \ / r -> s_m (sync) \ t -> u (main) -
懒一下再懒一下,开始混乱
接下来就是这次的状况了:我又想同步上游了,从upstream向main提交了 pr,按着 Github 的流程开始解决冲突。这时按着标准流程应该重新从
main分一个sync出来,保证sync与main有相同的历史,但遗憾的是我忘记了上一次同步之后又进行了魔改,想当然的认为不需要重新把sync删了重建。于是按着上面的流程一套下来就导致虽然
sync与upstream同步上了,但是sync的历史变成了a -> b -> r -> s_m -> s_m2,与main的a -> b -> r -> s_m -> t -> u也冲突了。a -> b -> c -> d -> e -> f (upstream) \ / / r -> s_m -----> s_m2 (sync) \ t -> u (main)这个时候虽然乱了一些但还没出现什么问题,我想着合都合完了再合一次也无伤大雅,于是又懒了一下在
main分支处理了一次和sync的合并。a -> b -> c -> d -> e -> f (upstream) \ / / r -> s_m -----> s_m2 (sync) \ | t -> u -> v_m (main)这个时候的 commit 历史就真的混乱了。
-
意外:合 炸 了。
在合并之后我测试了一下发现不能正常的编译,原因是上游在皮肤里加了新的颜色,然后我一看加了还不止一个,仔细调试有点麻烦于是打算先滚回去。其实 Github 的 PR 有一个
revert的功能,但是因为我在main分支处理了sync分支的合并,导致没办法直接revert了。 -
灵 感 突 现
那该怎么能 revert 呢?诶,我有一个点子☝️🤓:我们直接把v_m给hard reset掉不就行了。结果就是在
s_m和s_m2这两个节点之间在main分支之间的提交全丢了。好死不死的是我刚刚还正好push --force了,意味着远程的仓库里也丢了。
解法
到这个情况我已经懵了,我完全不知道自己做了什么修改,甚至我已经在考虑从生成好的静态站里扒布局了。
不过抱着死马当作活马衣的想法,还是搜了一下,结果还真的看到了【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?!
帮大忙了。
先摘录一句话:
首先要先建立一個觀念,不管是用什麼模式進行 Reset,Commit 就是 Commit,並不會因為你 Reset 它然後就消失了。
具体的介绍可以查看地址内容,这里写一下我的过程:
Reflog找到原本的 commit 的 SHA-1。
Reflog 会记录HEAD的移动记录,因此在这里直接使用git reflog找到了之前 hard reset 时的移动记录。reset回合并后的 commit。
这里就很简单:git reset <commit> --hard,这里的<commit>就是第一步找到的 SHA-1 记录。reset回合并前的 commit。git log查看 commit 记录 SHA-1 但是这次学聪明了用了--soft,虽然我还是git push --force了。