Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you undo changes committed to main line from a feature branch but keep the branch up to date?

Tags:

git

From time to time we can run across issues where we commit a feature branch to our baseline and discover in some situations it can go horribly wrong, so the change needs to be reverted, without losing all the other commits done since then. However, someone needs to continue working on the original branch.

I don't want to use git rebase on the main line to change history (because that'd cause all sorts of issues all by itself), but when I do git revert on the main line then as soon as git merge is run on the branch, to pick up any other changes done to the system, then all the work done disappears.

What can I do to keep the changes on the branch intact?

like image 553
Tom Tanner Avatar asked Jul 23 '13 09:07

Tom Tanner


People also ask

How do I undo a commit in mainline?

Steps to revert a Git commitLocate the ID of the commit to revert with the git log or reflog command. Issue the git revert command and provide the commit ID of interest. Supply a meaningful Git commit message to describe why the revert was needed.


2 Answers

I assume you don't want to do any rebases and resets, this is merge-only approach.

Suppose you have two branches master and feature. So, you've decided merge the feature into master:

$ git merge feature

Now, you have all your feature changes on the master. I assume the most difficult scenario - there are commits made after the merge on both branches. But, suddenly you see that nothing works of feature, all is broken and decide to revert it. Your history is (you could see it with git log --graph feature master):

* commit 838f29fda2333bdbfc0d1be44d2387e6119dc4e8
| 
|     f3
|    
| * commit 58d1e3f0e032cc77d4ab2bbf0bdfe6407b96b7e6
| | 
| |     m3
| |     
| *   commit afb600fe382befe095f9b8a6e9eef98be25c929b
| |\  Merge: 5cddc52 8660a59
| |/  
|/|   
| |       Merge branch 'feature'
| |   
* | commit 8660a59eeb13f9b3447846ba6977140f7c86c7a4
| | 
| |     f2
| |   
* | commit 6f76e2288d69808b97981340198fd8044ab47630
| | 
| |     f1
| |   
| * commit 5cddc528de424a01d1d18552ddea93435618e2f7
| | 
| |     m2
| |   
| * commit fa6ebb76f9f0308f7dcd1148503534668fa15358
|/  
|   
|       m1
|  
* commit 4e3aa05d6f46eb14bbbc253a42325e9a53a3393e

Notice the commits f3 and m3 which have been done after merge. So, you need carefully delete only changes from feature appeared in the master.

To do it you could revert the merge commit on the master, keeping master's base (the parameter -m1). To achieve it I create a new branch based on the merge point and revert in it:

$ git checkout -b feature-revert afb600fe
$ git revert -m1 HEAD

Now, we have a reverted changes on the branch feature-revert. Now it is simple just put it into master by merging:

$ git checkout master
$ git merge feature-revert

So, at the moment the master doesn't have anything from the feature. However, if later you want to re-merge the feature, all reverted changes will be lost in master, as they were merged and reverted.

To solve the issue you should revert the revert (he-he) and merge it back to the feature:

$ git checkout feature-revert
$ git revert HEAD
$ git checkout feature
$ git merge feature-revert

I suppose we don't need the branch anymore, as we merged it already, but you could keep it if you want:

$ git branch -d feature-revert

You should be aware, that merging it back brings all changes from master into feature which usually normal workflow.

Now, after fixes made in feature you could merge it again into master as usual anytime.

like image 178
kan Avatar answered Oct 01 '22 18:10

kan


When you git revert your changes, it creates a new commit, whose tree doesn't have those changes.

The changes aren't removed though, their original commits still exist.

So, just:

  • git revert your merge commit on master (remember to select the correct parent). Now master doesn't have the broken code introduced from your feature branch
  • fix the feature branch
  • revert the first revert on master. This will re-introduce the broken state of the feature as you merged it originally
  • merge the feature-branch fixes over

See here (or the same file in your local git docs if installed) for more details.

You history ends up looking like:

 --- a -- ... -- Mi ... ~Mi ... ~~Mi -- Mx  [master]
      \         /                      /
       f1 ... fi -- fj ........ x -- fx     [feature]

where Mi is your original merge from the feature branch, ~Mi is the reversion when you noticed the problem, fj .. fx are subsequent fixes to the feature branch, ~~Mi is the reversion of ~Mi, etc.

like image 41
Useless Avatar answered Oct 01 '22 19:10

Useless