12-git reset 版本回退

1、知识前提:git 重要的三个工作区域

  1. 工作区(Working Directory):写代码的目录。就是项目代码存放的目录。
  2. 暂存区(index/stage):工作区与版本库之间的缓冲地带。用 git add 添加文件,实际上是把文件修改添加到暂存区。
  3. 版本库(仓库区):git commit 提交更改,实际上是把暂存区的所有内容全部提交到当前分支,查看记录 git log

2、git reset 版本回退

git reset 命令用于回退版本,可以指定退回某一次提交的版本。

语法

1
git reset [--soft | --mixed | --hard] [HEAD]

2.1 –mixed 默认参数。保留工作目录,将所有修改放入到工作区

示例:

1
2
3
$ git reset HEAD^            # 回退所有内容到上一个版本  
$ git reset HEAD^ main.java # 回退 main.java 文件的版本到上一个版本
$ git reset 052e # 回退到指定版本

作用:reset 默认使用 --mixed 参数。用于重置 暂存区和版本区 的文件。保留工作目录,并且清空暂存区中未提交的修改。也就是说,工作目录的修改、暂存区的未提交的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。简而言之,就是把所有差异都混合(mixed)放在工作目录中。

  • 版本区:移动 HEAD 指针指向 HEAD 参数指定的 commit_id,文件内容恢复到 HEAD 参数指定的 commit_id 提交时的内容。HEAD 参数指定的 commit_id 之后变化的内容放到工作区,变成未 add 状态。
  • 暂存区:文件内容与 HEAD 指定的 commit_id 提交时的数据保持一致。已 add 未 commit 的内容放到工作区,变成未 add 状态。
  • 工作区:文件内容保持不变,但是状态有所变更。工作目录的修改、暂存区的未提交的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。

使用场景:

  • 使用 reset --mixed 之后,执行 git add 将这些改变过的文件內容加入 暂存区(index) 中,再执行 git commit 将暂存区中的內容提交至仓库中,和 reset --soft 一样可以达到合并 commit 节点的效果。
  • 用于当发现 add 错了,执行 git reset HEAD 来重置暂存区(index)的文件。

测试:

  1. 第一次提交文件内容

    1
    add 1
  2. 第二次提交文件内容

    1
    2
    add 1
    add 2
  3. 修改文件

    1
    2
    3
    add 1
    add 2
    add 3
  4. 执行 git reset,然后执行 git statusgit diffgit diff --cached

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git reset a19a6f9917


    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git status
    On branch master
    Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git restore <file>..." to discard changes in working directory)
    modified: a.txt
    no changes added to commit (use "git add" and/or "git commit -a")


    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git diff
    diff --git a/a.txt b/a.txt
    index b9ff64e..3bf8a10 100644
    --- a/a.txt
    +++ b/a.txt
    @@ -1 +1,3 @@
    add 1
    +add 2
    +add 3
    \ No newline at end of file


    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git diff --cached

2.2 -soft 保留工作目录,并把重置 HEAD 所带来的新的差异放进暂存区。

作用:在重置版本库的时候,保留工作目录和暂存区中的内容,并把重置版本库所带来的新的差异放进暂存区。也就说是说,工作目录的内容不受影响,而暂存区中已经 commit 的内容变成已 add 的状态

  • 版本库:移动当前 Head 指针,指向 HEAD 参数指定的 commit_id,文件内容恢复到 HEAD 参数指定的 commit_id 提交时的内容。HEAD 参数指定的 commit_id 之后的内容放到 暂存区,变成未 commit 状态。
  • 暂存区:文件内容与 HEAD 指定的 commit_id 提交时的数据保持一致。重置版本库所带来的新的差异放进暂存区。
  • 工作区:文件内容保持不变,状态也不变,修改内容和删除内容还是未 add 的状态。

使用场景:

  • 使用 reset --soft 之后,commit_id 之后提交的内容会被放入暂存区(index)中,此时可以直接执行commit,将 commit_id 之后的提交作为一个 commit 来统一进行提交,减少不必要的log记录

测试:

  1. 第一次提交文件内容

    1
    add 1
  2. 第二次提交文件内容

    1
    2
    add 1
    add 2
  3. 修改文件

    1
    2
    3
    add 1
    add 2
    add 3
  4. 执行 git reset,然后执行 git statusgit diffgit diff --cached

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git reset --soft 2073078181eeea97951a2b1c2460b664b9ab2e25


    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git status
    On branch master
    Changes to be committed:
    (use "git restore --staged <file>..." to unstage)
    modified: a.txt

    Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git restore <file>..." to discard changes in working directory)
    modified: a.txt


    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git diff
    diff --git a/a.txt b/a.txt
    index 9237eb7..3bf8a10 100644
    --- a/a.txt
    +++ b/a.txt
    @@ -1,2 +1,3 @@
    add 1
    add 2
    +add 3
    \ No newline at end of file


    fenglepeng@PC00110544 MINGW64 /d/git/test (master)
    $ git diff --cached
    diff --git a/a.txt b/a.txt
    index 6bf3f98..9237eb7 100644
    --- a/a.txt
    +++ b/a.txt
    @@ -1 +1,2 @@
    add 1
    +add 2
    \ No newline at end of file

2.3 –hard 撤销工作区中所有未提交的修改内容,

作用:在重置版本的同时,重置暂存区和工作目录里的内容。也就说,就是在暂存区中你没有 commit 的修改会被全部擦掉,在工作区中你没有 add 的修改也被全部擦掉。

  • 版本库:移动当前 Head 指针,指向HEAD 参数指定的 commit_id,文件内容恢复到 HEAD 参数指定的 commit_id 提交时的内容。HEAD 参数指定的 commit_id 之后的内容丢失。
  • 暂存区与工作区:都回到指定版本,并删除所有未 commit 和未 add 的内容。
  • 最危险的操作,容易造成丢失

使用场景:

  • 使用 git reset --hard HEAD 来强制恢复 git 管理的文件夹的內容及状态;版本回滚。
    但是这种操作存在一个问题,服务器上的代码虽然被还原了,但假如有多个人在这个分支上开发,他们本地的版本依然是比服务器上的版本高的,所以,别人再重新提交(push)代码的话,你撤销的操作又会被重新,你上面的操作也就白操作了。
    解决办法是,让别人把本地的分支先删掉,然后重新从服务器上拉取分支,或者你在对方提交完所有本地代码之后对方没有再进行修改代码,这个时候你提交了,发现你提交的有问题,再进行reset操作,然后让对方拉取(pull)最新的代码也ok,最主要的就是对方本地没有你要reset的代码即可

  • 误删恢复。如果回滚代码之后发现复制错了 commit_id,或者误删了某次 commit 记录,也可以通过下方代码恢复:

    1
    2
    git relog // 复制要恢复操作的前面的 hash
    git reset --hard hash // 将 hash 换成要恢复的历史记录的 hash

12-git reset 版本回退
https://flepeng.github.io/044-Git-21-命令-12-git-reset-版本回退/
作者
Lepeng
发布于
2021年3月8日
许可协议