7 minutes read

In previous topics, you learned how to initialize a Git repository, create snapshots of files called commits, and understand branches in Git. Another important consideration is the differences between files, branches, and commits. This is crucial when working alone on a project, and you need to perform essential tasks such as debugging. By comparing the current version with a previous working version, you can identify where a bug is located.

Moreover, this becomes even more significant when working in a team, as you need to compare versions of files received from different team members and resolve conflicts when merging the results. In this topic, we will explore a tool that allows you to view these differences.

What is git diff

git diff is a command that shows the differences between two versions of a file, two commits, or two branches. By default, without arguments and options, it compares the changes made to the files in the working tree with files in your staging area.

Let's look at how it works. First, let's make a repo, initialize git in it, then create a file with some lines and add it to the staging area. After that, we will change the file in the working tree by adding additional lines of text and use git diff to watch the differences between them. You can repeat the following steps on your machine:

$ git init our-repo     # initialize git and make a repo
$ cd our-repo
$ echo "Now you are" > our-file # write the line to the file
$ git add .     # add all files in directory to the staging area
$ echo "in JetBrains Academy" >> our-file     # change the file
$ git diff  # look for the difference of our-file in staging area and in working tree

git diff without arguments will show changes in all files in the staging area. To see the changes made to specific files, you have to type the names of those files.

Now, let's look at the output.

Output of git diff

The output of git diff shows the lines that have been added, deleted, or modified, along with their line numbers and context. This is what our output looks like:

diff --git a/our-file b/our-file
index c703f5f..891ccac 100644
--- a/our-file
+++ b/our-file
@@ -1 +1,2 @@
 Now you are
+in JetBrains Academy

Let's examine the output line by line.

The line diff --git a/our-file b/our-file shows the names of the files being compared. There is one file name marked with a and b in front, indicating two different versions of the same file.

This line, index c703f5f..891ccac 100644, contains object hash values required by Git for internal use and the mode of the file (100644).

The lines --- a/our-file +++ b/our-file show you that the changes in the first file are marked by the - sign, and changes in the second one are marked by +. This is the legend of the output.

The last lines together form what is called a chunk and shows changes in files using their - and + signs.

@@ -1 +1,2 @@
 Now you are
+in JetBrains Academy

The line @@ -1 +1,2 @@ is the chunk header and is a summary of changes made in the files. In our example, -1 indicates that one line has been removed from the first version of the file. +1,2 indicates that two lines have been added starting at the first line of the new version of the file. If the header was something like @@ -8,39 +20,7 @@, it would mean that 39 lines have been removed at line 8, and 7 lines added starting at line 20. Cool summary, huh?

The following lines display those changes, where words in white mark unchanged text, and words in a different color indicate modifications.

Now, let's explore how you can use git diff beyond its default version.

More options of git diff

$ git diff --staged

This git diff command with option --staged will show the difference between files in your staging area and files in the last commit.

You can use git diff --cached instead of git diff --staged — they are both the same

$ git diff --name-only

This command shows only the names of the files that have been changed, making it easier to identify which files you need to review.

Another option --stat lets git diff display not only the names of files that have been modified, but also the number of lines added and removed; as well as the total number of files with changes.

$ git diff --stat

Let's see now how to use git diff to watch the differences between commits and branches. That's just:

$ git diff <commit1>..<commit2>
$ git diff <branch1>..<branch2>

Instead of <branch...> and <commit...> you just type their branch name and abbreviated commit hash respectively.

If you would like to view changes to a specific file across branches, you can pass the file name as the third argument:

$ git diff main new_branch ./our-file.txt

The two dots between names of commits and branches are actually optional, you can put the space instead of them

Patches

Maybe you already noticed that the output of git diff looks like a set of instructions. And actually, we can use these instructions to change files. The file with these instructions is called a patch. It used to be the major way of sharing the code sent by email, however now it's mostly replaced by pull requests.

So, let's make one simple patch. First, let's make a file with one line of text, add it to the staging area, then add a second line to that file. After that using git diff command write our "changes-instructions" to the file our-patch.patch. Finally, we remove the second line to return the file to its original state.

$ echo "Felis catus is your taxonomic nomenclature," > spot
$ git add .
$ echo "An endothermic quadruped, carnivorous by nature;" >> spot
$ git diff > our-patch.patch # make the patch with adding second line to the file
$ sed -i '2d' spot # deleting the second line and restore the original version of our file

Now we can pretend that we got this patch from our colleague, and use our patch to apply changes. For that we need the command git apply:

$ git apply our-patch.patch

If you check the file, spot it should now contain 2 lines.

Final word about /dev/null

If you add a file spot to the staging area, remove it from your working directory, and use git diff command, then you will see in the part of output of both new files the line +++ /dev/null. Like here

diff --git a/spot b/spot
deleted file mode 100644
index 9af82f5..0000000
--- a/spot
+++ /dev/null
...

That's how git diff marks the current version of the file if it is removed or the previous version of a file (---) if it didn't exist before, or if you added a new file. In these cases, the device file /dev/null is used as a placeholder.

In Unix and Unix-like OSes, /dev/null is a null device file.

Conclusion

So, we learned today the git diff command, which is used to show the differences between two versions of a file, two files, branches, or commits.

The main commands to remember are:

  • git diff which shows the difference between files in your staging area and modified files in the working tree;

  • git diff --staged shows the difference between files in the staging area and the last commit;

  • git diff <commit1>..<commit2> and git diff <branch1>..<branch2> show differences between commits and branches;

  • git diff --stat shows a short summary of the number of changes and names of files with those changes;

  • git apply <patch-name.patch> will apply changes from the patch.

In general, this command helps developers to track changes made to the code over time and makes it easier to collaborate with others on a project.

50 learners liked this piece of theory. 1 didn't like it. What about you?
Report a typo