Practical Guide to Resolving Git Merge Conflicts

Share

Have you ever wondered how developers solve conflicts and which tools will be using to tackle it? What happens if we can't continuously day-to-day tasks and catch the deadline on time because of the issue?

It feels like searching never end to look for the way fixing it, even if you had some solutions that bring it up from some posts on the Internet. In this tutorial, you'll learn fundamental knowledge of Git commands and how to resolve conflicts when merging code from other developers or branches. We'll specifically cover the following sections:

  • Most Common Git Commands
  • Push Local Repository to Remote Repository
  • Resolve Conflicts with IDE IntelliJ
  • Use Git Meld Tool
  • Conclusion

Prerequisites

  • Fundamental knowledge of Git commands
  • Git tool installed on your machine
  • Any suitable IDE of your choice to view your source code; I'll be using Visual Studio Code for this demonstration

I. Most Common Git Commands

To catch up with the usage of Git commands, we will have an example that will demonstrate how to implement Git commands and resolve conflicts. Before moving forward, you should prepare an available project and suitable IDE that uses for our demonstration.

For instance, if the local machine installed Intellij, then you can open the as below:

As you can see the screenshot, the project haven't been setup Git. Hence, the module Git will be hide temporarily out of top navigation menu. To activate Git module, be sure you've opening Enable Version Control Integration feature and select the Git option.

Press button OK was that means you are running the git init to setup local repository for this project. In Intellij, click to Git at bottom navigation menu at the right corner and then you can view all of things like branches, logs, HEAD, Local, Date,...

Notice that you didn't link to remote repository form any host of codebase like GitHub, GitLab or Bitbucket,... So, everything commands executed will affect in Local. Use the following command to create some branch as develop by default, and we will stay in that branch.

git checkout -b develop

Use git status to displays the state of the working directory and which files/folders are committed and stored in the staging area.

PS C:\Users\admin\Documents\flagtick> git status
On branch develop                                                           
                                                                            
No commits yet                                                              
                                                                            
Untracked files:                                                            
  (use "git add <file>..." to include in what will be committed)            
        .idea/                                                              
        LICENSE                                                             
        README-CIF.md                                                       
        README-precompiled-scripts.md                                       
        README.md                                                           
        all/                                                                
        archetype.properties                                                
        core/                                                               
        dispatcher.ams/                                                     
        dispatcher/                                                         
        it.tests/                                                           
        pom.xml                                                             
        ui.apps.structure/                                                  
        ui.apps/                                                            
        ui.config/                                                          
        ui.content/                                                         
        ui.frontend/                                                        
        ui.tests/                 

In reality, we won't commit all files/folder as above to staging area upon there are some build files generated from your local machine. That leads to conflicts are always happening on other machine once they use git pull or git fetch to update latest changes from remote repository.

For this, we will have .gitignore file that is important file to skip these files/folders that describe as above. Running the following command in your terminal to create .gitignore file, then open it with your preferred code editor.

 type NUL > .gitignore

In the .gitignore file, you will need to add all files, folders that need to skip once push to remote repository. Using the slash (/) at the beginning of the line if your .gitignore file was placed in the root folder.

Finally, we can check git status to view the result.

C:\Users\admin\Documents\flagtick>git status
On branch develop
No commits yet
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .gitignore
        LICENSE
        all/
        archetype.properties
        core/
        it.tests/
        pom.xml
        ui.apps.structure/
        ui.apps/
        ui.config/
nothing added to commit but untracked files present (use "git add" to track)
Note: If you have already committed it, run the following command git rm <files/folders>.

If we want to track how your project are changed in phase of development then need to review and read a history of everything that happens to a repository. Hence, use git log and git commit that would be best be of your choice to record these things.

git add .
git commit -m "Init project"
Note: The git add . command is used to all files/folders to staging area before commit command executed.

After that, use the git log or git reflog will help you get a review what did you add or modify in the repository.

C:\Users\admin\Documents\flagtick>git log
commit c8a713264450e4bbece8dfb0f56177cfd40f695d (HEAD -> develop)
Author: vuongluis <[email protected]>
Date:   Mon Jun 13 13:22:47 2022 +0700
    Init project
Note: Use the git reflog is a powerful feature that will help you recover lose code while delete commit, branch or reset HARD.

Upon a successful commit files/folders to the repository, the IDE Intellij also provides a lot of features in Git module and you can reference for tracking your activities and team in the project. For example, let have a look at develop branch:

II. Push Local Repository to Remote Repository

Many remote hosts are popular that use to manage, store source code like GitHub, GitLab and Bitbucket. So, the next step is to push local repository to remote repository through some tools as Git Bash, Command Prompt or Terminal by IntelliJ.

