工作区域
Workspace:本地文件系统上的一个目录,包含了从 Git 仓库中检出的项目文件。可以在这里查看、编辑和运行项目。
Index / Stage:暂存区是一个位于工作目录和仓库之间的临时区域。当我们对工作目录中的文件做出修改后,可以将这些修改添加到暂存区,以准备提交到仓库。
Repository:本地仓库,就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中 HEAD 指向最新放入仓库的版本
Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换
代码回滚
git reset
假如我们的系统现在有如下几个提交:
其中:A
和 B
是正常没有问题的提交,C
和 D
是存在错误的提交。现在,我们想把 C
和 D
回退掉。此时,HEAD 指针指向 D
提交(6tgh8)。我们只需将 HEAD 指针移动到 B
提交(a3456),就可以达到目的。
这个时候我们就可以使用 git 的 reset
命令来进回滚:
git reset --hard a3456
reset
的模式有四种:
soft
:将本地仓库回退到指定版本,暂存区和工作区不变。也就是说新增和修改的记录都会保留,后面还可以提交。
mixed
:将本地仓库回退到指定版本,暂存区清空,工作区不变。也就是说新增的文件会取消add
(在 idea 里表现就是这个文件变“红”了,需要重新add
才能提交),修改的记录保留,后面还可以提交。
hard
:将本地仓库回退到指定版本,暂存区和工作区清空。相当于是丢弃所选提交后的所有提交的内容。
keep
:将版本库回退的同时,将暂存区也清空,但工作区中文件如果当前版本和退回版本之间没有发生过变动,则工作区的修改保持不变;如果发生了变动,并且工作区也进行了修改,需要自行合并或解决冲突。
命令运行后,我们系统的版本如下:
我们在运行上面的命令后,修改的只是本地仓库,远程仓库的 HEAD 指针依然不变,仍在 D
提交上。所以,如果直接使用 git push
命令的话,将无法将更改推到远程仓库,会被远程拒绝。此时,可以使用 -f
/ -force
选项将提交强制推到远程仓库:
git push -f
采用这种方式回退代码的弊端显而易见,那就是会使 HEAD 指针往回移动,从而会失去之后的提交信息。
在这里提醒大家:不要轻易使用 git push -f,不要轻易使用!!!
会使用到强推可能是因为有一些不可描述的代码被误提交,希望这种不堪入目的代码永远消失在历史的长河中,于是,掏出百度查到了可以使用 git reset
回滚代码,然后使用 git push -f
强推到远程仓库,以为这样可以悄无声息的丢弃掉这段代码,殊不知,只要修改被提交,git 就已经将信息记录了下来,那段代码将会永永远远在远程仓库里烙下印记。
所以,再次提醒大家,不要轻易使用 git push -f !!!
而且,有些公司明令禁止使用 git reset
命令去回退代码。git reset
会引发多种问题,在多人协作的分支上,使用强推来回滚代码,会使其他人辛辛苦苦的代码丢失。
git revert
git revert
的作用通过反做创建一个新的版本,这个版本的内容与我们要回退到的目标版本一样,但是 HEAD 指针是指向这个新生成的版本,而不是目标版本。
简单来说就是我们提交了一个对于要回滚的提交的反向操作,来做到代码的回滚。
使用 git revert
命令来实现上述例子的话,我们可以这样做:先 revert D
,再 revert C
(有多个提交需要回退的话需要由新到旧进行 revert):
git revert 6tgh8
git revert d5rg7
这里会生成两个新有提交:D'
和 C'
,如下图示:
这里只有两个提交需要 revert,我们可以一个个回退。但如果有几十个呢?一个个回退效率太低而且容易出错。我们可以使用以下方法进行批量回退:
git revert OLDER_COMMIT^..NEWER_COMMIT
这时,错误的提交 C
和 D
依然保留。而且,这样操作的话 HEAD 指针是往后移动的,可以使用 git push
命令推送到远程仓库里。这种做法是被企业所鼓励的。
再举一个例子:
假如现有三个提交,有问题的提交位于中间位置。如下图示:
这时,直接使用 git reset
命令将 HEAD 指针重置到 A
提交显然是不行的,因为 C
提交是没问题的,需要保留。我们的做法是:先把 C
提交 及 B
提交全部回退,再使用 cherry-pick
命令将 C
提交重新再生成一个新的提交 C''
,这样就实现了将 B
提交回退的需求。完整的过程如下:
通过以上对比可以发现,git reset
与 git revert
最大的差别就在于,git reset
会失去后面的提交,而 git revert
是通过反做的方式重新创建一个新的提交,而保留原有的提交。