玩转 git reset

玩转 git reset

keywords: git reset soft mixed hard

前言

首先对网上一些对git reset用法的谬解进行辟谣,有些人会说git reset --hard是一种不可逆的操作,但是这种说法其实是错误的,因为--hard仅仅只是移动了指向HEAD,INDEXWorking directory
也就是说,如果仅仅只是调用了git reset --hard没有执行其他操作,还是可以被还原的,具体方法和原理,请继续阅读。

起因

我之前在多个分支上滥用rebase interactive导致最后这些分支合并到主分支之后,有很多重复的commit。
因为我用了rebase的squash功能,这些commit的message一样但是hash不一样,所以合并之后出现了很多重复的commit。
为了解决这些重复,我尝试了reset功能(虽然最后还是靠rebase,解铃还须系铃人啊,用的rebase -i中的drop功能)。

介绍

HEAD,INDEXWorking directory

以上三个词汇的意思来自于git book中的Reset Demystified(见文末reference)。
在这里我对它们的意思给出了我自己的理解,用我自己的思维来解释他们。

我简单的将所有的git commits认为是一个链表,一个可以产生分岔的链表,用不同的指针来指定不同分岔链表的表头,这些指针被成为分支。(以上全是我的个人理解,助于我理解git行为的,不代表git源码是如此组织的)
在链表论的基础上就很容易的理解HEAD,INDEXWorking directory
HEAD: 它是指向当前链表的头的指针。
INDEX: 它是指向即将被提交的commit的指针(还没被提交的commit哦)。
Working directory: 它是当前工作文件夹中的内容。
NOTE: 每个branch中的这三个指针都是独立的,但是被删的commit是会影响到其他的branch的。

如果Working directoryINDEX之间内容不同,文件就是红色的。

$ git status
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory)
modified: file.txt

no changes added to commit (use "git add" and/or "git commit -a")

如果INDEXHEAD之间不同,那么文件就是绿色的。

$ git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
modified: file.txt

NOTE: HEAD不会和Working directory比较

用法

git reset --soft

这个命令很简单,就是移动HEAD的指针,能往前移也能往后移。
如果当前是working tree clean的状态,那么输入

git reset --soft HEAD~

HEAD就会往前移一格(一次commit),此时INDEXHEAD的内容就会出现差异,文件差异就是绿色的。
此时,Working directoryINDEX的内容没有变化,只是HEAD的指针前移了。
在这种情况下,如果使用git commit那么就能在当前HEAD的基础上提交,相当于重新修改了commit。
如果将HEAD前移多格(git reset --soft hash_num),再使用git commit,那么就可以将这些commits全部压缩成一个commit,
这种操作有点像rebase interactive中的squash,见我前一篇博客,git squash commits

NOTE: 如果你用了git reset --soft命令后悔,想将HEAD变回最开始的样子,就输入git reset --soft hash_num,这里hash_num就是你想移回的commit的hash值

git reset --mixed

这个命令就是同时修改INDEXHEAD把他们移动到指定的commit中。
如果当前是working tree clean的状态,那么输入

git reset --mixed HEAD~

INDEXHEAD就会往前移动一格,此时Working directoryINDEX之间内容不同,文件就是红色的。
如果在当前情况下再输入git reset --soft就会发现,绿色和红色,同时出现了,哈哈。如果想要撤回就输入git reset --mixed hash_num
在这个命令下有个特殊的用法,可以单独还原某一个提交中的某一个文件

git reset --mixed hash_num file_nmae

git reset --hard

这个命令就是同时修改Working directoryINDEXHEAD把他们移动到指定的commit中。
此时这三者都是都被改变了,代表它们三者完全相同,那么输入git status之后可以看到working tree clean。
想要还原就输入

git reset --hard hash_num

hash_num 就是想要还原到的那个commit的hash值。

Reference

7.7 Git Tools - Reset Demystified

posted @ 2023-07-24 09:45  LogicBai  阅读(21)  评论(0编辑  收藏  举报