To follow along with the manipulation as below, be sure you're using GitHub and have own account on this site.

Once you logged in successfully, we will create a new repository which names aemflagtick and generated clone URL as below: 

https://github.com/flagtick/aemflagtick.git

To specify the branch for push, let us move to switch to that branch and use the following syntax:

git checkout develop
git remote add origin <clone URL>
git push origin develop

Upon a successful push source code, you should see a success message from your terminal that looks like the screenshots below:

C:\Users\admin\Documents\flagtick>git push origin develop
Enumerating objects: 637, done.
Counting objects: 100% (637/637), done.
Delta compression using up to 12 threads
Compressing objects: 100% (473/473), done.
Writing objects: 100% (637/637), 39.47 MiB | 3.63 MiB/s, done.
Total 637 (delta 147), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (147/147), done.
remote:
remote: Create a pull request for 'develop' on GitHub by visiting:
remote:      https://github.com/flagtick/aemflagtick/pull/new/develop
remote:
To https://github.com/flagtick/aemflagtick.git
 * [new branch]      develop -> develop

Now, you can access to GitHub page and switch to develop branch:

Next, we will need to modify any files from local and also remote repository. For instance, let us have a look at the SimpleServlet.java as below:

public class SimpleServlet extends SlingSafeMethodsServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(final SlingHttpServletRequest req,
            final SlingHttpServletResponse resp) throws ServletException, IOException {
        final Resource resource = req.getResource();
        resp.setContentType("text/plain");
        resp.setCharacterEncoding("UTF-8");
        resp.getWriter().write("Title = " + resource.getValueMap().get(JcrConstants.JCR_TITLE));
    }
}

In local repository, we will add setCharacterEncoding("UTF-8") to translate any Unicode character to a matching unique binary string, and can also translate the binary string back to a Unicode character.

C:\Users\admin\Documents\flagtick>git status
On branch develop
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   core/src/main/java/com/adobe/flagtick/core/servlets/SimpleServlet.java
no changes added to commit (use "git add" and/or "git commit -a")

Now, we will commit the file and add the message "Update Character Encoding".

git add "core/src/main/java/com/adobe/flagtick/core/servlets/SimpleServlet.java"
git commit -m "Update Character Encoding"

Once you have committed SimpleServlet.java, you should see a success message from your terminal that looks like this:

C:\Users\admin\Documents\flagtick>git commit -m "Update Character Encoding"
[develop e0f988c] Update Character Encoding
 1 file changed, 1 insertion(+)

With that done, it's time to open remote repository and assume that another developer update latest code for SimpleServlet.java class. Let update and commit the SimpleServlet.java as below:

public class SimpleServlet extends SlingSafeMethodsServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(final SlingHttpServletRequest req,
            final SlingHttpServletResponse resp) throws ServletException, IOException {
        final Resource resource = req.getResource();
        resp.setContentType("text/plain;charset=UTF-8");    
        resp.getWriter().write("Title = " + resource.getValueMap().get(JcrConstants.JCR_TITLE));
    }
}

Use the message for commit is "Optimize code for function doGet in SimpleServlet.java".

This way, you will be positive to create differences between local and remote repository at the same file. As you can see here, our updates for function doGet in SimpleServlet.java are different.

It basically means that conflicts will happen certainly. Thus, let run the following command as below:

PS C:\Users\admin\Documents\flagtick> git push origin develop
To https://github.com/flagtick/aemflagtick.git
 ! [rejected]        develop -> develop (fetch first)
error: failed to push some refs to 'https://github.com/flagtick/aemflagtick.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
PS C:\Users\admin\Documents\flagtick> 

As you can see here, the push action have been rejected by conflicts happening. To go for fixing it, we have a lot of ways for fixing it. Let's split into two ways, one is use IDE Intellij and another is use Git Meld tool.

III. Resolve Conflicts with IDE IntelliJ

In the context of our tutorial guideline, the IDE IntelliJ or another one that contains Git module will be further convenient for support how far the developer can tackle the issue regarding to conflicts.

As you can see above screenshot, we are going to click Push All up to Here... and execute push source code to branch develop.

To specify which files are getting conflicts with local repository, let us move to right click develop branch and select Pull into 'develop' using Merge as below:

After that, there is an popup dialog that will show warning files that has conflicts.

Here, there is only one file named SimpleServlet.java happening conflicts. Let now move to double click into the file.

There are three columns which name and order from left side to right side that is local, compare and remote. Thus, you need to ensure that remote and local repository are merged with the same content.

This is what we have finished after using some manipulations as Accept Left, Accept Right.

Finally, we will run the following command as below:

