はじめに
Git Advent Calendar 2023 3日目の投稿です。よろしくおねがいします。
前々回、前回を通じて以下のコマンドが使えるようになったと思います。
git init
git add
git commit
git branch
git checkout
git merge
内部でどんな動きがされてるか気になったので、今回は↑のコマンドを実行した時に.git
フォルダの中がどのように変化するか観察したいと思います。
やること
下の感じで進めていきます。
リポジトリ(A)を作成
⬇
リポジトリ(A)の.git
内でgit init
して.git
を管理するリポジトリ(B)を作成
⬇
リポジトリ(A)の方でGitのコマンドをいろいろ打ってリポジトリ(B)で差分を観察
Gitリポジトリを2つ使っているので、切り替えがわかりにくい箇所があると思いますがご容赦ください
準備
- 「git/sample2」フォルダを用意。
このフォルダでGitの各コマンドを打って.git
の中身を観察していきます。
git init
git init
をしてリポジトリ(A)の.git
フォルダを作ります。
~/Desktop/git/sample2
$ git init
Initialized empty Git repository in フォルダ名
-
.git
フォルダの構成
.git
│ config
│ description
│ HEAD
│
├─hooks
│ applypatch-msg.sample
│ commit-msg.sample
│ fsmonitor-watchman.sample
│ post-update.sample
│ pre-applypatch.sample
│ pre-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
.git
フォルダでgit init
してリポジトリ(B)を作ります。
~/Desktop/git/sample2/.git (GIT_DIR!)
$ git init
Initialized empty Git repository in フォルダ名
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
HEAD
config
description
hooks/
info/
nothing added to commit but untracked files present (use "git add" to track)
~/Desktop/git/sample2/.git (master)
$ git add .
~/Desktop/git/sample2/.git (master)
$ git commit -m"git init後"
[master (root-commit) a47036c] git init後
git add
リポジトリ(A)上で「sample.txt」を作成します。
~/Desktop/git/sample2 (master)
$ echo "hello world" > sample.txt
~/Desktop/git/sample2 (master)
$ ls
sample.txt
ファイルを作成した直後の.git
フォルダは特になにも変わりがありません。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
nothing to commit, working tree clean
git add
してみます。
~/Desktop/git/sample2 (master)
$ git add .
git add
後の.git
フォルダ
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
index
objects/
nothing added to commit but untracked files present (use "git add" to track)
お、変化がありましたね。
-
.git
フォルダの現在の状況
C:.
│ config
│ description
│ HEAD
│ index ←←←新規
│
├─hooks
│ applypatch-msg.sample
│ commit-msg.sample
│ fsmonitor-watchman.sample
│ post-update.sample
│ pre-applypatch.sample
│ pre-commit.sample
│ pre-push.sample
│ pre-rebase.sample
│ pre-receive.sample
│ prepare-commit-msg.sample
│ update.sample
│
├─info
│ exclude
│
├─objects
│ ├─3b ←←←新規
│ │ 18e512dba79e4c8300dd08aeb37f8e728b8dad
│ │
│ ├─info
│ └─pack
└─refs
├─heads
└─tags
git init
後の.git
フォルダと比較すると、新しくindex
とobjects
配下の3b/18e512...
が作成されたことが分かります。index
はバイナリファイルで差分の検証が難しいので、最後に補足で説明書いてみます。
オブジェクトの中身を見てみましょう。
~/Desktop/git/sample2 (master)
$ git cat-file -p 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
hello world
git add
されたタイミングでブロブオブジェクトが生成されてます。
分かるのはこれくらいですね。
git commit
次にコミットをしてみます。
~/Desktop/git/sample2 (master)
$ git commit -m"first commit"
[master (root-commit) 411124e] first commit
.git
でgit status
してみます。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: index
Untracked files:
(use "git add <file>..." to include in what will be committed)
COMMIT_EDITMSG
logs/
objects/02/
objects/88/
refs/
no changes added to commit (use "git add" and/or "git commit -a")
.git
フォルダの中身が色々変わってきました。 .git
フォルダ全体です。
.git
│ COMMIT_EDITMSG ←←新規
│ config
│ description
│ HEAD
│ index ←←更新
│
├─hooks
│ applypatch-msg.sample
│ commit-msg.sample
│ fsmonitor-watchman.sample
│ post-update.sample
│ pre-applypatch.sample
│ pre-commit.sample
│ pre-push.sample
│ pre-rebase.sample
│ pre-receive.sample
│ prepare-commit-msg.sample
│ update.sample
│
├─info
│ exclude
│
├─logs ←←新規
│ │ HEAD
│ │
│ └─refs
│ └─heads
│ master
│
├─objects
│ ├─02 ←←新規
│ │ 3bd50171db535beab09fed56bd5a9281b01555
│ │
│ ├─3b
│ │ 18e512dba79e4c8300dd08aeb37f8e728b8dad
│ │
│ ├─88 ←←新規
│ │ ccc6b27fbf7beb37e2b2dadceef08ed83a5716
│ │
│ ├─info
│ └─pack
└─refs
├─heads
│ master ←←新規
│
└─tags
1つづつ見てみましょう。
まず、オブジェクトが2つ生成されてますので、中身をのぞいてみます。
~/Desktop/git/sample2 (master)
$ git cat-file -p 88ccc6b27fbf7beb37e2b2dadceef08ed83a5716
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad sample.txt
~/Desktop/git/sample2 (master)
$ git cat-file -p 023bd50171db535beab09fed56bd5a9281b01555
tree 88ccc6b27fbf7beb37e2b2dadceef08ed83a5716
author hogehoge <fugafuga> 1699592736 +0900
committer hogehoge <fugafuga> 1699592736 +0900
first commit
ツリーオブジェクトとコミットオブジェクトが生成されていることが分かります。
ツリーはブロブへの、コミットはツリーへの参照を持っていることも分かりますね。
続いてCOMMIT_EDITMSG
をのぞいてみましょう。
$ cat COMMIT_EDITMSG
first commit
直前にコミットしたときのコミットメッセージですかね?いまのところ、これ以上分かりません。
あとで試しにもう一度コミットして変化するかどうか観察してみましょう。
続いてrefs/heads/master
をのぞいてみましょう。
$ cat refs/heads/master
023bd50171db535beab09fed56bd5a9281b01555
中身はobjects
フォルダに新規で作成されたコミットオブジェクトのハッシュ値ですね。
最後にlogs/HEAD
とlogs/refs/master
です。
$ cat logs/HEAD
0000000000000000000000000000000000000000 023bd50171db535beab09fed56bd5a9281b01555 hogehoge <fugafuga> 1699592736 +0900 commit (initial): first commit
$ cat logs/refs/heads/master
0000000000000000000000000000000000000000 023bd50171db535beab09fed56bd5a9281b01555 hogehoge <fugafuga> 1699592736 +0900 commit (initial): first commit
logs
はその名の通りログを格納してますね。
それぞれ、HEAD
がどのコミットからどのコミットへ移動したか、ブランチがどのコミットからどのコミットへ移動したのかを記録してます。
今回はブランチに対して特に操作をしていないので、同じ内容っぽいです。
COMMIT_EDITMSG
の扱いが気になるので、もう1度コミットしてみましょう。
適当に「sample.txt」を更新して再度コミットします。
~/Desktop/git/sample2 (master)
$ echo "hello" > sample.txt
~/Desktop/git/sample2 (master)
$ git add .
~/Desktop/git/sample2 (master)
$ git commit -m"second commit"
[master 6cf4fd0] second commit
1 file changed, 1 insertion(+), 1 deletion(-)
.git
はどうなるでしょうか。git status
をしてみます。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: COMMIT_EDITMSG
modified: index
modified: logs/HEAD
modified: logs/refs/heads/master
modified: refs/heads/master
Untracked files:
(use "git add <file>..." to include in what will be committed)
objects/6c/
objects/ce/
objects/e3/
no changes added to commit (use "git add" and/or "git commit -a")
取り合えず見たかったCOMMIT_EDITMSG
ファイルの差分を見てみましょう。
~/Desktop/git/sample2/.git (master)
$ git diff COMMIT_EDITMSG
diff --git a/COMMIT_EDITMSG b/COMMIT_EDITMSG
index 44e4d81..2ff0cc0 100644
--- a/COMMIT_EDITMSG
+++ b/COMMIT_EDITMSG
@@ -1 +1 @@
-first commit
+second commit
どうやら、直前のコミットメッセージを保存しているファイルのようです。
もう察しがつくと思いますが、他のファイルも一応見ていきましょうか。
今の.git
フォルダの様子です。
.git
│ COMMIT_EDITMSG ←←←更新
│ config
│ description
│ HEAD
│ index ←←←更新
│
├─hooks
│ applypatch-msg.sample
│ commit-msg.sample
│ fsmonitor-watchman.sample
│ post-update.sample
│ pre-applypatch.sample
│ pre-commit.sample
│ pre-push.sample
│ pre-rebase.sample
│ pre-receive.sample
│ prepare-commit-msg.sample
│ update.sample
│
├─info
│ exclude
│
├─logs
│ │ HEAD ←←←更新
│ │
│ └─refs
│ └─heads
│ master ←←←更新
│
├─objects
│ ├─02
│ │ 3bd50171db535beab09fed56bd5a9281b01555
│ │
│ ├─3b
│ │ 18e512dba79e4c8300dd08aeb37f8e728b8dad
│ │
│ ├─6c ←←←新規
│ │ f4fd07bd3d1f982045f50fae9dc070d6967f36
│ │
│ ├─88
│ │ ccc6b27fbf7beb37e2b2dadceef08ed83a5716
│ │
│ ├─ce ←←←新規
│ │ 013625030ba8dba906f756967f9e9ca394464a
│ │
│ ├─e3 ←←←新規
│ │ d14d7340059b5852f32f29574e98ff73eb3c47
│ │
│ ├─info
│ └─pack
└─refs
├─heads
│ master
│
└─tags
-
objects
フォルダ配下の新規作成されたファイル3つ
~/Desktop/git/sample2 (master)
$ git cat-file -p ce013625030ba8dba906f756967f9e9ca394464a
hello
~/Desktop/git/sample2 (master)
$ git cat-file -p e3d14d7340059b5852f32f29574e98ff73eb3c47
100644 blob ce013625030ba8dba906f756967f9e9ca394464a sample.txt
~/Desktop/git/sample2 (master)
$ git cat-file -p 6cf4fd07bd3d1f982045f50fae9dc070d6967f36
tree e3d14d7340059b5852f32f29574e98ff73eb3c47
parent 023bd50171db535beab09fed56bd5a9281b01555
author hogehoge <fugafuga> 1699594574 +0900
committer hogehoge <fugafuga> 1699594574 +0900
second commit
ブロブとツリーとコミットのオブジェクトですね。
-
logs
フォルダ配下の更新されたファイルの差分
~/Desktop/git/sample2/.git (master)
$ git diff logs/
diff --git a/logs/HEAD b/logs/HEAD
index 8783cde..58d6c1d 100644
--- a/logs/HEAD
+++ b/logs/HEAD
@@ -1,2 +1,2 @@
0000000000000000000000000000000000000000 023bd50171db535beab09fed56bd5a9281b01555 hogehoge <fugafuga> 1699592736 +0900 commit (initial): first commit
+023bd50171db535beab09fed56bd5a9281b01555 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699594574 +0900 commit: second commit
diff --git a/logs/refs/heads/master b/logs/refs/heads/master
index 8783cde..58d6c1d 100644
--- a/logs/refs/heads/master
+++ b/logs/refs/heads/master
@@ -1,2 +1,2 @@
0000000000000000000000000000000000000000 023bd50171db535beab09fed56bd5a9281b01555 hogehoge <fugafuga> 1699592736 +0900 commit (initial): first commit
+023bd50171db535beab09fed56bd5a9281b01555 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699594574 +0900 commit: second commit
ログはこうやって書かれていくんですね。
-
refs
配下の更新されたファイルの差分
~/Desktop/git/sample2/.git (master)
$ git diff refs/
diff --git a/refs/heads/master b/refs/heads/master
index f1bb341..ed3d53b 100644
--- a/refs/heads/master
+++ b/refs/heads/master
@@ -1 +1 @@
-023bd50171db535beab09fed56bd5a9281b01555
+6cf4fd07bd3d1f982045f50fae9dc070d6967f36
master
ブランチの参照するコミットが移動しました。
git branch
次にgit branch
でブランチを作ってみましょう。
another
ブランチを作ります。
~/Desktop/git/sample2 (master)
$ git branch another
.git
フォルダの中はどうなったのでしょうか。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
logs/refs/heads/another
refs/heads/another
nothing added to commit but untracked files present (use "git add" to track)
2つファイルができました。見てみましょう。
$ cat refs/heads/another
6cf4fd07bd3d1f982045f50fae9dc070d6967f36
$ cat logs/refs/heads/another
0000000000000000000000000000000000000000 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699595907 +0900 branch: Created from master
refs/heads/another
はmaster
と同じコミットを指しています。
ログを見て確認しておきます。
~/Desktop/git/sample2 (master)
$ git log --oneline
6cf4fd0 (HEAD -> master, another) second commit
023bd50 first commit
git checkout
では、git checkout
してブランチを移動してみましょう。
another
ブランチに移動してみます。
~/Desktop/git/sample2 (master)
$ git checkout another
Switched to branch 'another'
~/Desktop/git/sample2 (another)
さて.git
はどうなるでしょうか。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: HEAD
modified: logs/HEAD
no changes added to commit (use "git add" and/or "git commit -a")
見ての通り、HEAD
とlogs/HEAD
が更新されてますね。
差分とってみます。
-
HEAD
ファイル
~/Desktop/git/sample2/.git (master)
$ git diff HEAD -- HEAD
diff --git a/HEAD b/HEAD
index cb089cd..b64c555 100644
--- a/HEAD
+++ b/HEAD
@@ -1 +1 @@
-ref: refs/heads/master
+ref: refs/heads/another
先ほど作成されたrefs/heads/another
ファイルを参照するように更新されてました。そりゃそうなんですが、HEAD
がanother
を参照するように更新されてますね。
再掲にはなりますが、refs/heads/another
は以下の内容でした。
$ cat refs/heads/another
6cf4fd07bd3d1f982045f50fae9dc070d6967f36
このことからHEAD
another
ブランチ コミット6cf4fd..
へと参照が続くように更新されてます。
-
logs/HEAD
ファイル
~/Desktop/git/sample2/.git (master)
$ git diff HEAD -- logs/HEAD
diff --git a/logs/HEAD b/logs/HEAD
index 58d6c1d..9bb9ffe 100644
--- a/logs/HEAD
+++ b/logs/HEAD
@@ -1,2 +1,3 @@
0000000000000000000000000000000000000000 023bd50171db535beab09fed56bd5a9281b01555 hogehoge <fugafuga> 1699592736 +0900 commit (initial): first commit
023bd50171db535beab09fed56bd5a9281b01555 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699594574 +0900 commit: second commit
+6cf4fd07bd3d1f982045f50fae9dc070d6967f36 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699596443 +0900 checkout: moving from master to another
これはHEAD
参照のログですね。こういう風にログをとってるんですね。
git merge
最後にgit merge
して.git
フォルダを観察してみます。
準備
(準備が長いので準備と観察する節をわけました)
まず準備としてanother
ブランチへ適当なコミットを作ります。
~/Desktop/git/sample2 (another)
$ echo "another" > sample.txt
~/Desktop/git/sample2 (another)
$ git add .
~/Desktop/git/sample2 (another)
$ git commit -m"third commit"
[another cbc33d4] third commit
1 file changed, 1 insertion(+), 1 deletion(-)
.git
フォルダの状態。特筆すべきところは特にないので、とりあえずコミットしておきます。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: COMMIT_EDITMSG
modified: index
modified: logs/HEAD
modified: logs/refs/heads/another
modified: refs/heads/another
Untracked files:
(use "git add <file>..." to include in what will be committed)
objects/11/
objects/9b/
objects/cb/
no changes added to commit (use "git add" and/or "git commit -a")
~/Desktop/git/sample2/.git (master)
$ git add .
~/Desktop/git/sample2/.git (master)
$ git commit -m"git commit 1回目@another"
[master d25acad] git commit 1回目@another
今度はmaster
ブランチにgit checkout
します。
~/Desktop/git/sample2 (another)
$ git checkout master
Switched to branch 'master'
.git
フォルダの状態。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: HEAD
modified: index
modified: logs/HEAD
no changes added to commit (use "git add" and/or "git commit -a")
~/Desktop/git/sample2/.git (master)
$ git add .
~/Desktop/git/sample2/.git (master)
$ git commit -m"git checkout後another→master"
[master c15e8de] git checkout後another→master
3 files changed, 2 insertions(+), 1 deletion(-)
another
ブランチでファイルを更新した状態から元のmaster
ブランチに戻ってきたので、「index」も更新されてますね。
マージ
さあ、another
ブランチをmaster
ブランチへgit merge
してみます。
~/Desktop/git/sample2 (master)
$ git merge --no-ff another
Merge made by the 'recursive' strategy.
sample.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
.git
フォルダの状態。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: index
modified: logs/HEAD
modified: logs/refs/heads/master
modified: refs/heads/master
Untracked files:
(use "git add <file>..." to include in what will be committed)
ORIG_HEAD
objects/bb/
no changes added to commit (use "git add" and/or "git commit -a")
新しくORIG_HEAD
とオブジェクトが生成されましたね。
見てみましょう。
$ cat ORIG_HEAD
6cf4fd07bd3d1f982045f50fae9dc070d6967f36
何のハッシュ値だっけこれ…。ということで、ログを確認してみます。
~/Desktop/git/sample2 (master)
$ git cat-file -p 6cf4fd07bd3d1f982045f50fae9dc070d6967f36
tree e3d14d7340059b5852f32f29574e98ff73eb3c47
parent 023bd50171db535beab09fed56bd5a9281b01555
author hogehoge <fugafuga> 1699594574 +0900
committer hogehoge <fugafuga> 1699594574 +0900
second commit
~/Desktop/git/sample2 (master)
$ git log --oneline --graph
* bb54bb5 (HEAD -> master) Merge branch 'another'
|\
| * cbc33d4 (another) third commit
|/
* 6cf4fd0 second commit
* 023bd50 first commit
ORIG_HEAD
が参照する6cf4fd
はmaster
ブランチの直前のコミットですね。
だからgit reset ORIG_HEAD --hard
でマージ前の状況に戻れるわけですね。
新たに生成されたオブジェクトはどういう内容でしょうか。
MINGW64 ~/Desktop/git/sample2 (master)
$ git cat-file -p bb54bb567fc99a85750561362e2dcd892f179434
tree 11982c20951b8249234a871fb7fce5983fe1465f
parent 6cf4fd07bd3d1f982045f50fae9dc070d6967f36
parent cbc33d4a1844fddc6f4dad5918897d00a6eaa80f
author hogehoge <fugafuga> 1699598971 +0900
committer hogehoge <fugafuga> 1699598971 +0900
Merge branch 'another'
2つの親のオブジェクトを参照するマージコミットのオブジェクトですね。
他の全ファイル見てるとくどくなるので、個人的な興味でlogs
配下のファイルだけ見てみます。
~/Desktop/git/sample2/.git (master)
$ git diff logs/
diff --git a/logs/HEAD b/logs/HEAD
index c43111f..eb4e0a5 100644
--- a/logs/HEAD
+++ b/logs/HEAD
@@ -4,3 +4,4 @@
6cf4fd07bd3d1f982045f50fae9dc070d6967f36 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699596443 +0900 checkout: moving from master to another
6cf4fd07bd3d1f982045f50fae9dc070d6967f36 cbc33d4a1844fddc6f4dad5918897d00a6eaa80f hogehoge <fugafuga> 1699598305 +0900 commit: third commit
cbc33d4a1844fddc6f4dad5918897d00a6eaa80f 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699598624 +0900 checkout: moving from another to master
+6cf4fd07bd3d1f982045f50fae9dc070d6967f36 bb54bb567fc99a85750561362e2dcd892f179434 hogehoge <fugafuga> 1699598971 +0900 merge another: Merge made by the 'recursive' strategy.
diff --git a/logs/refs/heads/master b/logs/refs/heads/master
index 58d6c1d..1256f4a 100644
--- a/logs/refs/heads/master
+++ b/logs/refs/heads/master
@@ -1,2 +1,3 @@
0000000000000000000000000000000000000000 023bd50171db535beab09fed56bd5a9281b01555 hogehoge <fugafuga> 1699592736 +0900 commit (initial): first commit
023bd50171db535beab09fed56bd5a9281b01555 6cf4fd07bd3d1f982045f50fae9dc070d6967f36 hogehoge <fugafuga> 1699594574 +0900 commit: second commit
+6cf4fd07bd3d1f982045f50fae9dc070d6967f36 bb54bb567fc99a85750561362e2dcd892f179434 hogehoge <fugafuga> 1699598971 +0900 merge another: Merge made by the 'recursive' strategy.
ログはそう書かれるわけね。
競合
では競合させるとどうなるのでしょう。
master
とanother
で同じファイルを適当に編集してみます。
説明:masterブランチでファイルを編集
~/Desktop/git/sample2 (master)
$ echo "master" > sample.txt
~/Desktop/git/sample2 (master)
$ git add .
~/Desktop/git/sample2 (master)
$ git commit -m"fourth commit"
[master 61dd6f5] fourth commit
1 file changed, 1 insertion(+), 1 deletion(-)
説明:anotherブランチでファイルを編集
~/Desktop/git/sample2 (master)
$ git checkout another
Switched to branch 'another'
~/Desktop/git/sample2 (another)
$ echo "another branch" > sample.txt
~/Desktop/git/sample2 (another)
$ git add .
~/Desktop/git/sample2 (another)
$ git commit -m"fifth commit"
[another bd61df7] fifth commit
1 file changed, 1 insertion(+), 1 deletion(-)
説明:masterブランチでマージするので移動
~/Desktop/git/sample2 (another)
$ git checkout master
Switched to branch 'master'
今こんな感じです。
~/Desktop/git/sample2 (master)
$ git log --graph --oneline --all
* bd61df7 (another) fifth commit
| * 61dd6f5 (HEAD -> master) fourth commit
| * bb54bb5 Merge branch 'another'
| |\
| |/
|/|
* | cbc33d4 third commit
|/
* 6cf4fd0 second commit
* 023bd50 first commit
さあ、マージして競合させてみます。
~/Desktop/git/sample2 (master)
$ git merge --no-ff another
Auto-merging sample.txt
CONFLICT (content): Merge conflict in sample.txt
Automatic merge failed; fix conflicts and then commit the result.
競合しました。.git
フォルダはどうなっているのでしょうか。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: ORIG_HEAD
modified: index
Untracked files:
(use "git add <file>..." to include in what will be committed)
MERGE_HEAD
MERGE_MODE
MERGE_MSG
objects/7a/
no changes added to commit (use "git add" and/or "git commit -a")
先ほどのマージの際にはなかったファイルが生成されてますね。
MERGE_HEAD
、MERGE_MODE
、MERGE_MSG
の中身を見ていきましょう。
$ cat MERGE_HEAD
bd61df78647648b52c932db29880eda9f0e6b72f
$ cat MERGE_MODE
no-ff
$ cat MERGE_MSG
Merge branch 'another'
# Conflicts:
# sample.txt
MERGE_HEAD
はマージされるブランチの最新コミットですね(今回で言うとanother
ブランチの最新コミット)。
7a
から始まるオブジェクトも生成されていますので中身を見てみます。
~/Desktop/git/sample2 (master)
$ git cat-file -p 7a67e00d6b7bee74c0f0ebdd167f22400ea80f9b
<<<<<<< HEAD
master
=======
another branch
>>>>>>> another
競合するとdiff形式のオブジェクトが生成されるんですね。
次に更新されたORIG_HEAD
です。
先ほどと同じく、マージする直前のコミットを指してます。
~/Desktop/git/sample2/.git (master)
$ git diff ORIG_HEAD
diff --git a/ORIG_HEAD b/ORIG_HEAD
index ed3d53b..6eb6ba5 100644
--- a/ORIG_HEAD
+++ b/ORIG_HEAD
@@ -1 +1 @@
-6cf4fd07bd3d1f982045f50fae9dc070d6967f36
+61dd6f56c96d9a3edef66cce619cf2915d76205e
--abort
すると.git
フォルダはどうなるんですかね。
--abort
した後の.git
フォルダの状況は以下のようになります。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: MERGE_HEAD
deleted: MERGE_MODE
deleted: MERGE_MSG
modified: index
modified: logs/HEAD
no changes added to commit (use "git add" and/or "git commit -a")
消えました。これらのファイルはマージが完了されても消えそうですね。
先ほどの競合を再現した後に、今度は競合を解消してマージしてみます。
競合の再現は省略します。↓競合発生後から競合解消までです。
~/Desktop/git/sample2 (master|MERGING)
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: sample.txt
no changes added to commit (use "git add" and/or "git commit -a")
~/Desktop/git/sample2 (master|MERGING)
$ git diff
diff --cc sample.txt
index 1f7391f,5d70384..0000000
--- a/sample.txt
+++ b/sample.txt
@@@ -1,1 -1,1 +1,5 @@@
++<<<<<<< HEAD
+master
++=======
+ another branch
++>>>>>>> another
~/Desktop/git/sample2 (master|MERGING)
$ echo "master" > sample.txt
~/Desktop/git/sample2 (master|MERGING)
$ git add .
~/Desktop/git/sample2 (master|MERGING)
$ git commit
[master 8254984] Merge branch 'another'
競合を解消して、マージコミットができました。
「.git」フォルダの状況はこうなります。
~/Desktop/git/sample2/.git (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: COMMIT_EDITMSG
deleted: MERGE_HEAD
deleted: MERGE_MODE
deleted: MERGE_MSG
modified: index
modified: logs/HEAD
modified: logs/refs/heads/master
modified: refs/heads/master
Untracked files:
(use "git add <file>..." to include in what will be committed)
objects/82/
no changes added to commit (use "git add" and/or "git commit -a")
--abort
と同じくMERGE_HEAD
、MERGE_MODE
、MERGE_MSG
は消えました。
また、マージコミットのオブジェクトが生成されています。
~/Desktop/git/sample2 (master)
$ git cat-file -p 8254984b906f193d27c2e4f55ee75991155bcedf
tree d9fd303cfe17e779b06fe84c97c970ba22253c4b
parent 61dd6f56c96d9a3edef66cce619cf2915d76205e
parent bd61df78647648b52c932db29880eda9f0e6b72f
author hogehoge <fugafuga> 1699601812 +0900
committer hogehoge <fugafuga> 1699601812 +0900
Merge branch 'another'
以上で、「.git」を「Git」に管理させてみる回は終わりです。
最後まで読んでくれた方ありがとうございました。
「index」ファイルについて補足
ここでかたくなに無視し続けたindex
ファイルについて補足です。
index
ファイルはバイナリファイルなので観察するのをやめてましたが、名前の通りindex
ファイルはインデックスの状態を表現するバイナリファイルです。ツリーオブジェクトと同じく、ツリーの参照とファイル名とブロブの対応を持つイメージです。
index
ファイルの作成と更新をまとめると以下のようになります。
-
git add
:初回のみindex
作成、その後は更新 -
git commit
:index
更新 -
git branch
:なにもなし -
git checkout
:なにもなし -
git merge
:index
更新
git add
するとindex
ファイルが更新されてgit commit
時にツリーオブジェクトが作成されることから、言い換えるとgit add
時はツリーオブジェクトは作成されずindex
ファイルの更新のみが行われます。git commit
でツリーオブジェクトが作成されてインデックスの内容も差し替えられます。
こうすることで、git add
した際は作業ディレクトリとインデックスの内容が一致して、git commit
時は作業ディレクトリとインデックスとリポジトリが一致してますね。
さいごに
コマンドを打ちながら記事を書きましたが、途中間違えたりして一部コマンド結果を改変して載せてますので、細かい箇所に間違いがあったらごめんなさい