git deep dive part 2: Additional commit to master and new branch
Tags: git
Published: 2020-05-07 15:42:23

---
title: git deep dive part 2: Additional commit to master and new branch
published: true
description: git deep dive
tags: git
---

In the [previous article](https://dev.to/kenakamu/git-deep-dive-part-1-from-initialize-to-first-commit-19nh), I try ``git init`` to first commit. In this article, I do additional commits.

There are several great video explain the very detail and I am just summarizing them here.

# Add a folder and files

I just added a file so far. Let's add folder and files.

### Create folder and files, then add

```shell
mkdir docs
cd docs
echo "great article" > article.txt
echo "great news" > news.txt
cd ..
```
Then check the git status. I added ``-u`` parameter to show files. As expected, two files are shown as **Untracked files**.

```shell
gitDeepDive> git status -u
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        docs/article.txt
        docs/news.txt

nothing added to commit but untracked files present (use "git add" to track)
```
Same as last time, there is no change in .git folder at the moment.
Run the ``git add`` command and see status.

```shell
gitDeepDive> git add docs
gitDeepDive> git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   docs/article.txt
        new file:   docs/news.txt
```

### Examine objects

As expected, there are several new and modified files in .git folder.

```shell
.git
│  COMMIT_EDITMSG
│  config
│  description
│  HEAD
│  index
├─info
│      exclude
├─logs
│  │  HEAD
│  │
│  └─refs
│      └─heads
│              master
├─objects
│  ├─16
│  │      f1fa822d53d12329e9a68c7463c5697bddc7d1
│  ├─20
│  │      fe8be9820a49252e2a4dd37a60e678cd5cda14
│  ├─2b
│  │      54426c8ded2b5334352e13b3ae62231ab67fee
│  ├─44
│  │      f41854d770f2a38d368936b14975d280cbd950
│  ├─8d
│  │      0e41234f24b6da002d962a26c2495ea16a425f
│  ├─a2
│  │      cf761ea993127a4aae5762806441cc18d730f5
│  ├─info
│  └─pack
└─refs
    ├─heads
    │      master
    └─tags
```
- index file was updated
- 2b and 44 folders were created in objects folder
- 54426c8ded2b5334352e13b3ae62231ab67fee file in 2b folder was created
- f41854d770f2a38d368936b14975d280cbd950 file in 44 was created

Run following commands to see the contents.

```shell
gitDeepDive> git ls-files -t
H docs/article.txt
H docs/news.txt
H hello.txt
gitDeepDive> git cat-file -t 2b54426c8ded2b5334352e13b3ae62231ab67fee
blob
gitDeepDive> git cat-file blob 2b54426c8ded2b5334352e13b3ae62231ab67fee
great news
gitDeepDive> git cat-file -t 44f41854d770f2a38d368936b14975d280cbd950
blob
gitDeepDive> git cat-file blob 44f41854d770f2a38d368936b14975d280cbd950
great article
```

index file tracks which files are in git, so it contains all three files now. I can run status with verbose option to see diff at the same time. I can see the blob ids which to be compared.

```shell
gitDeepDive> git status -v
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   docs/article.txt
        new file:   docs/news.txt

diff --git a/docs/article.txt b/docs/article.txt
new file mode 100644
index 0000000..44f4185
--- /dev/null
+++ b/docs/article.txt
@@ -0,0 +1 @@
+great article
diff --git a/docs/news.txt b/docs/news.txt
new file mode 100644
index 0000000..2b54426
--- /dev/null
+++ b/docs/news.txt
@@ -0,0 +1 @@
+great news
```

# Commit changes

Let's see what happens when I ``git commit``, which is my second commit.

### Run commit and see which files are created

Run ``git commit`` and it says two files were changed.

```shell
gitDeepDive> git commit -m "Add doc folder and files"
[master 2adbcac] Add doc folder and files
 2 files changed, 2 insertions(+)
 create mode 100644 docs/article.txt
 create mode 100644 docs/news.txt
```
In .git folder, I see below changes.

```shell
.git
│  COMMIT_EDITMSG
│  config
│  description
│  HEAD
│  index
├─info
│      exclude
├─logs
│  │  HEAD
│  │
│  └─refs
│      └─heads
│              master
├─objects
│  ├─12
│  │      9b57b6945a4e9e56abaf5b229701565e2c6cdd
│  ├─16
│  │      f1fa822d53d12329e9a68c7463c5697bddc7d1
│  ├─20
│  │      fe8be9820a49252e2a4dd37a60e678cd5cda14
│  ├─2a
│  │      dbcacc0047a991956dedb4b16691ba244674b3
│  ├─2b
│  │      54426c8ded2b5334352e13b3ae62231ab67fee
│  ├─44
│  │      f41854d770f2a38d368936b14975d280cbd950
│  ├─79
│  │      a776223b60cb98e81a58d0ec92f00242ca7dcb
│  ├─8d
│  │      0e41234f24b6da002d962a26c2495ea16a425f
│  ├─a2
│  │      cf761ea993127a4aae5762806441cc18d730f5
│  ├─info
│  └─pack
└─refs
    ├─heads
    │      master
    └─tags
```
- index and COMMIT_EDITMSG file were updated
- HEAD in logs folder was updated
- master in logs\refs\heads and refs\heads was updated
- 12, 2a and 79 folders were added in objects folder
- 9b57b6945a4e9e56abaf5b229701565e2c6cdd file in 12 folder was created
- dbcacc0047a991956dedb4b16691ba244674b3 file in 2a folder was created
- a776223b60cb98e81a58d0ec92f00242ca7dcb file in 79 folder was created

### Examine files

As I already see "2adbcac" in the commit result, so I start examine it first. I already know this is commit file, so I omit to check type. 

This commit has parent id which is the first commit I created in the previous article.

```shell
gitDeepDive> git cat-file commit 2adbcacc0047a991956dedb4b16691ba244674b3
tree 129b57b6945a4e9e56abaf5b229701565e2c6cdd
parent 16f1fa822d53d12329e9a68c7463c5697bddc7d1
author Kenichiro Nakamura <kenakamu@microsoft.com> 1588783197 +0900
committer Kenichiro Nakamura <kenakamu@microsoft.com> 1588783197 +0900

Add doc folder and files
```
Next, I ``git ls-tree`` the tree id in the commit file. The docs is marked as  **tree** which is a folder, and hello.txt as blob. As I didn't change hello.txt content at all, it still points to the original id.

```shell
gitDeepDive> git ls-tree 129b57b6945a4e9e56abaf5b229701565e2c6cdd
040000 tree 79a776223b60cb98e81a58d0ec92f00242ca7dcb    docs
100644 blob 20fe8be9820a49252e2a4dd37a60e678cd5cda14    hello.txt
```
Continue to docs tree. We already know what this should contain.

```shell
gitDeepDive> git ls-tree 79a776223b60cb98e81a58d0ec92f00242ca7dcb
100644 blob 44f41854d770f2a38d368936b14975d280cbd950    article.txt
100644 blob 2b54426c8ded2b5334352e13b3ae62231ab67fee    news.txt
```
master file in refs\heads now points to new commit id.

```shell
gitDeepDive> cat .\.git\refs\heads\master
2adbcacc0047a991956dedb4b16691ba244674b3
```
Logs has all the log information. So obviously, this contains not only the latest commit log but entire histories. I can also see the commit chain from 16f1fa8 to 2adbca too.

```shell
gitDeepDive> cat .\.git\logs\HEAD
0000000000000000000000000000000000000000 16f1fa822d53d12329e9a68c7463c5697bddc7d1 Kenichiro Nakamura <kenakamu@microsoft.com> 1588780516 +0900    commit (initial): commit hello.txt
16f1fa822d53d12329e9a68c7463c5697bddc7d1 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588783197 +0900    commit: Add doc folder and files
gitDeepDive> cat .\.git\logs\refs\heads\master
0000000000000000000000000000000000000000 16f1fa822d53d12329e9a68c7463c5697bddc7d1 Kenichiro Nakamura <kenakamu@microsoft.com> 1588780516 +0900    commit (initial): commit hello.txt
16f1fa822d53d12329e9a68c7463c5697bddc7d1 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588783197 +0900    commit: Add doc folder and files
```
# Add branch

I have some idea what's going on when I add/commit. Let's move to next topic, branch.

### Add new branch

What happens when I add new branch? Let's figure out. First I create dev branch.

```shell
git branch dev
```

Then I check current branch. I have dev branch but I am still on the master branch.

```shell
gitDeepDive> git branch -a
  dev
* master
```
As soon as I created a branch, there is new item in .git folder.

- dev file in logs\refs\heads and refs\heads were created

Both are just text file. The dev file in refs folder pointing the current commit of dev branch, which is the latest commit id.

```shell
gitDeepDive> cat .\.git\refs\heads\dev
2adbcacc0047a991956dedb4b16691ba244674b3
```
The dev file in logs folder contains log history, but it is a history for the dev branch.

```shell
gitDeepDive> cat .\.git\logs\refs\heads\dev
0000000000000000000000000000000000000000 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588784059 +0900    branch: Created from master
```
Now it's clear that logs\HEAD contains current log information, and ones under logs\refs\heads contains each branch's log.

### Checkout to dev branch

I will work on dev branch. Do [checkout](https://git-scm.com/docs/git-checkout) and see what will be changed.

```shell
git checkout dev
```
When I did ``git checkout``, .git folder has following changes.

- updated HEAD and index in .git folder
- updated HEAD in logs folder

Let's see HEAD in .git. Now it points to dev file instead of master.

```shell
gitDeepDive> cat .\.git\HEAD
ref: refs/heads/dev
```

Finally, HEAD in logs folder. It seems to contain log history, but as it has **checkout** history, it is reflog info.

```shell
gitDeepDive> cat .\.git\logs\HEAD
0000000000000000000000000000000000000000 16f1fa822d53d12329e9a68c7463c5697bddc7d1 Kenichiro Nakamura <kenakamu@microsoft.com> 1588780516 +0900    commit (initial): commit hello.txt
16f1fa822d53d12329e9a68c7463c5697bddc7d1 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588783197 +0900    commit: Add doc folder and files
2adbcacc0047a991956dedb4b16691ba244674b3 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588785225 +0900    checkout: moving from master to dev
```

Run [reflog](https://git-scm.com/docs/git-reflog) command to display reflog info.

```shell
gitDeepDive> git reflog
2adbcac (HEAD -> dev, master) HEAD@{0}: checkout: moving from master to dev
2adbcac (HEAD -> dev, master) HEAD@{1}: commit: Add doc folder and files
16f1fa8 HEAD@{2}: commit (initial): commit hello.txt
```

The following diagram illustrates the current status.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/5dwwe7rwz3imoiktz70s.png)

### Modify file and commit to dev branch

Create branch is just create dev files in .git folder. Let's modify the existing file.

```shell
echo "more info in news" >> .\docs\news.txt
```
See the status.

```shell
gitDeepDive> git status
On branch dev
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:   docs/news.txt

no changes added to commit (use "git add" and/or "git commit -a")
```

Add the change and commit at the same time.

```shell
gitDeepDive> git commit -am "Update news"
[dev 367c2d0] Update news
 1 file changed, 1 insertion(+)
```
I run ``gi cat-file`` in a different way to see the commit. I use ``-p dev`` which is a pointer to current commit (367c2d0).

```shell
gitDeepDive> git cat-file -p dev
tree 30962e4266975d43d1698bec735caa2e17ba3223
parent 2adbcacc0047a991956dedb4b16691ba244674b3
author Kenichiro Nakamura <kenakamu@microsoft.com> 1588786051 +0900
committer Kenichiro Nakamura <kenakamu@microsoft.com> 1588786051 +0900

Update news
```

When I run ``git log``, I see dev and master now points to different commit ids.

```shell
gitDeepDive> git log --graph --pretty
* commit 367c2d000be0ffbb640252384c820ce472fe32a4 (HEAD -> dev)
| Author: Kenichiro Nakamura <kenakamu@microsoft.com>
| Date:   Thu May 7 02:27:31 2020 +0900
|
|     Update news
|
* commit 2adbcacc0047a991956dedb4b16691ba244674b3 (master)
| Author: Kenichiro Nakamura <kenakamu@microsoft.com>
| Date:   Thu May 7 01:39:57 2020 +0900
|
|     Add doc folder and files
|
* commit 16f1fa822d53d12329e9a68c7463c5697bddc7d1
  Author: Kenichiro Nakamura <kenakamu@microsoft.com>
  Date:   Thu May 7 00:55:16 2020 +0900

      commit hello.txt
```

### Examine .git folder objects

The change in .git folder is very similar to last time. The index, HEAD files are updated and blob/tree items are created in objects folder.

# Checkout to previous commit

Sometimes, I need to go back to older commit. Let's see what happens when I do that from git point of view.

First of all, check current commits with ``git log``.

```shell
gitDeepDive> git log --oneline
367c2d0 (HEAD -> dev) Update news
2adbcac (master) Add doc folder and files
16f1fa8 commit hello.txt
```
I also draw a diagram to illustrate current status.
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3fxv1qk4qkzlbrhnm3d4.png)

Let me go back to commit 2adbcac. It shows a bit terrifying message :).

