1.把少量文件回退到B版本
git checkout B – 要回退的文件1 要回退的文件2
然后commit这两个文件得到新的版本D
本地: A — B — C — D
(HEAD)
repo: A — B — C
(HEAD)
此时 push,repo可以快速移动指针 HEAD,从C移动到D,push 成功。如果B版本中这个文件不存在,只是想删除呢?更简单,你直接rm删了再commit好了。
2.回退前1次,或者几次commit的所有变更(少用)
这种情况也非常简单,使用 revert undo 掉之前的 commit 就行了
git revert C 产生跟 B 内容一样的新commit B’,repo 快速移动到B’就行了
A — B — C — B’
(HEAD)
revert 是逆向回放,如果revert 的是B,由于C的一些变更,可能undo会有冲突,无法自动完成,所以它不是万能的,只适用于某些情况。
3.回退到某个指定版本
这是最容易引起force push的场景了,那么how to?假设repo如下,想回退到B
A — B — C — D
(HEAD)
git reset --hard B
git reset --soft D
第一个操作把 working, index, HEAD 都强行置为 B,状态如下
A — B
(HEAD)
第二个操作,把 HEAD 设置回 D,看起来状态如下,B’是跟B内容一样的状态
A — B — C — D — B’
(HEAD)
此时若 commit,得到如下状态,满足 fast forward
A — B — C — D — B’
(HEAD)
4.更好的姿势,不用 git reset --hard B,直接起个新分支
A — B — C — D
(HEAD)
git checkout -b ttt B
git reset --soft D
然后 commit 得到
ttt: A — B — C — D — B’
(HEAD)
把这个branch推到repo的master
git push origin HEAD:master 或者
git push origin ttt:master 都行
完事之后删掉这个临时的ttt branch即可
开临时新分支的最大的好处,是不会影响master分支,你可以更方便的查看或者切回master。不像hard reset后那样,丢掉了master的历史,只能借助reflog查看和恢复历史。