2.1 No Conflict

First, let’s see how git works on a normal revision, before we check how it behaves on conflicts when merging. Let’s work with branches from example 09 (before we did the merges). Right after checking out example9/branchA, we run git status:

Listing 2.1:git status on clean working tree
$ git status 
On branch example9/branchA 
nothing to commit, working tree clean

How does git know that there are no changes in my working tree? Git compares the working tree with the index:

Listing 2.2:git ls-files on clean working tree
$ git ls-files -s 
100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0       .gitignore 
100755 ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b 0       example.py 
100644 475f980e6c6e24f8fc4a144e498fa1c1c59da370 0       module.py

git is listing permissions for the files, object ID, index stage3 and the file name for each one of the files in the current revision. git compares the files in the working tree and sees that they haven’t changed and so it reports no changes.

Next thing, let’s modify bf example.py somehow. After modifying and saving, git realizes that the file has changed because it does not match what is on index anymore. Index information won’t change until we add the file, of course. So let’s add the file in the index and check what git ls-files has for us then:

Listing 2.3:git ls-files on a modified file
$ git add example.py 
$ git status 
On branch example9/branchA 
Changes to be committed: 
  (use "git restore --staged <file>..." to unstage) 
        modified:   example.py 
 
$ git ls-files -s 
100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0       .gitignore 
100755 b30ade699b80860abd0ed6d84cff9df94e801d34 0       example.py 
100644 475f980e6c6e24f8fc4a144e498fa1c1c59da370 0       module.py

We can see that the id of the object for example.py has changed4 but other than that, there’s no other difference. How can git know what the ids of those objects in index were before adding them? git is also checking the information about HEAD:

Listing 2.4:git ls-tree on example9/branchA
$ git ls-tree -r HEAD 
100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f    .gitignore 
100755 blob ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b    example.py 
100644 blob 475f980e6c6e24f8fc4a144e498fa1c1c59da370    module.py

And we can see how the ids of the 3 files were the same as the ids that were in the index when we checked out example9/branchA. Now that the id of example.py has changed between HEAD and what’s on the index, git knows that there’s a new content associated for example.py in index that is ready to be committed. That’s why it’s showing up in Changes to be committed now.

Let’s modify the file yet again without adding it and let’s see what happens:

Listing 2.5:After modifying staged file
$ git status 
On branch example9/branchA 
Changes to be committed: 
  (use "git restore --staged <file>..." to unstage) 
        modified:   example.py 
 
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:   example.py 
 
$ git ls-tree -r HEAD 
100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f    .gitignore 
100755 blob ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b    example.py 
100644 blob 475f980e6c6e24f8fc4a144e498fa1c1c59da370    module.py 
$ git ls-files -s 
100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0       .gitignore 
100755 b30ade699b80860abd0ed6d84cff9df94e801d34 0       example.py 
100644 475f980e6c6e24f8fc4a144e498fa1c1c59da370 0       module.py

This is interesting. example.py is showing up in Changes to be committed because the id for the file has changed between HEAD and index. But it’s also showing up in Changes not staged for commit because git notices that the content of the file on the working tree is not matching the object on index. If we added it now and we checked again:

Listing 2.6:After adding file again
$ git add example.py 
$ git status 
On branch example9/branchA 
Changes to be committed: 
  (use "git restore --staged <file>..." to unstage) 
        modified:   example.py 
 
$ git ls-tree -r HEAD 
100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f    .gitignore 
100755 blob ad957360597fb9bd3e83d4bfa869f6e19b7fbf2b    example.py 
100644 blob 475f980e6c6e24f8fc4a144e498fa1c1c59da370    module.py 
$ git ls-files -s 
100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0       .gitignore 
100755 1858db13464ae33329a90cacbe294e749ea9a1a5 0       example.py 
100644 475f980e6c6e24f8fc4a144e498fa1c1c59da370 0       module.py

Notice how the id of the object associated to example.py in index has changed now (from b30ade699b8.... to 1858db13464....). The ids of the objects are still different between index and HEAD and that’s why the file is showing up in Changes to be committed. The file content now matches what is on index and that’s why git doesn’t need to say anything else about the file. If we created a revision at this moment, what would be the result?

Listing 2.7:committing
$ git commit -m "Some test" 
[example9/branchA b2f9a40] Some test 
 1 file changed, 6 insertions(+) 
$ git status 
On branch example9/branchA 
nothing to commit, working tree clean 
$ git ls-tree -r HEAD 
100644 blob 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f    .gitignore 
100755 blob 1858db13464ae33329a90cacbe294e749ea9a1a5    example.py 
100644 blob 475f980e6c6e24f8fc4a144e498fa1c1c59da370    module.py 
$ git ls-files -s 
100644 2f78cf5b66514f2506d9af5f3dadf3dee7aa6d9f 0       .gitignore 
100755 1858db13464ae33329a90cacbe294e749ea9a1a5 0       example.py 
100644 475f980e6c6e24f8fc4a144e498fa1c1c59da370 0       module.py

Notice how the id of example.py has changed on HEAD5 to what was on index before we committed (1858db13464ae33329a90cacbe294e749ea9a1a5). Now the ids of the files is the same between HEAD and index and the file in the working tree matches what’s on index, so git says there’s nothing to report in git status.

Let’s reset the branch before we play with conflicts:

Listing 2.8:Resetting
$ git reset --hard HEAD~ 
HEAD is now at dfde76c A little refactor (moving condition to another function)