DEV Community

Kenichiro Nakamura
Kenichiro Nakamura

Posted on

git deep dive part 2: Additional commit to master and new branch

In the previous article, 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

mkdir docs
cd docs
echo "great article" > article.txt
echo "great news" > news.txt
cd ..
Enter fullscreen mode Exit fullscreen mode

Then check the git status. I added -u parameter to show files. As expected, two files are shown as Untracked files.

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)
Enter fullscreen mode Exit fullscreen mode

Same as last time, there is no change in .git folder at the moment.
Run the git add command and see status.

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
Enter fullscreen mode Exit fullscreen mode

Examine objects

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

.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
Enter fullscreen mode Exit fullscreen mode
  • 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.

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
Enter fullscreen mode Exit fullscreen mode

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.

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
Enter fullscreen mode Exit fullscreen mode

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.

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
Enter fullscreen mode Exit fullscreen mode

In .git folder, I see below changes.

.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
Enter fullscreen mode Exit fullscreen mode
  • 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.

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
Enter fullscreen mode Exit fullscreen mode

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.

gitDeepDive> git ls-tree 129b57b6945a4e9e56abaf5b229701565e2c6cdd
040000 tree 79a776223b60cb98e81a58d0ec92f00242ca7dcb    docs
100644 blob 20fe8be9820a49252e2a4dd37a60e678cd5cda14    hello.txt
Enter fullscreen mode Exit fullscreen mode

Continue to docs tree. We already know what this should contain.

gitDeepDive> git ls-tree 79a776223b60cb98e81a58d0ec92f00242ca7dcb
100644 blob 44f41854d770f2a38d368936b14975d280cbd950    article.txt
100644 blob 2b54426c8ded2b5334352e13b3ae62231ab67fee    news.txt
Enter fullscreen mode Exit fullscreen mode

master file in refs\heads now points to new commit id.

gitDeepDive> cat .\.git\refs\heads\master
2adbcacc0047a991956dedb4b16691ba244674b3
Enter fullscreen mode Exit fullscreen mode

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.

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
Enter fullscreen mode Exit fullscreen mode

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.

git branch dev
Enter fullscreen mode Exit fullscreen mode

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

gitDeepDive> git branch -a
  dev
* master
Enter fullscreen mode Exit fullscreen mode

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.

gitDeepDive> cat .\.git\refs\heads\dev
2adbcacc0047a991956dedb4b16691ba244674b3
Enter fullscreen mode Exit fullscreen mode

The dev file in logs folder contains log history, but it is a history for the dev branch.

gitDeepDive> cat .\.git\logs\refs\heads\dev
0000000000000000000000000000000000000000 2adbcacc0047a991956dedb4b16691ba244674b3 Kenichiro Nakamura <kenakamu@microsoft.com> 1588784059 +0900    branch: Created from master
Enter fullscreen mode Exit fullscreen mode

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 and see what will be changed.

git checkout dev
Enter fullscreen mode Exit fullscreen mode

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.

gitDeepDive> cat .\.git\HEAD
ref: refs/heads/dev
Enter fullscreen mode Exit fullscreen mode

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

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
Enter fullscreen mode Exit fullscreen mode

Run reflog command to display reflog info.

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
Enter fullscreen mode Exit fullscreen mode

The following diagram illustrates the current status.
Alt Text

Modify file and commit to dev branch

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

echo "more info in news" >> .\docs\news.txt
Enter fullscreen mode Exit fullscreen mode

See the status.

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")
Enter fullscreen mode Exit fullscreen mode

Add the change and commit at the same time.

gitDeepDive> git commit -am "Update news"
[dev 367c2d0] Update news
 1 file changed, 1 insertion(+)
Enter fullscreen mode Exit fullscreen mode

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).

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
Enter fullscreen mode Exit fullscreen mode

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

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
Enter fullscreen mode Exit fullscreen mode

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.

gitDeepDive> git log --oneline
367c2d0 (HEAD -> dev) Update news
2adbcac (master) Add doc folder and files
16f1fa8 commit hello.txt
Enter fullscreen mode Exit fullscreen mode

I also draw a diagram to illustrate current status.
Alt Text

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

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
Enter fullscreen mode Exit fullscreen mode

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.

gitDeepDive> cat .\.git\HEAD
2adbcacc0047a991956dedb4b16691ba244674b3
gitDeepDive> cat .\.git\refs\heads\dev
367c2d000be0ffbb640252384c820ce472fe32a4
Enter fullscreen mode Exit fullscreen mode

Alt Text

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

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
Enter fullscreen mode Exit fullscreen mode

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.

git checkout -b test
Enter fullscreen mode Exit fullscreen mode

This simply create a branch file which pointing to commit id 2adbcac.

gitDeepDive> cat .\.git\HEAD
ref: refs/heads/test
Enter fullscreen mode Exit fullscreen mode

.git folder looks like this now.

.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
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)