Git

Git Undo Merge Example

In the previous example, we have talked about Git Merge Conflict Example. Merge process sometimes can be automatized or can required human interaction and when this happens, few times, problems come around. In this topic, we shall cover about how to unmerge a branch taking advantage of Git’s power.

What exactly is undo merge? Well, if merge is the process to join another branch into the current working branch then unmerge is the process to remove changes merged into the current working branch.
 
 
 

1. Why undo merge?

First, we have to put focus in our commits. In the real world, we work in a specific branch and this branch has a bunch of commits but each one must be atomic in order to ensure the application state with each one. Taking this into account, merge or unmerge should provide changes as a single operation.

We are not crazy if we want to undo a merge. There are some reasons to do this:

  1. Merge had mistakes. People in charge of this task, require communication with the team if there are conflicts. If each team member is working in his own branch, he can rebase his branch in order to keep updated and easily merged.
  2. Feature should be moved to the future. Have you been working very hard on new features and have not been included in the release? In the real world, it is possible. We can perform a merge with some new features but what about if bugs appears on production? we need to undo the merge and fix the problem as soon as we can.

2. Undo merge

Imagine the first scenario mentioned above. We have finished the merge and we can see that does not compile due to missing lines which were not included in the merge. In this scenario, we have 2 options: Add the missing line or do the merge again. Add the missing line sounds easy (includes a new commit) but remember that every change in the application must be atomic. If we do this then we will add another commit or maybe we will amend the merge commit. But, in order to keep our history clean we should perform the the merge again.

In this example, we are going to use an spring-boot application. The current status of the application is the image below, two branches (master and new-feature)

git-undo-merge-example

  1. We will proceed with merge. First, make sure we are at master branch.
    git merge new-feature
    
  2. Merge has finished but with one error in src/main/java/com/javacodegeeks/examples/PhoneTypesController.java.
    M  pom.xml
    M  src/main/java/com/javacodegeeks/examples/Application.java
    A  src/main/java/com/javacodegeeks/examples/PhoneType.java
    A  src/main/java/com/javacodegeeks/examples/PhoneTypeRepository.java
    UU src/main/java/com/javacodegeeks/examples/PhoneTypesController.java
    
  3. We are going to proceed resolving conflicts but accidentally we will make a mistake during merge. We will keep changes from HEAD.
    package com.javacodegeeks.examples;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Arrays;
    import java.util.List;
    
    @RestController
    @RequestMapping("/phonetypes")
    public class PhoneTypesController {
    
    <<<<<<< HEAD
            @RequestMapping(value = "/phonetypes", method = RequestMethod.GET)
            public List get() {
                    return Arrays.asList("home", "mobile", "phone");
    =======
            @Autowired
            private PhoneTypeRepository repository;
    
            @RequestMapping(method = RequestMethod.GET)
            public List get() {
                    return this.repository.findAll();
    >>>>>>> new-feature
            }
    
    }
    

    Our code should look like this:

    package com.javacodegeeks.examples;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Arrays;
    import java.util.List;
    
    @RestController
    @RequestMapping("/phonetypes")
    public class PhoneTypesController {
    
            @RequestMapping(value = "/phonetypes", method = RequestMethod.GET)
            public List get() {
                    return Arrays.asList("home", "mobile", "phone");
            }
    
    }
    

    Have you seem the error? We have added all the infrastructure for database but we are not using it.

    This merge does not accomplish our atomic commit rule. If we want to fix it we have to add another commit with the correct changes.

  4. After the merge check the git’s history using git log --oneline --decorate --graph.
    5332437 (HEAD -> master) Merge branch 'new-feature'
    eeec84f (new-feature) Add jpa integration
    3a32600 Add dummy data
    7f134f0 Add Controller
    9e463f7 Initial commit
    
  5. Now, we will proceed undoing merge. In this case, we will delete this merge from our master’s history due to is not atomic. To do that, we are going to use git reset command. We use --hard in order to delete all changes and 3a32600 which is the commit id where we want to stay.
    git reset --hard 3a32600
    
  6. Check the log again and we have returned to the prior state.
    3a32600 Add dummy data
    7f134f0 Add Controller
    9e463f7 Initial commit
    
  7. Now, we are going to perform merge again but a good one this time. Make sure the class looks like this:
    package com.javacodegeeks.examples;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.Arrays;
    import java.util.List;
    
    @RestController
    @RequestMapping("/phonetypes")
    public class PhoneTypesController {
    
            @Autowired
            private PhoneTypeRepository repository;
    
            @RequestMapping(method = RequestMethod.GET)
            public List get() {
                    return this.repository.findAll();
            }
    
    }
    
  8. But, what happen if we need to add a new item in the current list and remove our changes with database integration? At this time, our merge is ok because respect the atomic commit rule. So, there are no reason to delete it from the history. We will not perform another merge in the future to re-integrate changes from new-feature branch. In this case, we are going to revert changes using git revert command.
    git revert -m 1 HEAD
    
  9. Check logs one more time and now we will see a new commit with the message Revert “Merge branch ‘new-feature'”. In this case, our repository looks like in the commit id 3a32600.
    2fb51a5 (HEAD -> master) Revert "Merge branch 'new-feature'"
    16ddc15 Merge branch 'new-feature'
    12e7d4c (new-feature) Add jpa integration
    3a32600 Add dummy data
    7f134f0 Add Controller
    9e463f7 Initial commit
    
  10. Finally, suppose we have added some additional changes and it is time to include new-feature branch in master again. What happen if we try to do the merge again?
    git merge new-feature
    Already up-to-date.
    

    Merge was performed before and git does not allow us to do it again. To reintegrate with those changes we have to revert the commit reverted in the step 8.

    git revert 2fb51a5
    

    Check logs and review if everything is ok in your class.

    275068d (HEAD -> master) Revert "Revert "Merge branch 'new-feature'""
    2fb51a5 Revert "Merge branch 'new-feature'"
    16ddc15 Merge branch 'new-feature'
    12e7d4c (new-feature) Add jpa integration
    3a32600 Add dummy data
    7f134f0 Add Controller
    9e463f7 Initial commit
    

3. Download the Source Code

Download
You can download the full source code of this example here: GitUndoMergeExample

Eddu Melendez

Eddu is a Peruvian software engineer. He is interested in Java, Spring Framework and Mule ESB. He is also very enthusiastic to learn new stuff.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button