I've watched numerous videos on how to use git as a version control system. But I used to forget the stuffs every once in a while. That's when I decided to jump into the git internals and learn git from a different aspect this time. I didn't memorize the git commands, rather studied extensively on various practical used cases of those commands. Surely such a mental mapping has helped me in learning the basics of git faster and retain them in a better way.
Let the fun begin!
Current Working Directory:
This refers to the physical area where we as developers actually write our code. It is here that we make our changes and expect our code to reach out to our colleague who might be working remotely thousands of KMs away.
Staging area is the intermediate area where the files reside before getting saved into the repository. Staging area is the penultimate stage where modifications are still possible before data gets stored into the repository.
.git is the repo where our transferable code is stored. Whenever we clone a repo using git clone, it is this .git directory which actually gets downloaded as a local copy and development starts on top of this.
You modify files in your working tree.
You selectively stage just those changes you want to be part of your next commit, which adds only those changes to the staging area.
You do a commit, which takes the files as they are in the staging area and stores that snapshot permanently to your Git directory.
Inside any directory if we type the above commands then it would create a .git hidden directory and would track all the changes to the files and folders of the parent directory.
Suppose we initialized our directory and are about to add the first file to the staging area, this can be done by the following command for a single file:
git add <filename>
for multiple files to be staged:
git add .
Now that we've added our first files to the staging area, let's see how git stores them under the hood.
git actually stores objects in a key store format.
For files, these are stored as blob(Binary Large Objects) SHA-1 key is generated by passing the contents of the file through the encryption algorithm and the 40-character checksum hash now corresponds to the file.
Note: There is no file name attached to the blob object.
8f94139338f9404f26296befa88755fc2598c289 is an example of 40 digit checksum hash.
Now you must be wondering how does the file name gets mapped on to the blob contents?
This is done by another git object - tree.
Tree is basically used to store the filenames as well as the directories. A single tree object contains one or more entries, each of which is the SHA-1 hash of a blob or sub-tree with its associated mode, type, and filename.
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
The above is an example of a simple tree.
Git normally creates a tree by taking the state of your staging area or index and writing a series of tree objects from it. So, to create a tree object, you first have to set up an index by staging some files.
Once we've staged our files in the staging area/index we can then commit those changes to the local Repo using the following command:
git commit -m "some sample message"
if we wish to write multi-line commits, we can simply write:
and it would open a text editor to write the multi-line commits.
The format for a commit object is simple: it specifies the top-level tree for the snapshot of the project at that point; the parent commits if any (the commit object described above does not have any parents); the author/committer information (which uses your user.name and user.email configuration settings and a timestamp); a blank line, and then the commit message.
this command shows the differences between the staged files and their corresponding versions in the working directory. It however doesn't check for those files which haven't been added to the staging area.
git diff --staged
this command marks the contrast between the committed and the staged files.
Git status does 2 things:
it compares the index file with:
- the current working directory changes are reported as Changes not staged for commit
- the HEAD commit — changes are reported as Changes to be committed
If suppose we've made some changes which we later feel aren't of much use. Then we can undo them before actually committing.
git reset --hard HEAD
This resets the file of the working directory and of the staging area to the commit pointed in HEAD.
git checkout <file_name>
This command replaces the working directory version of the file with the prev version that has been staged.
git checkout <commit_hash> --<file_name>
This command replaces the working directory and staged versions of the file with the prev version that has been committed.
Please note that both the above commands, replace the current working directory content and this change can't be undone.
git rm --cached <filepath>
This command removes the file from the staging area and keeps an untracked copy in the current working directory. If a commit is made now, it would remove that from the repo as well.
git reset HEAD <filepath>
In the case where the file is already in the repo, it replaces the index version of the file with the one from repo (HEAD), effectively unstaging the modifications to it.
git rm <filepath>
The above command removes a file from both the working directory and staging area.
You might be thinking that we can simply delete the file from our system and that would work equally good. But no that isn't the case, git rm removes the file from both working directory and staging area while the rm command of operating system only deletes that from the working directory and we need to add the change again to get reflected in the staging area. Something kind of adding a negation to reflect the change.
git log provides us a log of all the commits that have been made to the repo. However to get a better representation use the following command:
git log --all --decorate --oneline --graph
There is a shortcut that I use to remember the above command - git log A DOG.