Difference Between Working Tree And Index In Git Git

Jan 8th, 2021 - written by Kimserey with .

In few of our previous posts, we referred to the HEAD, working tree and index when dealing with Git. In today’s post we will look at what those mean with example.

In Git HEAD is known as a reference or “refs”. References are stored under the /.git folder and HEAD is under /,git/HEAD.

For example if we display the content:

1
2
3
4
5
❯ cat .git/HEAD
ref: refs/heads/master

❯ cat .git/refs/heads/master
1911bf2d5227f92ba0b2f4bc03170e02e7a179fe

We can see that right now HEAD is a reference to another reference which itself a commit sha-1.

This second reference .git/refs/heads/master is where our master branch points to on our local repository. This allows us to reference master instead of 1911bf2. Similarly HEAD can simply be referred as HEAD with for example git show HEAD.

Under /,git we can also find ORIG_HEAD which is the reference kept for safety when doing dangerous operations like git reset allowing us to reset back to the original head.

So HEAD is simply a reference to the current commit we are working on. It usually points to the branch which itself is a reference to the latest commit on the branch. But HEAD can also sometime be a specific commit in cases of detached HEAD where we checkout a tag or a specific commit.

Working Tree

The working tree is the current tree on which we are working. It’s where our unstaged changes are kept. Git object model is built around files, trees, commits and references. A tree can be seen as directory which links files blob. We can see trees with ls-tree, for example we show the tree from HEAD:

1
2
3
4
❯ git ls-tree HEAD
100644 blob 2ae827f56b06d064dd3e65e07e92c5a537aa99d3    .gitignore
100644 blob 42f11063a879b952f89165f7f4fa83ddca178408    HELLO
040000 tree 9d254d776ebe2b8e02e0269116f79976b1c5c306    _data

We see that HEAD is composed of blobs and trees and we can list the content of _data which is a directory by using the hash.

Similarly we can look at the content of a file with cat-file -p:

1
2
❯ git cat-file -p 42f11063a879b952f89165f7f4fa83ddca178408
Hello%  

So the working tree is the current tree we are working on.

Commitish and treeish are words used in Git documentation to refer to an object pointing to a commit or a tree.

Index

The index is a tree containing all files including staged changes. We can see its content with ls-files -s:

1
❯ git ls-files -s

where -s includes staged changes.

When doing a git diff, we can use git diff --staged to show the diff between the index and HEAD (which is usually a reference to the tip of the local branch checked out).

The index is the stage where all changes are prepared to be committed, once we do:

1
2
3
❯ git commit -am "Some changes"
[master 1328c74] Some changes
 1 file changed, 2 deletions(-)

The changes from index are saved into a commit on our local master, here at 1328c74. From here our changes are inside our local repository and we can compare it to the upstream:

1
❯ git diff origin/master master

This would compare our local master with origin/master. Then we can push our local branch to the upstream wtih git push to update origin/master.

Remote

origin is known as representing the remote repository. When we talk about remote, we are talking about the remote repository. We can list all our remote repository with: 5ab2f8a4323abafb10abb68657d9d39f1a775057

1
2
3
❯ git remote -v
origin  https://....git (fetch)
origin  https://....git (push)

We can see our origin repository. Just like HEAD, origin is also a reference:

1
2
3
4
5
❯ cat  .git/refs/remotes/origin/HEAD
ref: refs/remotes/origin/master

❯ cat .git/refs/remotes/origin/master
e86ed6b7a9f8e3db7e58dc499728da479d2fac4a

The origin remote is used to fetch (or pull) and push. When we clone a repository, the origin is set by default. If we create a new branch that isn’t track by the remote, we can use --set-upstream or -u to set the upstream branch to track the local branch. This is important to let us use git pull and git push without arguments.

So to summarize here is a graph showing the flow involved:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+--------------+    +-------+   +------------------+   +---------+
|              |    |       |   |                  |   |         |
| Working Tree |    | Index |   | Local Repository |   |  Remote |
|              |    |       |   |                  |   |         |
+------+-------+    +---+---+   +---------+--------+   +----+----+
       |                |                 |                 |
       |                |                 |                 |
       |    git add     |                 |                 |
       +--------------->+                 |                 |
       |                |                 |                 |
       |                |   git commit    |                 |
       |                +---------------->+                 |
       |                |                 |                 |
       |                |                 |     git push    |
       |                |                 +---------------->+
       |                |                 |                 |

Conclusion

In today’s post we looked at the definition of HEAD, working tree, index and remote in Git. Those terms are important terms to understand the Git documentation as they are used throughout the explanations. I hope you liked this post and I see you on the next one!

External Sources

Designed, built and maintained by Kimserey Lam.