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 ..
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)
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
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
- 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
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
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
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
- 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
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
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
master file in refs\heads now points to new commit id.
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.
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.
git branch dev
Then I check current branch. I have dev branch but I am still on the master branch.
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.
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.
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 and see what will be changed.
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.
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.
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 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
The following diagram illustrates the current status.
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
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")
Add the change and commit at the same time.
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).
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.
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
.
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.
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
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
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
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
This simply create a branch file which pointing to commit id 2adbcac.
gitDeepDive> cat .\.git\HEAD ref: refs/heads/test
.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
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.
Top comments (0)