乐趣区

关于git:没想到Git居然有3种后悔药

你晓得 Git 版本控制系统中都有哪些“后悔药”吗?

本文通过案例解说 git reset、git revert、git checkout 在版本控制中的作用;

场景

小明同学作为新人退出到一个新的项目组中做开发,在我的项目的迭代开发中,小明勤勤恳恳的写代码,直到有一次 …

小明:完了,完蛋了
洋仔:怎么了,一惊一乍的

小明:我把错误代码用 git commit 后还 push 到线上代码库了 !这可怎么办!
洋仔:莫慌,git 有“后悔药”!

洋仔:容我给你缓缓道来。然而咱们要先晓得一些 git 的基础知识,你能力更好的了解 git 命令的作用

准备常识

git 将我的项目的存储分为 4 局部,每局部有本人作用,

见下图:

  • Workspace:工作区(以后用户操作批改的区域)
  • Index / Stage:暂存区(add 后的区域)
  • Repository:仓库区或本地仓库(commit 后的区域)
  • Remote:近程仓库(push 后的区域)

整体过程能够简述为:

  • 工作区–>add–> 暂存区–>commit–> 本地仓库区–>push–> 近程仓库区
  • 近程仓库区–>fetch–> 应用 refsremotes 下对应分支文件记录近程分支末端 commit_id 和 本地仓库区 –>merge–> 工作区
  • 近程仓库区–>pull–> 应用 refsremotes 下对应分支文件记录近程分支末端 commit_id and 本地仓库区 and 工作区

具体的 git 的组成部分和概念命令,请移步下述两个博客(超链接):

Git 技术干货!工作中 Git 的应用实际和常用命令合集!

Git – 应用 git 不晓得外部实现机制怎么行

假如我的项目存在这么一个提交记录:

$ git log
commit commit_id4 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第三次批改 README 文件

commit commit_id3 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第二次批改 README 文件

commit commit_id2
Author: test
Date:   Thu Aug 20 16:28:19 2020 +0800
    第一次批改 README 文件

commit commit_id1
Author: test
Date:   Thu Aug 20 16:26:59 2020 +080
    初始化我的项目

提交程序为:commit_id1 –> commit_id2 –> commit_id3 –> commit_id4

留神:在 git 中每次的 commit 都有一个 commit id 惟一标识以后的提交!

上面,咱们先来解决小明的这个问题,应用 git reset 即可完满解决~

问题解决

洋仔:小明,你的这个就能够用git reset 这个命令来完满的搞定,上面咱们看一下如何解决

1、获取以后提交的 commit id

命令:git log

获取到以后我的项目分支下的所有 commit 记录;

假如上述小明提交谬误的 commit id 为 commit id:commit_id4 这一次提交;

他的上一次提交就是 commit id:commit_id3,咱们要将批改回滚到commit_id3 的时刻!

小明:我想要把我方才 commit 的批改保留下来,我批改的代码不能给我删除掉呀!

洋仔:没问题

2、将某个 commit id 前的 commit 革除,并 保留批改的代码

命令:git reset <commit_id> 以后场景下就是:git reset commit_id3

将指定 commit_id 后的所有提交,都去除,并保留批改的代码在本地的区域,也就是 Workspace

小明:啊哈,这样的话我就能够把错误代码批改后再提交了;然而我曾经 push 到线上仓库的数据怎么办呢?

洋仔:别急,有方法~

3、批改代码实现后,将批改好的代码 add 到暂存区,并提交到本地仓库中

命令:git add <file_name> and git commit 以后场景下:git add . and git commit

将最新批改后的代码 commit

则提交后的提交记录假如如下:能够看到,咱们谬误提交的 commit_id4 提交记录隐没,取而代之的是咱们更新代码后提交的记录commit_id5;这样就实现了本地的代码批改和更新

$ git log
commit commit_id5 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第三次批改 README 文件 - 更新谬误后提交

commit commit_id3 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第二次批改 README 文件

commit commit_id2
Author: test
Date:   Thu Aug 20 16:28:19 2020 +0800
    第一次批改 README 文件

commit commit_id1
Author: test
Date:   Thu Aug 20 16:26:59 2020 +080
    初始化我的项目

4、将本地批改同步到近程仓库

命令:git push origin HEAD --force

将本地批改强行同步到近程仓库,使得近程仓库和本地仓库保持一致!

整体流程如下:

git log
git reset commit_id3
批改代码
git add .
git commit -m '第三次批改 README 文件 - 更新谬误后提交'
git push origin HEAD --force

洋仔:好了,小明,你的问题完满解决了

小明:哦吼,然而我还有一个问题:如果我想要 不保留回滚 commit 的批改,间接删除掉批改!该怎么解决呢?

洋仔:简略~ 咱们整体看一下 git reset 命令

后悔药 -git reset

