Fuhui

Git撤销本地修改


懂得了好多大道理,但还是过不好这一生!

用了git就会发现,再也不想用svn了。

Note:在执行push操作前,所有的修改都发生在本地,可以使用reset随便回滚本地的提交。但要注意:本地修改一旦回滚,无法找回。push,想要回滚到指定的版本,便需要使用revert,这样的代价就是:你的回滚记录被记录在了log中,所有人都可以看见。

使用reset回退

本质上是commit操作的回退。Git工作流可以简化为三个部分:Working DirectoryindexHEAD。后两部分对应的git命令便是addcommit。如果使用的是Sourcetree工具,那么这三部分就更直观了。

该命令的具体功能是移动HEAD,即移动分支的指针。将当前的HEAD重新指向之前的版本,本地工作环境也会跟着切换。适用场景:本地已经commit,但尚未push到远端仓库的回滚操作。

该命令提供了三个属性:分别是softmixed、和hard

  1. soft撤销上一次的commit命令,返回到HEAD前的index状态。
  2. mixed撤销了上一次的git addgit commit命令,将index的修改回滚到Working Directory
  3. hard撤销了最后git addgit commit 命令以及工作目录中的所有修改。

所以reset重写的顺序如下:

  1. 移动 HEAD 指向的分支(如果是soft,则到此停止)。
  2. 使索引看起来像 HEAD(如果是mixed,则到此停止)。
  3. 使工作目录看起来像索引。

Example

当执行pull命令发生冲突时时,本地代码需要做merge操作。但本地代码只是临时调试修改,并不需要保存提交。执行如下命令,便会清空本地的修改,hard相当于一个版本的指针,origin/master可以替换为具体的版本号

git reset --hard origin/master
git reset --hard version-number
git reset --hard HEAD

获取版本号可以通过git log直接查看。

更多详细介绍,可以查看: 高级合并重置揭密

checkout

stash储藏

将工作区的修改进行存储,使本地重新成为一个干净的环境,同时方便在之后应用这些改动。可以用于存储已被索引的文件、或者未跟踪的文件。执行git stash -a来暂存所有改动的文件。常见的包括如下命令:

  1. git stash 储藏修改
  2. git stash list 查看储藏的列表
  3. 将储藏重新应用到当前分支:git statsh apply stash@{1}或者git stash pop stash@{1}。后者会在应用暂存之后从堆栈上删除
  4. git stash drop stash@{1} 移除暂存
  5. git stash clear 清除本地所有的贮藏历史

使用clean清空

用于从==工作区==移除==未被追踪的文件==,执行git clean -d -f来移除所有未被追踪的文件或目录。

  1. git clean -d -n 可以用来做一次删除前的演示
  2. git clean -d -i 用于交互式的删除文件

使用revert

我们工作区看到的内容,是所有版本修改合并的结果。如果觉得某个版本的提交有问题,使用revert便可以直接撤销这个版本的修改。本质上通过提交新的版本来撤销修改。

--> (modify version 1) --> (modify version 2) --> (modify version3)

执行git revert 版本号仅仅是撤销这个版本的修改。如果你想将版本回滚到version 1,你需要执行2次revert操作。且每次执行revert都会有一个新的版本生成。

Revert a merge

回滚merge提交跟普通的提交是有区别的。我们一般都是在分支上开发,然后将修改合并到主分支上。所以merge的那个提交版本,存在两个parent分支。

所以,执行git revert MERGE_HASH是不能正常工作的。原因在于这个提交存在多个parent,它需要有额外的信息来决定哪一个分支作为回滚的主线。参数-m就是用来干这个的。

git revert 0cce3a0837da60fb8ef458d98f81feaa97397363
error: Commit 603c1333339bc9b5ad4d8b864e948d4bd950bf05 is a merge but no -m option was given.
fatal: 还原失败

Revert vs Reset

  1. reset是在正常的commit历史中,删除了指定的commit,这时 HEAD 是向后移动了,而 revert 是在正常的commit历史中再commit一次,只不过是反向提交,他的 HEAD 是一直向前的.
  2. git revert是用一次新的commit来回滚之前的commitgit reset是直接删除指定的commit

Revert the revert

听着这个标题,就感觉很有意思!


参考文档:

  1. How to revert a merge commit in Git