Categories: ProgrammingTutorials

Searching and Resolving Conflicts

11 min read

This article, by Eric Pidoux, author of Git Best Practices Guide, covers a part of Git that you will definitely meet: conflicts. How can we resolve them?

(For more resources related to this topic, see here.)

While working together as a team on a project, you will work on the same files. The pull command won’t work because there are conflicts, and you might have tried some Git commands and things got bad. In this chapter, we will find solutions to these conflicts and see how we can fix them. We will cover the following topics:

  • Finding content inside your Git repository
  • Stashing your changes
  • Fixing errors by practical examples

Finding content inside your repository

Sometimes, you will need to find something inside all your files. You can, of course, find it with the search feature of your OS, but Git already knows all your files.

Searching file content

To search text inside your files, simply use the following command:

Erik@server:~$ git grep "Something to find"
Erik@server:~$ git grep -n body
Master:Website.Index.html:4:       <bodyMaster:Website.Index.html:12:       </body>

It will display every match to the given keyword inside your code. All lines use the [commitref]:[filepath]:[linenumber]:[matchingcontent] pattern.

Notice that [commitref] isn’t displayed on all Git versions.

You can also specify the commit references that grep will use to search the keyword:

Erik@server:~$ git grep -n body d32lf56 p88e03d HEAD~3
Master:Website.Index.html:4:       <body>
Master:Website.Index.html:12:       </body>

In this case, grep will look into the d32lf56, p88e03d, and third commit starting by the head pointer.

Your repository has to be encoded in UTF-8; otherwise, the grep command won’t work.

Git allows you to use regex inside the search feature by replacing somethingToFind with a regex.

You can use the logical operators (or and and), as shown in the following command:

Erik@server:~$ git grep -e myRegex1 --or -e myRegex2
Erik@server:~$ git grep -e myRegex1 --and -e myRegex2

Let’s see this with an example. We only have a test.html page inside our last commit, and we want to find whether or not there is a word with an uppercase alphabetic value and numeric values:

Erik@server:~$ git grep -e [A-Z] --and -e [0-9] HEAD
Master:Website.Test.html:6:       TEST01

With the grep command, you can delve deeper, but it’s not necessary to discuss this topic here because you won’t use it every day!

Showing the current status

The git status command is helpful if you have to analyze your repository:

Erik@server:~$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits
# (use "git push" to publish your local commits)
# Changes not staged for commit:
#   (use "git add<file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   myFile1
# modified:   myFile2
#
# Untracked files:
#   (use "git add<file>..." to include in what will be committed)
#
# newFile.txt
no changes added to commit (use "git add" and/or "git commit -a")

Git analyzes the local repository in comparison to the remote repository. In this case, you have to add newFile.txt, commit myFile1 and myFile2, and push them to the remote repository.

Exploring the repository history

The best way to explore the past commits inside your repository is to use the git log command. For this part, we will assume that there are only two commits.

To display all commits, use the following commands:

Erik@server:~$ git log --all 
Commit xxxxxxxxxxx
Author: Jim <jim@mail.com>
Date: Sun Jul 20 15:10:12 2014 -0300
Fix front bugs on banner
 
Commit xxxxxxxxxxx
Author: Erik <erik@mail.com>
Date: Sat Jul 19 07:06:14 2014 -0300
Add the crop feature on website backend

This is probably not what you want. After several days of work, you will have plenty of these commits, so how will you filter it?

The power of the git log command is that you can quickly find anything in all commits.

Let’s go for a quick overview of what Git is able to find. We will start by finding the last commit:

Erik@server:~$ git log -1
Commit xxxxxxxxxxx
Author: Jim <jim@mail.com>
Date: Sun Jul 20 15:10:12 2014 -0300
Fix front bugs on banner

The number after the git log command indicates that it is the first commit from Head.

Too easy! Let’s try to find what the last commit of Erik is:

Erik@server:~$ git log --author=Erik -1
Commit xxxxxxxxxxx
Author: Erik <erik@mail.com>
Date: Sat Jul 19 07:06:14 2014 -0300
Add the crop feature on website backend

Now, let’s find it between two dates:

Erik@server:~$ git log --author=Erik --before "2014-07-20" --after "2014-07-18"
Commit xxxxxxxxxxx
Author: Erik <erik@mail.com>
Date: Sat Jul 19 07:06:14 2014 -0300
Add the crop feature on website backend

As I told you earlier, there are a lot of parameters to the git log command. You can see all of them using the git help log command.

The stat parameter is really useful:

Erik@server:~$ git log --author=Jim --stat 
Commit xxxxxxxxxxx
Author: Jim <jim@mail.com>
Date: Sun Jul 20 15:10:12 2014 -0300
Fix front bugs on banner
 
index.php | 1 +
     1 file changed, 1 insertion(+)

This parameter allows you to view a summary of the changes made in each commit. If you want to see the full changes, try the -p parameter.

Remember that the git log command has a file parameter to restrict the search to the git log [file] file.

Viewing changes

There are two ways to see changes in a repository: git diff and git show.

The git diff command lets you see the changes that are not committed. For example, we have an index.phpfile and replace the file content by a line. Just before the lines, you will see a plus (+) or minus () sign. The + sign means that content was added and the sign denotes that it was removed:

Erik@server:~$ git diff
diff --git a/index.php b/index.php
indexb4d22ea..748ebb2 100644
--- a/index.php
+++ b/index.php
@@ -1,11 +1 @@
-<html>
-
-<head>
-<title>Git is great!</title>
-</head>
-<body>
-<?php
- echo 'Git is great';
-?>
-</body>
-</html>
+<b> I added a line</b>