```shell
gitDeepDive> git checkout 2adbcac
Note: switching to '2adbcac'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 2adbcac Add doc folder and files
```
But no worries, there are only several files updated in .git folder.

- index and HEAD in .git folder were updated
- HEAD in logs was updated

At the end, this is exactly same when I checkout to dev branch. The difference is that HEAD in .git contains commit id, rather than branch name. This is the meaning of "detached HEAD", as dev file in refs folder still pointing to last commit id.

```shell
gitDeepDive> cat .\.git\HEAD
2adbcacc0047a991956dedb4b16691ba244674b3
gitDeepDive> cat .\.git\refs\heads\dev
367c2d000be0ffbb640252384c820ce472fe32a4
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/b00943vlqo3laxkht4nl.png)

HEAD in logs folder has reflog info which shows command history.

```shell
gitDeepDive> cat .\.git\logs\HEAD
0000000000000000000000000000000000000000 16f1fa822d53d12329e9a68c7463c5697bddc7d1 Kenichiro Nakamura <kenakamu@microsoft.com> 1588780516 +0900    commit (initial): commit hello.txt
16f1fa822d53d12329e9a68c7463c5697bddc7d1 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588783197 +0900    commit: Add doc folder and files
2adbcacc0047a991956dedb4b16691ba244674b3 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588785225 +0900    checkout: moving from master to dev
2adbcacc0047a991956dedb4b16691ba244674b3 367c2d000be0ffbb640252384c820ce472fe32a4 Kenichiro Nakamura <kenakamu@microsoft.com> 1588786051 +0900    commit: Update news
367c2d000be0ffbb640252384c820ce472fe32a4 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588786798 +0900    checkout: moving from dev to 2adbcac
```

So what does this mean? Even though I am in *detached HEAD* state, I lost nothing. All the objects such as commit, tree, blob are still there. I can restore them anytime.

If I want to create new branch in this commit, then I can run ``git checkout`` with ``-b`` parameter.

```shell
git checkout -b test
```
This simply create a branch file which pointing to commit id 2adbcac. 

```shell
gitDeepDive> cat .\.git\HEAD
ref: refs/heads/test
```
.git folder looks like this now.

```shell
.git
│  COMMIT_EDITMSG
│  config
│  description
│  HEAD
│  index
├─info
│      exclude
├─logs
│  │  HEAD
│  │
│  └─refs
│      └─heads
│              dev
│              master
│              test
├─objects
│  ├─12
│  │      9b57b6945a4e9e56abaf5b229701565e2c6cdd
│  ├─16
│  │      f1fa822d53d12329e9a68c7463c5697bddc7d1
│  ├─20
│  │      fe8be9820a49252e2a4dd37a60e678cd5cda14
│  ├─2a
│  │      dbcacc0047a991956dedb4b16691ba244674b3
│  ├─2b
│  │      366bf2f2784dbf26fcd56e1cedb3afc1345753
│  │      54426c8ded2b5334352e13b3ae62231ab67fee
│  │      af027b74c551817c2a5ef6a3472ccc8e99738c
│  ├─30
│  │      962e4266975d43d1698bec735caa2e17ba3223
│  ├─36
│  │      7c2d000be0ffbb640252384c820ce472fe32a4
│  ├─44
│  │      f41854d770f2a38d368936b14975d280cbd950
│  ├─79
│  │      a776223b60cb98e81a58d0ec92f00242ca7dcb
│  ├─8d
│  │      0e41234f24b6da002d962a26c2495ea16a425f
│  ├─a2
│  │      cf761ea993127a4aae5762806441cc18d730f5
│  ├─info
│  └─pack
└─refs
    ├─heads
    │      dev
    │      master
    │      test
    └─tags
```

# Summary

Create a branch is as simple as create a file in git, that is why it's super quick. In the next article, I explain a bit more detail about HEAD, index and working tree.

[Go to next article](https://dev.to/kenakamu/git-deep-dive-part-3-head-index-and-working-tree-3oim)