PS C:\Users\admin\Documents\flagtick> git push origin develop
Enumerating objects: 46, done.
Counting objects: 100% (46/46), done.
Delta compression using up to 12 threads
Compressing objects: 100% (14/14), done.
Writing objects: 100% (24/24), 1.72 KiB | 440.00 KiB/s, done.
Total 24 (delta 6), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (6/6), completed with 3 local objects.
To https://github.com/flagtick/aemflagtick.git
   2ecb7ca..aea7c64  develop -> develop

Now, go to the remote repository, we will have a commit message generated as 'HEAD@{0}: commit (merge): Merge remote-tracking branch 'origin/develop' into develop'.

IV. Use Git Meld Tool

Meld is a visual diff and merge tool targeted at developers. Meld helps you compare files, directories, and version controlled projects. Thus, we encourage you should download and install to get the way of passing conflicts when merging code from developers.

Visit the page https://meldmerge.org/ and select package will be suitable for your operating system.

Sometimes, there will be some problems that relates to git mergetool command when execution, be sure you're following this step to add Meld tool to path environment variable in Windows 10.

Upon a successful install to Git Meld tool, we will repeat these above steps to create different in SimpleServlet.java with both of side: Local and Remote.

After install Git Meld tool, we also replace meld.tool default of Git and indicate Meld tool - default tool:

git config --global merge.tool meld
git config --global mergetool.meld.path "C:\Program Files (x86)\Meld\Meld.exe"&nbsp;

+ Local

@Override
protected void doGet(final SlingHttpServletRequest req,
        final SlingHttpServletResponse resp) throws ServletException, IOException {
    final Resource resource = req.getResource();
    resp.setContentType("text/plain");
    resp.setCharacterEncoding("UTF-8");
    resp.getWriter().write("Title = " + resource.getValueMap().get(JcrConstants.JCR_TITLE));
}

+ Remote

@Override
protected void doGet(final SlingHttpServletRequest req,
    final SlingHttpServletResponse resp) throws ServletException, IOException {
    final Resource resource = req.getResource();
    resp.setContentType("text/plain;charset=UTF-8");
    resp.getWriter().write("Title = " + resource.getValueMap().get(JcrConstants.JCR_TITLE));
}

Next, navigate into your project folder. In the Terminal of IntelliJ or Command Prompt, we will need to pull develop branch again and specify which file has conflict.

PS C:\Users\admin\Documents\flagtick> git pull origin develop
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 12 (delta 3), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (12/12), 1.18 KiB | 43.00 KiB/s, done.
From https://github.com/flagtick/aemflagtick
 * branch            develop    -> FETCH_HEAD
   aea7c64..9942905  develop    -> origin/develop
Auto-merging core/src/main/java/com/adobe/flagtick/core/servlets/SimpleServlet.java
CONFLICT (content): Merge conflict in core/src/main/java/com/adobe/flagtick/core/servlets/SimpleServlet.java
Automatic merge failed; fix conflicts and then commit the result.

Now, let open the git meld tool with following command:

git mergetool

This is visual user interface for Git Meld when opening.

You can press arrow left and arrow right to merge SimpleServelt.java between local and remote repository.

Once you have finished the manipulation, you should close the window and notice that you should uncheck SimpleServlet_LOCAL and SimpleServlet_REMOTE to avoid generated files that not be necessary.

Note: You should sure that SimpleServlet.java will be modify after end of the manipulation. As you can see the screenshot above, it doesn't work after you finish.

Now, we will run the following command to push code from local repository to remote repository.

PS C:\Users\admin\Documents\flagtick> git add .
PS C:\Users\admin\Documents\flagtick> git commit -m "[] (Lorence) resolve conflicts"
[develop c025ad6] [] (Lorence) resolve conflicts
PS C:\Users\admin\Documents\flagtick> git push origin develop
Enumerating objects: 35, done.
Counting objects: 100% (35/35), done.
Delta compression using up to 12 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (13/13), 1023 bytes | 511.00 KiB/s, done.
Total 13 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/flagtick/aemflagtick.git
   9942905..c025ad6  develop -> develop

V. Conclusion

The article mainly presented how to use fundamental knowledge of Git commands and seek to resolve conflicts in software development process. For Git Meld tool, it is useful and visualize more than meld tool from IDE IntelliJ. If you encounter any problem while referring to our post, please leave a comment below to support you.

Vuong Nguyen
Vuong Nguyen The individual is sociable and enjoys making friends, often sharing knowledge across various fields. |1 second ago
Vuong Nguyen The individual is sociable and enjoys making friends, often sharing knowledge across various fields. 1 second ago
You need to login to do this manipulation!