共计 3659 个字符,预计需要花费 10 分钟才能阅读完成。
当某个性能开发结束之后,须要及时提交 commit 到以后分支。为了升高代码失落的危险,须要在失当的时候把以后分支推送到近程分支。然而,在某些场景下(比方:向分支提交了谬误的代码),须要从分支中撤销某个 commit 的提交。面对这种理论需要,Git 提供了两个命令:git revert
和git 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 ∙ B0 | |
B1 // you, 2 hours ago ∙ B1 | |
B2 // you, 3 hours ago ∙ B2 | |
B3 // you, 4 hours ago ∙ B3 | |
B4 // you, 5 hours ago ∙ B4 | |
B5 // 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 ∙ B0 | |
B1 // you, 2 hours ago ∙ B1 | |
B2 // you, 3 hours ago ∙ B2 | |
B3 // you, 4 hours ago ∙ B3 | |
B4 // 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 ∙ B0 | |
B1 // you, 2 hours ago ∙ B1 | |
B2 // you, 3 hours ago ∙ B2 | |
B3 // you, 4 hours ago ∙ B3 | |
B4 // you, 5 hours ago ∙ B4 | |
B5 // 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 B4 | |
Author: ...... | |
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 ∙ B0 | |
B1 // you, 2 hours ago ∙ B1 | |
B5 // 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 ∙ B0 | |
B1 // you, 2 hours ago ∙ B1 | |
B2 // you, 3 hours ago ∙ B2 | |
B3 // you, 4 hours ago ∙ B3 | |
B4 // you, 5 hours ago ∙ B4 | |
B5 // 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 ∙ B0 | |
B1 // you, 2 hours ago ∙ B1 | |
B2 // you, 3 hours ago ∙ B2 | |
B3 // you, 4 hours ago ∙ B3 | |
B4 // 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 之后的危险。