在进行上面的解说是,还是先假如有这么一个提交链:

commit_id1 --> commit_id2 --> commit_id3 --> commit_id4

git reset <param> commit_id2:

reset 是将 HEAD 从新定位到 commit_id2 上,对于 commit_id3 和 commit_id4 和本地以后的批改,对于不同的参数 param,会有不同的解决;

reset 命令有三种解决模式:

  • –soft:保留 commit 批改,将批改存储到 index 中;也就是说 git add 后的区域
  • –mixed:保留 commit 批改,将批改存储到本地工作区域中;也就是说 git add 前的区域
  • –hard:删除 commit 批改,慎用!

git reset –soft

回滚 commit_id 前的所有提交,不删除批改:

git reset --soft commit_id

重设 head,不动 index,所以成果是 commit_id 之后的 commit 批改全副在 index 中
将 id3 和 id4 的批改放到 index 区(暂存区),也就是 add 后文件寄存的区域,本地以后的批改保留

git reset –mixed

回滚 commit_id 前的所有提交,不删除批改:
git reset commit_id 等同于 git reset --mixed commit_id

与 下述的 git reset –hard commit_id 成果不同

重设 head 和 index,不重设 work tree,成果就是 commit_id 之前的批改,全副在 work tree 中,为还未 add 的状态
将 id3 和 id4 的所有批改放到本地工作区中,本地以后的批改保留

git reset –hard

回滚 commit_id 前的所有提交,将批改全副删除:
git reset --hard commit_id

重设 head、index、work tree,也就是说将以后我的项目的状态复原到 commit_id 的状态,其余的全副删除(蕴含 commit_id 后的提交和本地还未提交的批改)
慎用!!

后悔药 -git revert

小明:原来 git reset 这么弱小呀!然而我这还有个问题:

如果想要只操作批改两头的一个 commit,不对其余的 commit 产生影响;也就是相似于咱们只批改 commit_id2,而对 commit_id3 和 commit_id4 无影响,该怎么解决呢?

洋仔:(这么多问题,幸好我懂,要不这次就丢大了。。)简略!git revert 命令!

实用场景: 在我的项目开发中,忽然发现在前几次的提交中,有一次提交中蕴含一个 bug;当然咱们能够进行一个新的批改,而后再提交一次;然而,不优雅哈哈;咱们能够间接 重做 有 bug 的 commit~

为什么不间接去再增加一个 commit 呢? git revert 是用于“反做”某一个版本,以达到撤销该版本的批改的目标。

比方,咱们 commit 了三个版本(版本一、版本二、版本三),忽然发现版本二不行(如:有 bug),想要撤销版本二,但又不想影响撤销版本三的提交,就能够用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的货色,但撤销了版本二的货色;

在 revert 命令中罕用的就两个:

  • git revert -e <commit_id>:重做指定 commit 的提交信息
  • git revert -n <commit_id>:重做执行 commit 的代码批改

git revert -e

重做 commit_id 的提交信息,生成为一个新的 new_commit_id
git revert -e commit_id

git revert -n

重做 commit_id 的提交
git revert -n commit_id
将 commit_id 中批改,放到 index 区,咱们能够对他从新做批改并从新提交

revert vs reset

  • git revert 是用一次新的 commit 来回滚之前的 commit,此次提交之前的 commit 都会被保留不动;
  • git reset 是回到某次提交,提交及之前的 commit 都会被保留,然而此 commit id 之后的批改都会被删除或放回工作区期待下一次提交;

小明:还有这种操作,能够间接独自操作提交过程中的某一个 commit!太棒了!

后悔药 -git checkout

小明:还有最初一个问题:

如果我在一次开发中,发现某个文件批改谬误了,想要将文件复原到刚 pull 代码时的状态 怎么办呢?

洋仔:简略!看 git checkout 解决这个问题!

咱们晓得应用 git checkout 能够

  • git checkout <branch_name>切换分支
  • git checkout -b <branch_bame>创立分支等操作

它还有 回滚指定文件的批改 的性能

命令:git checkout -- <file_name>

上述语句的作用,就是将 file_name 的本地工作区的批改全副撤销,有两种状况:

  • 如果 file_name 在 commit 后没有 add 过这个文件,则撤销到版本库中的状态
  • 如果 file_name 在 commit 后 add 过这个文件,则撤销到暂存区的状态,也就是 add 后的状态

总之,就是让指定的文件回滚到最近的一次 git add 或者 git commit 时的状态!

小明:太棒了,当前再也不怕提错代码了!

总结

上述,咱们介绍了 git reset git revert git checkout 在版本回滚、重做、撤销批改方面的作用;

能够利用到工作中对 误操作、不满足要求、不满足志愿的 commit 记录的重做和批改;

不必慌谬误的 commit 了,撒花~

退出移动版