当某个性能开发结束之后,须要及时提交commit到以后分支。为了升高代码失落的危险,须要在失当的时候把以后分支推送到近程分支。然而,在某些场景下(比方:向分支提交了谬误的代码),须要从分支中撤销某个commit的提交。 面对这种理论需要,Git提供了两个命令:git revertgit reset。上面具体介绍这两个命令的应用以及区别。

git revert

命令:git revert <commit id>

创立revert commit,其内容为反转某个要撤销commit所引入的更改,向以后分支增加该commit。

原理:不是真正地撤销某个commit,而是利用互补原理,反转该commit所引入的更改。

应用场景 - 撤销某个非merge commit的commit

初始commit log:

            B2(B2)---B3(B3)---B4(B4)           /                    \B0(B0)---B1(B1)-----------------B4`(Merge branch 'fix')---B5(B5)

初始文件index.js:

B0 // you, 1 hours ago ∙ B0B1 // you, 2 hours ago ∙ B1B2 // you, 3 hours ago ∙ B2B3 // you, 4 hours ago ∙ B3B4 // you, 5 hours ago ∙ B4B5 // you, 6 hours ago ∙ B5
撤销commit id为B5的commit,删除所提交的代码“B5”

找到提交代码“B5”的commit的commit id,而后执行revert命令:

git revert B5

执行命令之后,会自动弹出编辑revert commit message:

Revert "B5"This reverts commit B5.# Please enter the commit message for your changes. Lines starting# with '#' will be ignored, and an empty message aborts the commit.## On branch master# Your branch and 'origin/master' have diverged,# and have 5 and 8 different commits each, respectively.#   (use "git pull" to merge the remote branch into yours)## Changes to be committed:# modified:   index.js

保留&退出revert commit message之后,revert commit就会主动增加在以后分支的末端。

后果:在以后分支增加revert commit,“B5”代码被删除。

此时commit log被改为:

            B2(B2)---B3(B3)---B4(B4)           /                    \B0(B0)---B1(B1)-----------------B4`(Merge branch 'fix')---B5(B5)---B6(Revert 'B5')
B0 // you, 1 hours ago ∙ B0B1 // you, 2 hours ago ∙ B1B2 // you, 3 hours ago ∙ B2B3 // you, 4 hours ago ∙ B3B4 // you, 5 hours ago ∙ B4

应用场景 - 撤销某个merge commit

初始commit log:

            B2(B2)---B3(B3)---B4(B4)           /                    \B0(B0)---B1(B1)-----------------B4`(Merge branch 'fix')---B5(B5)

初始文件index.js:

B0 // you, 1 hours ago ∙ B0B1 // you, 2 hours ago ∙ B1B2 // you, 3 hours ago ∙ B2B3 // you, 4 hours ago ∙ B3B4 // you, 5 hours ago ∙ B4B5 // you, 6 hours ago ∙ B5
撤销commit id为B4`的commit,删除所提交的代码“B2”、“B3”、“B4”

找到merge commit的commit id,而后执行revert命令:

git revert B4`

执行命令之后,打印出谬误的提醒:

error: commit B4` is a merge but no -m option was given.fatal: revert failed

通过查问相干文档理解到:无奈间接revert merge commit;因为merge commit的父级commit有多个,Git无奈判断要应用哪个父级commit(请察看下面的“初始commit log”,commit B4\`有两个父级commit:1. commit - B1,2. commit - B4);应用命令git revert <commit id> -m <parent number>,决定反转到哪个父级commit;parent number是自然数,以1开始,具体的parent number与commit id映射关系,能够查看merge commit - log中的merge字段。

通过命令git log <commit id>,查看merge commit的具体信息:

git log B4`commit B4`Merge: B1 B4Author: ......Date:   ......    Merge branch 'fix'......

通过下面的log信息,能够看出:parnet number为1的分支,其commit id为B1;parent number为2的分支,其commit id为B4。

因为须要“撤销commit id为B4\`的commit,删除commit id为B4\`的commit所提交的代码‘B2’、‘B3’、‘B4’”,所以须要让merge commit反转回到commit B1,执行命令:

git revert B4` -m 1

如果遇到合并抵触,则须要手动解决。提交revert commit message之后,revert commit就会主动增加在以后分支的末端。

后果:在以后分支增加revert commit,删除commit id为B4`的commit所提交的代码“B2“、“B3“、“B4“。

此时commit log被改为:

            B2(B2)---B3(B3)---B4(B4)           /                    \B0(B0)---B1(B1)-----------------B4`(Merge branch 'fix')---B5(B5)---B6(Revert "Merge branch 'fix'")
B0 // you, 1 hours ago ∙ B0B1 // you, 2 hours ago ∙ B1B5 // you, 6 hours ago ∙ B5

git reset

命令:git reset --hard <commit id>

将以后分支的HEAD指向为<commit id><commit id>之后的commit都从git log中移除,已达到撤销commit的目标。

命令中的--hard参数,表明:将强制复原到指定<commit id>时的状态。本地工作区、暂存区的批改都将被删除。

应用场景 - 撤销某个commit

初始commit log:

            B2(B2)---B3(B3)---B4(B4)           /                    \B0(B0)---B1(B1)-----------------B4`(Merge branch 'fix')---B5(B5)

初始文件index.js:

B0 // you, 1 hours ago ∙ B0B1 // you, 2 hours ago ∙ B1B2 // you, 3 hours ago ∙ B2B3 // you, 4 hours ago ∙ B3B4 // you, 5 hours ago ∙ B4B5 // you, 6 hours ago ∙ B5
撤销commit id为B5,删除commit id为B5的commit所提交的代码“B5”

找到提交代码“B5”的commit的上一级commit的commit id,而后执行reset命令:

git reset --hard B4

执行下面的命令之后,Git主动将HEAD复原到commit - B4,并且移除了commit - B5

此时commit log被改为:

            B2(B2)---B3(B3)---B4(B4)           /                    \B0(B0)---B1(B1)-----------------B4`(Merge branch 'fix')
B0 // you, 1 hours ago ∙ B0B1 // you, 2 hours ago ∙ B1B2 // you, 3 hours ago ∙ B2B3 // you, 4 hours ago ∙ B3B4 // you, 5 hours ago ∙ B4

总结:

git revert 和 get reset,这两个命令都能够达到撤销某个commit,删除该commit所提交更改的目标,但原理不一样:

  • git revert通过反转的操作,达到目标;长处是,不扭转commit log history,通过commit log能够清晰地看到撤销记录。
  • git reset通过移除commit,达到目标;长处是,彻底删除某个commit;毛病是,扭转了commit log history,不太适宜在公共分支上进行操作,除非能承当git reset之后的危险。