The Git working tree, index and commit history explained by example
When developers perform distributed version control with Git, they should no longer think of the development workspace as simply a collection of files and folders stored on the file system. Git transforms a development environment into a four-dimensional space, with the Git working tree as the most important element.
The Git working tree is comprised of files in their present state as they exist on the file system. The Git index -- to which files are staged -- is the second dimension. A commit of the staged files is the third dimension and the history of commits over time is the fourth.
But to understand how all of these dimensions interact, one must first understand the Git working tree, and the right Git utility for elucidation is the status command.
The Git working tree explained
To properly translate the Git working tree, a developer must first recognize what is and isn't part of it.
When a new repository is initialized, Git creates a hidden folder named .git in the location where the init command runs. This folder isn't part of the Git working tree but is instead part of Git's internal plumbing. All the other files and folders that a developer adds to the Git repository residing outside the .git folder are known as the Git working tree. The working tree is the set of all files and folders a developer can add, edit, rename and delete during application development.
More colloquially, developers often refer to the Git working tree as the workspace or the working directory. But the technical name for the collection of files and folders in a repository is the Git working tree. Also, a bare Git repository where development doesn't take place -- such as one hosted on GitHub or Bitbucket -- doesn't have a working tree. That's one of the key differences between a local Git repository and a cloud-hosted, as-a-service offering.
It's not wrong to think of the Git working tree as more of a service than simply a collection of files. The working tree constantly keeps track of the file system's resource status. For example, if a developer adds a new file, the Git working tree takes note. If a file is deleted, the Git working tree takes note. If a file is edited and not added to the index, the Git working tree takes note. It's a service that watches everything on the file system.
The Git working tree examples
The git status command is the best way to garner insight into the mechanics of the working tree.
If a developer creates a brand-new Git repository and runs the git status command, the results will show that nothing interesting happened on the file system, as to be expected.
$ git init Initialized empty Git repository in C:/_bart/.git/ $ git status On branch master No commits yet nothing to commit (create/copy files and use "git add" to track)
Untracked Git files example
If a developer adds a new file to the workspace, the Git working tree will notice immediately and indicate that there is a new, untracked file:
$ touch home.html $ git status On branch master No commits yet Untracked files: home.html nothing added to commit but untracked files present (use "git add" to track)
To track the file, simply add it to the tracking index. After, the git status command will report that the working tree service recognizes that the home.html file will be part of the next commit.
$ git add home.html $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: home.html
Git commits and the working tree
A successful commit will bring the Git working tree back to its initial state.
$ git commit -m "Git status and working tree commit" [master (root-commit) ae59b26] Git status and working tree commit 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 home.html $ git status On branch master nothing to commit, working tree clean
Modified and deleted Git working tree files
If a developer edits a file that has been previously committed, the working tree will register it as modified:
$ echo "Hello World" >> home.html $ git status On branch master 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: home.html no changes added to commit (use "git add" and/or "git commit -a")
The working tree also takes note if a developer deletes a file.
$ rm home.html $ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: home.html
If these changes are staged, a commit can be issued to restore the working tree to a clean state:
$ git add . $ git commit -m "Another git working tree example" [master 31c0a24] Another git working tree example 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 home.html $ git reflog 31c0a24 (HEAD -> master) HEAD@{0}: commit: Another git working tree example ae59b26 HEAD@{1}: commit (initial): Git status and working tree commit
After a developer initializes a Git repository, there is far more behind the scenes than one might assume. The Git working tree plays a bit part in keeping track of new, staged, modified and deleted files, and the git status command serves as the porcelain tool that provides perspective on some of Git's internal plumbing.