git revert/reset

前言

  你是否也曾遇到版本回退的困扰,是否害怕使用版本回退,每次当错误提交之后,就惊的一身冷汗。很早以前,我就是这样子的。

场景一

  提交了一个commit,发现修改了不该修改的内容,怎么办?在现有分支上修改完了之后再次提交?这样无疑是可以的,但是我们可以通过git revert命令优雅的解决这种问题。

提交一个commit

  我们在A分支上提交一个commit。

1
2
3
$ vim a.txt
$ git add .
$ git commit -m "增加a.txt文件"

revert最近一次commit

  这个时候,我们使用revert命令将这次commit给重置。

1
$ git revert HEAD

  revert命令实际上做的事情就是重新生成一个commit覆盖掉之前的那个commit。这个时候git仓库的commit记录是这样的。005

提交了多次commit才发现有问题

  如果commit之后,你并没有发现问题,同时你又提交了多个commit,突然发现之前的commit有问题怎么办呢。

1
2
3
4
5
6
7
8
9
10
11
12
$ vim a.txt
$ git add .
$ git commit -m "增加a.txt文件"
$ vim b.txt
$ git add .
$ git commit -m "增加b.txt文件"
$ vim c.txt
$ git add .
$ git commit -m "增加c.txt文件"
$ vim d.txt
$ git add .
$ git commit -m "增加d.txt文件"

  发现a.txt的那次commit是不需要的。这个时候我们找到commit的唯一标识,然后使用revert将其废弃掉。

1
2
3
$ git log

$ git revert be6afa6ee5

  be6afa6ee5就是a.txt文件对应的commit唯一标识。这个时候git仓库的commit记录是这样的。006

找不到parent

  有时候你在revert的时候会出现如下的问题。007
  这个问题产生的原因是你revert的这个commit它是从两个不同的分支merge后产生的。所以它的parent有两个,你在revert的时候它不知道该revert到哪一个parent,所以就报错了。
  这个时候你可以通过-m参数来指定你需要revert的parent。

1
$ git revert HEAD -m 1

  上面的命令就表示你需要revert那个执行merge命令的分支。

场景二

  一年以前,不是很懂git的我,每次版本上线之后都不会打入tag,也不会给每次上线的版本单独保存一个分支,所以就出现了这样的问题。当出现线上bug的时候,我需要找到上线的commit,然后将HEAD指向那个commit修改bug(当时的我是多么的智障啊,哈哈哈)。

版本上线后提交若干个commit

  这里我们提交若干个commit。

1
2
3
4
5
6
7
8
9
10
11
12
$ vim a.txt
$ git add .
$ git commit -m "增加a.txt文件"
$ vim b.txt
$ git add .
$ git commit -m "增加b.txt文件"
$ vim c.txt
$ git add .
$ git commit -m "增加c.txt文件"
$ vim d.txt
$ git add .
$ git commit -m "增加d.txt文件"

强制回退

  线上出现问题,因为没有tag,也没有具体分支对应发布版本。我就copy了一份代码,然后reset强制回退后修改bug(千万不要学我,一年前的我就是这么做的)。

1
2
3
$ git log

$ git reset --hard 01aa54f328

  这样就将HEAD强制指向了之前发包的commit。

误操作reset

  这尼玛就蛋疼了,你在开发过程中发现自己误操作使用了reset命令。卧槽,git log还没有之前的东西了,怎么办怎么办,大脑一片空白。不要慌不要慌,git还是有记录存在的。

1
$ git reflog

  在我们reset –hard之后使用git log命令来查看得到如下结果。008
  而我们使用git reflog命令来查看可以得到如下结果。009
  看到这里我们就知道该怎么做了,我们可以直接通过reset命令再将HEAD指向对应的commit。

1
$ git reset --hard f06e667

  这里千万不要用git reset –hard HEAD~1,因为你现在HEAD之前1个commit是init的那个commit。

无关联覆盖

  前段时间,朋友遇到这样的问题。他在使用hexo做静态博客的过程中,repo仓库地址填写错误,导致hexo d命令执行后将原来一个项目的所有文件都被覆盖掉了。
  其实解决是十分简单的,我们只需要强制覆盖掉远程仓库的代码就可以了。

1
$ git push origin -f master

  但是我想说的并不是这个,因为这是两个完全没有关联的commit历史,执行pull命令的时候会报错。我们如果要pull远程仓库的代码就需要通过如下的命令了。

1
git pull origin master --allow-unrelated-histories

还可以这么用

  比如你修改了若干个文件,但是你想将这些文件作为两次commit,而你又恰巧执行了git add .命令,这个时候该如何使用git reset命令呢?

1
2
3
4
5
6
7
$ vim a.txt
$ vim b.txt
$ git add .
$ git reset HEAD b.txt
$ git commit -m "修改a.txt文件"
$ git add .
$ git commit -m "修改b.txt文件"

  git reset命令添加–hard参数之后确实是一个很危险的命令,但是如果你只是使用git reset命令是并不危险的,因为它修改的仅仅是暂存区的内容,而不会修改到你工作目录的文件。   

  余生没那么长,不要一味的付出去惯那些得寸进尺的人,请忠于自己,活得像最初的模样!

本文标题:git revert/reset

文章作者:严方雄

发布时间:2018-04-27

最后更新:2018-09-13

原始链接:http://yanfangxiong.com/2018/04/27/git-revert-reset/

0%