57
40

【Git】「.git」の中をGitに管理させてみた

Last updated at Posted at 2023-12-02

はじめに

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つ使っているので、切り替えがわかりにくい箇所があると思いますがご容赦ください:bow:

準備

  • 「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フォルダと比較すると、新しくindexobjects配下の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

.gitgit 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フォルダの中身が色々変わってきました。:arrow_down: .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/HEADlogs/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

どうやら、直前のコミットメッセージを保存しているファイルのようです。
もう察しがつくと思いますが、他のファイルも一応見ていきましょうか。
:arrow_down: 今の.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/anothermasterと同じコミットを指しています。
ログを見て確認しておきます。

~/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")

見ての通り、HEADlogs/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ファイルを参照するように更新されてました。そりゃそうなんですが、HEADanotherを参照するように更新されてますね。
再掲にはなりますが、refs/heads/anotherは以下の内容でした。

$ cat refs/heads/another
6cf4fd07bd3d1f982045f50fae9dc070d6967f36

このことからHEAD :arrow_right: anotherブランチ :arrow_right: コミット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が参照する6cf4fdmasterブランチの直前のコミットですね。
だから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.

ログはそう書かれるわけね。

競合

では競合させるとどうなるのでしょう。
masteranotherで同じファイルを適当に編集してみます。

説明: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_HEADMERGE_MODEMERGE_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_HEADMERGE_MODEMERGE_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時にツリーオブジェクトが作成されることから、言い換えるとgit add時はツリーオブジェクトは作成されずindexファイルの更新のみが行われます。git commitでツリーオブジェクトが作成されてインデックスの内容も差し替えられます。
こうすることで、git addした際は作業ディレクトリとインデックスの内容が一致して、git commit時は作業ディレクトリとインデックスとリポジトリが一致してますね。

さいごに

コマンドを打ちながら記事を書きましたが、途中間違えたりして一部コマンド結果を改変して載せてますので、細かい箇所に間違いがあったらごめんなさい:pray:

57
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
40