Undoing Merges
I would like to start writing more here about general Git tips, tricks and upcoming features. There has actually been a lot of cool stuff that has happened since the book was first published, and a number of interesting things that I didn't get around to covering in the book. I figure if I start blogging about the more interesting stuff, it should serve as a pretty handy guide should I ever start writing a second edition.
For the first such post, I'm going to cover a topic that was asked about at a training I did recently. The question was about a workflow where long running branches are merged occasionally, much like the Large Merging workflow that I describe in the book. They asked how to unmerge a branch, either permenantly or allowing you to merge it in later.
You can actually do this a number of ways. Let's say you have history that looks something like this:
You have a couple of topic branches that you have developed and then integrated together by a series of merges. Now you want to revert something back in the history, say 'C10' in this case.
The first way to solve the problem could be to rewind 'master' back to C3 and then merge the remaining two lines back in again. This requires that anyone you're collaborating with knows how to handle rewound heads, but if that's not an issue, this is a perfectly viable solution. This is basically how the 'pu' branch is handled in the Git project itself.
$ git checkout master
$ git reset --hard [sha_of_C3]
$ git merge jk/post-checkout
$ git merge db/push-cleanup
Once you rewind and remerge, you'll instead have a history that looks more like this:
Now you can go back and work on that newly unmerged line and merge it again at a later point, or perhaps ignore it entirely.
Reverting a Merge
However, what if you didn't find this out until later, or perhaps you or one of your collaborators have done work after this merge series? What if your history looks more like this:
Now you either have to revert one of the merges, or go back, remerge and then cherry-pick the remaining changes again (C10 and C11 in this case), which is confusing and difficult, especially if there are a lot of commits after those merges.
Well, it turns out that Git is actually pretty good at reverting an entire merge. Although you've probably only used the git revert
command to revert a single commit (if you've used it at all), you can also use it to revert merge commits.
All you have to do is specify the merge commit you want to revert and the parent line you want to keep. Let's say that we want to revert the merge of the jk/post-checkout
line. We can do so like this:
$ git revert -m 1 [sha_of_C9]
Finished one revert.
[master 88edd6d] Revert "Merge branch 'jk/post-checkout'"
1 files changed, 0 insertions(+), 2 deletions(-)
That will introduce a new commit that undoes the changes introduced by merging in the branch in the first place - sort of like a reverse cherry pick of all of the commits that were unique to that branch. Pretty cool.
However, we're not done.
Reverting the Revert
Let's say now that you want to re-merge that work again. If you try to merge it again, Git will see that the commits on that branch are in the history and will assume that you are mistakenly trying to merge something you already have.
$ git merge jk/post-checkout
Already up-to-date.
Oops - it did nothing at all. Even more confusing is if you went back and committed on that branch and then tried to merge it in, it would only introduce the changes since you originally merged.
Gah. Now that's really a strange state and is likely to cause a bunch of conflicts or confusing errors. What you want to do instead is revert the revert of the merge:
$ git revert 88edd6d
Finished one revert.
[master 268e243] Revert "Revert "Merge branch 'jk/post-checkout'""
1 files changed, 2 insertions(+), 0 deletions(-)
Cool, so now we've basically reintroduced everything that was in the branch that we had reverted out before. Now if we have more work on that branch in the meantime, we can just re-merge it.
$ git merge jk/post-checkout
Auto-merging test.txt
Merge made by recursive.
test.txt | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
So, I hope that's helpful. This can be particularly useful if you have a merge-heavy development process. In fact, if you work mostly in topic branches before merging for integration purposes, you may want to use the git merge --no-ff
option so that the first merge is not a fast forward and can be reverted out in this manner.
Until next time.
https://git-scm.com/blog/2010/03/02/undoing-merges.html
git 撤销 merging,git取消merge
$ git pull origin test
// git pull合并代码的时候,若发生冲突,会处于merging状态,检查代码,发现自己的分支低于主分支,这个时候想撤销merge
// 撤销merge
$ git reset --hard HEAD (or sha_1)
-
用git提交代码时 冲突了
于是分支名变成如下图所示
在命令行输入:
git reset --hard head 就可以了
但是在这个过程中 可能会碰到一个问题,如下图:
这个意思是在C:\Users\Admin\git\phhhh\.git目录下已经有一个index.lock文件夹存在了,只需要去这个目录下删了这个文件夹,然后再输入 git reset --hard head 就ok了
Undoing Merges的更多相关文章
- git push 报错:you are not allowed to upload merges
git rebase Cannot rebase: You have unstaged changes. git stash # 每次 push 前 git pull --rebase git pus ...
- Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty messa
1.git提交的时候遇到: # Please enter the commit message for your changes. Lines starting with '#' will be ig ...
- Devexpress VCL Build v2014 vol 15.2.3 发布
2016年第一个版本,继续修补. New Major Features in 15.2 What's New in VCL Products 15.2 Breaking Changes To lear ...
- TortoiseSVN中图标的含义
今天在使用svn时发现有好多不认识了,所以查了下svn帮助手册.借此总结了下 svn 中图标的含义 一个新检出的工作复本使用绿色的勾做重载.表示Subversion状态 正常. 在开始编辑一个文件后, ...
- Bash,Vim,gdb&git常用命令
Bash 目录 pwd //查看当前目录 mkdir dir1 dir2 //创建目录 tree dir1 mv test1.cpp test2.cpp dir1 dir //移动文件/目录到目 ...
- Pro Git - 笔记2
Git Basics Getting a Git Repository Initializing a Repository in an Existing Directory For Linux: $ ...
- TortoiseSVN 日常操作指南
TortoiseSVN A Subversion client for Windows Stefan Küng Lübbe Onken Simon Large 2005/01/17 19:09:21 ...
- InnoDB关键特性学习笔记
插入缓存 Insert Buffer Insert Buffer是InnoDB存储引擎关键特性中最令人激动与兴奋的一个功能.不过这个名字可能会让人认为插入缓冲是缓冲池中的一个组成部分.其实不然,Inn ...
- 自己写jquery插件之模版插件高级篇(一)
需求场景 最近项目改版中,发现很多地方有这样一个操作(见下图gif动画演示),很多地方都有用到.这里不讨论它的用户体验怎么样. 仅仅是从复用的角度,如果每个页面都去写text和select元素,两个b ...
随机推荐
- LDA实现
topic model本质上就一个套路,在doc-word user-url user-doc等关系中增加topic层,扩充为2层结构,一方面可以降维,另一方面挖掘深层次的关系,用户doc word ...
- OpenCV 直线检测
/*------------------------------------------------------------------------------------------*\ This ...
- Linux进程管理(第二版) --进程管理命令
进程管理命令 一.查看用户信息.5.15 分钟内的系统的,优先值越小,优先权越大 ] 1.nice 指定程序运行的优先级 格式 nice -n command 例如 nice -5 myprogrem ...
- iOS和OS X中的bundle
bundle也可以称之为包(package). 它在iOS和OS X中实际为一个文件夹但却当成单独的文件来对待. 每一个app都有一个bundle,并且你可以通过在xxx.app图标上右击鼠标然后选择 ...
- ubuntu下搭建gtk+编程环境
首先gtk+项目主页为: http://www.gtk.org/ gtk+现在有2和3两种版本,使用 sudo apt-get install gnome-core-devel 可以一次性安装2个版本 ...
- java的finalize方法使用
1. finalize的作用 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize()与C++中的析构函数 ...
- Python 3 中的json模块使用
1. 概述 JSON (JavaScript Object Notation)是一种使用广泛的轻量数据格式. Python标准库中的json模块提供了JSON数据的处理功能. Python中一种非常常 ...
- dom4j 解析 xml标签属性
重写onEnd()和onStart()方法 public class XmlElementHandler implements ElementHandler { @Override public vo ...
- volatile的适用场景
volatile保证线程间的数据是可见的(共享的),但不保证数据同步 volatile相当于synchronized的弱实现,也就是说volatile实现了类似synchronized的语义,却又没有 ...
- 利用LinkedHashMap实现简单的缓存
update1:第二个实现,读操作不必要采用独占锁,缓存显然是读多于写,读的时候一开始用独占锁是考虑到要递增计数和更新时间戳要加锁,不过这两个变量都是采用原子变量,因此也不必采用独占锁,修改为读写锁. ...