Git internals and Basic Commands
A Deep Dive into how Git works with command line tools
In this article we are going to take a look how git works internally. We shall learn some basic git commands on the go.
We shall start with empty project. In my case, have created a folder named "git-internals-learn-2", and opened that folder/project in VS Code. Keep the VS Code's integrated terminal open. There is no file or folder in the project now, one can check that by running following command in terminal.
ls -a
Output :
git-internals-learn-2 $ ls -a
. ..
Now let's initialise git. Meaning that as and when we create files and folders, it will be tracked by git in terms of version control & colloboration. In order to initialise git, run following command :
git init
Output :
git-internals-learn-2 $ git init
Initialized empty Git repository in xyz/git-internals-learn-2/.git/
This command has created a hidden folder named .git inside the project. One can check with following command :
ls -a
Output :
git-internals-learn-2 $ ls -a
. .. .git
And initial folder structure inside .git folder is as under (can be checked via VS Code Explorer) :
.git/
├── HEAD
├── config
├── description
├── hooks/
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ └── update.sample
├── info/
│ └── exclude
├── objects/
│ ├── info/
│ └── pack/
└── refs/
├── heads/
└── tags/
We have not learned anything yet but have a look at following Key Points, we shall revisit them as and when we learn and things will become clearer :
HEAD : In this file, it says "ref: refs/heads/main" which points to "refs/heads/main" . But right now "ref/head" is empty, there will be "main" when we shall add something in git.
config file contains some standard configuration.
description file's content says "Unnamed repository; edit this file 'description' to name the repository."
Sample hooks only: hooks/ contains only *.sample files; they are templates that become active if renamed (e.g., pre-commit). We shall keep any eye on them.
info/exclude file is local ignore file, in which we can add things which we don't want git to track and ignore (mostly files and folders which can be regenerated easily and does not make sense to track them).
No objects yet: objects/ is empty except for the info/ and pack/ directories because there are no commits or blobs until the first git add + git commit. We shall learn about these terms.
refs/heads and refs/tags exist but are empty until the first commit creates a branch reference (like refs/heads/main).
We have taken a look at directory structure and what files are there when we initialise a project. We have introduced terms like "add", "commit", "head", "main", "hooks", "objects", "blob", etc. These terms are not of same category and not of any order, but we have introduced while exploring .git folder.
Now lets create a file is our project folder. Either with VS Code Explorer or with following command in terminal :
cat > file1.txt << 'EOF'
This is first file1 creation. One can say it a "Title Line".
EOF
file1.txt is created with content we provided. Notice for any change in any file in .git folder. Right now even after file1.txt creation, there is not change in .git folder. This is because we have not yet asked git to track anything. By "tracking", I mean track file/folder for version controlling and colloboration, which are the things we want to use git for in the first place (we had discussed in a dedecated previous article). But how to ask git to track files. But first, let's check the status of the project by running following command :
git status
Output :
git-internals-learn-2 $ git status
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
file1.txt
The output shows that our project is on main branch, there are no commits (we shall learn about it later) yet, and there is one file file1.txt is untracked, as we have discussed.
This is where our first git command comes into action. The command is git init <filename>. This shall tell git to track that particular file from now onwards, this is called moving the file into Staging Area. Let's put our file1.txt into a staging area and look for any changes in .git folder. Run following command :
git add file1.txt
The file1.txt is added into Staging Area. Check git status :
git status
Output :
git-internals-learn-2 $ git status
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1.txt
And there are two changes is .git folder :
.git/indexfile is created.git/objects/60/d0624e907d248246dd0a1824fd4dc9d3971629is created.