If you want to analyze a commit, I suggest you to use the git show command. It will display the full list of changes of the commit:

Erik@server:~$ git show commitId

There is a way to do the opposite, that is, to display commits for a file with git blame:

Erik@server:~$ git blameindex.php
e4bac680 (Erik 2014-07-20 19:00:47 +0200 1) <b> I added a line</b>

Cleaning your mistakes

The first thing to know is that you can always clean your mistake with Git. Sometimes this will be hard or painful for your code, but you can do it!

Let’s start this section with how to remove untracked files:

Erik@server:~$ git clean -n

The –n option will make a dry-run (it’s always important to see what will happen before you regret it).

If you want to also remove directories and hidden files, use this one:

Erik@server:~$ git clean -fdx

With these options, you will delete new directories (-d) and hidden files (-x) and be able to force them (-f).

The git reset command

The git reset command will allow you to go back to a previous state (for example, commit). The git reset command has three options (soft, hard, or mixed, by default).

In general, the git reset command’s aim is to take the current branch, reset it to point somewhere else, and possibly bring the index and work tree along. More concretely, if the master branch (currently checked out) looks like the first row (in the following figure) and you want it to point to B and not C, you will use this command:

Erik@server:~$ git reset B

The following diagram shows exactly what happened with the previous command. The HEAD pointer was reset from C to B:

The following table explains what the options really move:

Option

Head pointer

Working tree

Staging area

Soft

Yes

No

No

Mixed

Yes

No

Yes

Hard

Yes

Yes

Yes

The three options that you can provide on the reset command can be easily explained:

  • –hard: This option is the simplest. It will restore the content to the given commit. All the local changes will be erased. The git reset –hard command means git reset –hard HEAD, which will reset your files to the previous version and erase your local changes.
  • –mixed: This option resets the index, but not the work tree. It will reset your local files, but the differences found during the process will be marked as local modifications if you analyze them using git status. It’s very helpful if you make some bugs on previous commits and want to keep your local changes.
  • –soft: This option will keep all your files, such as mixed, intact. If you use git status, it will appear as changes to commit. You can use this option when you have not committed files as expected, but your work is correct. So you just have to recommit it the way you want.

The git reset command doesn’t remove untracked files; use git clean instead.

Canceling a commit

The git revert command allows you to “cancel” your last unpushed commit. I used quotes around cancel because Git doesn’t drop the commit; it creates a new commit that executes the opposite of your commit. A pushed commit is irreversible, so you cannot change it.

Firstly, let’s have a look at the last commits:

Erik@server:~$ git log
commite4bac680c5818c70ced1205cfc46545d48ae687e
Author: Eric Pidoux
Date:   Sun Jul 20 19:00:47 2014 +0200
replace all
commit0335a5f13b937e8367eff35d78c259cf2c4d10f7
Author: Eric Pidoux
Date:   Sun Jul 20 18:23:06 2014 +0200
commitindex.php

We want to cancel the 0335… commit:

Erik@server:~$ git revert 0335a5f13

Canceling this commit isn’t necessary to enter the full commit ID, but just the first characters. Git will find it, but you will have to enter at least six characters to be sure that there isn’t another commit that starts with the same characters.

Solving merge conflicts

When you are working with several branches, a conflict will probably occur while merging them. It appears if two commits from different branches modify the same content and Git isn’t able to merge them.

If it occurs, Git will mark the conflict and you have to resolve it.

For example, Jim modified the index.html file on a feature branch and Erik has to edit it on another branch. When Erik merges the two branches, the conflict occurs.

Git will tell you to edit the file to resolve the conflict. In this file, you will find the following:

<<<<<<< HEAD
Changes from Erik 
=======
Changes from Jim 
>>>>>>> b2919weg63bfd125627gre1911c8b08127c85f8 

The <<<<<<< characters indicate the start of the merge conflict, the ====== characters indicate the break points used for comparison, and >>>>>>> indicate the end of the conflict.

To resolve a conflict, you have to analyze the differences between the two changes and merge them manually. Don’t forget to delete the signs added by Git. After resolving it, simply commit the changes.

If your merge conflict is too complicated to resolve because you can’t easily find the differences, Git provides a useful tool to help you.

Git’s diff helps you to find differences:

Diff --git erik/mergetestjim/mergetest
Index.html 88h3d45..92f62w 130634
--- erik/mergetest
+++ jim/mergetest
@@ -1,3 +1,4 @@
<body>
+I added this code between
This is the file content
-I added a third line of code
+And this is the last one

So, what happened? The command displays some lines with the changes, with the + mark coming from origin/master; those marked with are from your local repository, and of course, the lines without a mark are common to both repositories.

Summary

In this article, we covered all tips and commands that are useful to fix mistakes, resolve conflicts, search inside the commit history, and so on.

Resources for Article:


Further resources on this subject:


Packt

Share
Published by
Packt

Recent Posts

Top life hacks for prepping for your IT certification exam

I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…

3 years ago

Learn Transformers for Natural Language Processing with Denis Rothman

Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…

3 years ago

Learning Essential Linux Commands for Navigating the Shell Effectively

Once we learn how to deploy an Ubuntu server, how to manage users, and how…

3 years ago

Clean Coding in Python with Mariano Anaya

Key-takeaways:   Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…

3 years ago

Exploring Forms in Angular – types, benefits and differences   

While developing a web application, or setting dynamic pages and meta tags we need to deal with…

3 years ago

Gain Practical Expertise with the Latest Edition of Software Architecture with C# 9 and .NET 5

Software architecture is one of the most discussed topics in the software industry today, and…

3 years ago