今天恰巧遇到了须要回退分支的问题,我以前一直在用的都是git reset
,自认为清楚明了,也就没去看还有其余的回退方法。今天突然被问到,特地查了查。git
develop ----1 3-----
\ /
branch a a
复制代码
develop将a分支合并后,想要不留痕迹的撤回合并。这个时候用git reset
就是很好的选择了。github
具体的操做步骤以下:缓存
例如个人日志是这样的:bash
commit 3
Merge 1 2
Author: admin <admin@163.com>
Date: Wed May 30 15:00:00 2018 +0800
Merge branch 'feature/a' into 'develop'
close a
See merge request !20
commit 2
Author: admin <admin@163.com>
Date: Wed May 30 14:00:00 2018 +0800
close a
commit 1
Author: admin <admin@163.com>
Date: Wed May 30 13:00:00 2018 +0800
init project
复制代码
我要将develop回退到合并以前的状态,那就是退到 commit 1这了,将commit号复制下来。退出编辑界面。服务器
--soft 回退后a分支修改的代码被保留并标记为add的状态(git status 是绿色的状态)
--mixed 重置索引,但不重置工做树,更改后的文件标记为未提交(add)的状态。默认操做。
--hard 重置索引和工做树,而且a分支修改的全部文件和中间的提交,没提交的代码都被丢弃了。
--merge 和--hard相似,只不过若是在执行reset命令以前你有改动一些文件而且未提交,merge会保留你的这些修改,hard则不会。【注:若是你的这些修改add过或commit过,merge和hard都将删除你的提交】
--keep 和--hard相似,执行reset以前改动文件若是是a分支修改了的,会提示你修改了相同的文件,不能合并。若是不是a分支修改的文件,会移除缓存区。git status仍是能够看到保持了这些修改。
复制代码
a分支的代码我不须要了,之后应该也不须要了。所以:测试
git reset 1(粘贴过来的commit号) --hard
spa
a分支代码我仍是想要的,只是这个提交我不想要了: git reset 1
日志
git log
查看一下:commit 1
Author: admin <admin@163.com>
Date: Wed May 30 13:00:00 2018 +0800
init project
复制代码
是我想要的没错了,能够push到远端去了。(这一步很危险,必定要确认好reset的结果确实是你想要的结果,不然,丢失了代码就不要怨我了)code
git push origin develop
索引
![rejected] develop -> develop (non-fast-forward)
error: 没法推送一些引用到 'git@github.cn:...'
提示:更新被拒绝,由于您当前分支的最新提交落后于其对应的远程分支。
。。。
复制代码
好吧,个人分支确实落后于远程的develop分支。我须要--force
。
git push origin develop --force
Total 0 (delta 0), reused 0 (delta 0)
To git@...
+ 83***...23***** develop -> develop (forced update)
复制代码
能够了,回到github查看network。嗯,就是想要这样的。
仍是这个例子
develop ----1 3-----
\ /
branch a a
复制代码
仍是以前的需求,不想要合并a,只想要没合并a时的样子。
操做步骤:
git checkout develop
git log
,仍是上面的日志:commit 3
Merge 1 2
Author: admin <admin@163.com>
Date: Wed May 30 15:00:00 2018 +0800
Merge branch 'feature/a' into 'develop'
close a
See merge request !20
commit 2
Author: admin <admin@163.com>
Date: Wed May 30 14:00:00 2018 +0800
close a
commit 1
Author: admin <admin@163.com>
Date: Wed May 30 13:00:00 2018 +0800
init project
复制代码
此次和git reset
不一样的是我不能复制 commit 1
这个commit号了,我须要复制的是commit 2
的commit号。由于revert后面跟的是具体须要哪一个已经合并了的分支,而并非须要会退到哪的commit号。
git revert 2
Revert "close a"
This reverts commit 2
#.......
复制代码
这是至关于又新增了一个commit,把a分支上的全部修改又改了回去。
git log
查看一下是否是我想的那样
commit 4
Author: admin <admin@163.com>
Date: Wed May 30 17:00:00 2018 +0800
Revert "close a"
This reverts commit 2
commit 3
Merge 1 2
Author: admin <admin@163.com>
Date: Wed May 30 15:00:00 2018 +0800
Merge branch 'feature/a' into 'develop'
close a
See merge request !20
commit 2
....
复制代码
确实是新增长了一个commit,查看代码发现a分支的修改都不存在了,也达到了我想要的效果。
git push origin develop
查看network,是这样的:
develop ----1 3-----revert a------
\ /
branch a a
复制代码
如此看来,git reset
和git revert
都能实现我如今的需求,那这两个到底有什么区别呢,在网上查了这个问题,我以为说的有些抽象,看的不是很明白,因而本身实践了以后才明白。
git revert是用一次新的commit来回滚以前的commit,git reset是直接删除指定的commit。
这个很好理解,在刚才的操做中咱们看日志已经能够看到这个现象。
git reset
操做以后,咱们查看上面例子的network已经能够看到network中只有commit 1
,分支a
和合并分支后的commit 3
都消失了;
git revert
操做以后,network中仍是能够看到a分支和合并a分支的操做,只不过在其基础上又增长了一个revert的commit而已。
git reset 是把HEAD向后移动了一下,而git revert是HEAD继续前进,只是新的commit的内容和要revert的内容正好相反,可以抵消要被revert的内容。
这个也是能够清晰明了的看到,我就不作过多的解释了
在回滚这一操做上看,效果差很少。可是在往后继续merge之前的老版本时有区别。由于git revert是用一次逆向的commit“中和”以前的提交,所以往后合并老的branch时,致使这部分改变不会再次出现,可是git reset是之间把某些commit在某个branch上删除,于是和老的branch再次merge时,这些被回滚的commit应该还会被引入。
如今的需求是我以前已经把a分支revert了,可是我如今又须要a分支的代码了,我以前都写过一遍总不能再从新写一遍了。我首先想到的方法,把a分支再merge到develop不就行了。
git merge a
复制代码
结果
Already up-to-date
复制代码
啥?由于咱们以前提交合并的a分支的代码还在,所以咱们并不能在从新合并a分支。
解决办法:使用revert以前revert的commit号。在上面的例子中就是git revert 4
。因而又新增了一个commit,把以前revert的代码又从新revert回来了。具体参考
依旧是上面的需求。
develop -----1-----4-------5------6
\ / \ / \ /
feature b c d
复制代码
如今我将develop reset到commit 4这里,继续提交我之后的代码
develop -----1-----4-------7------8
\ / \\ /
feature b \ e
\------5----d
\-c-/
复制代码
我如今想从新合并d分支的代码
develop -----1-----4-------7------8------9
\ / \\ / /
feature b \ e /
\------5----d/
\-c-/
复制代码
合并过来大概是这个样子的。也就是说d分支以前已经合并过c分支,所以若是还想要合并d分支的话,c分支的代码就会同步的带过来。
讲到这里大部分经常使用的应用场景也就应该是比较清晰的了。
git revert
就再好不过了; 若是分支我就是提错了没用了还不想让别人发现我错的代码,那就git reset
吧git revert b分支commit号
,这样c和d的代码依然还在。我能想到的大概就是这些了,固然在具体项目上咱们会遇到不少没遇到过的情形。个人建议是不要盲目的查找相似问题后就去修改,由于他的问题并不必定就等同于你的问题。我建议去建立测试的分支,等真正整明白了,再去整线上的分支也不迟。
第一次写了这么详细的一篇文章,主要也是由于网上查到的知识,对git知识体系通常的人来讲,看的比较费解。