---
# System prepended metadata

title: Git

---

# Git

## HEAD是什麼東西？
#### HEAD是一種**指標**，指向某一個分支，可以把HEAD當作『目前所在分支』。

![](https://i.imgur.com/GPMtH45.png)

`＄cat .git/HEAD`
`ref: refs/heads/master` 此時HEAD指向master分支

`$cat .git/refs/heads/master`
`874b6a091b25c03ab7ee22772c7c67df2d7e9faf` master檔案

## .git裡有什麼？
#### 四個物件分別為 **Blob物件** **Tree物件** **Commit物件** 與 **Tag物件**
步驟：
1. 建立檔案，而內部放入字串"Git test" `$echo "Git test" > index.html`
2. 將檔案加入暫存區域(Staging Area) `$git add index.html`
3. 計算"Git test"字串的SHA-1值 `$echo "Git test" | git hash-obje
ct --stdin`
![](https://i.imgur.com/o9nNlfl.png)
SHA-1值中前２個字為目錄(ed)，剩餘的３８個字是檔名
![](https://i.imgur.com/VGFnkpg.png)

`$git cat-file -t`知道型態
`$git cat-file -p`知道內容
![](https://i.imgur.com/UEczAY5.png)

##### git add運作流程
1. 加入暫存區後，會依據內容計算出SHA-1值
2. 會依照SHA-1值前２個字建立目錄，剩餘的則當成檔案名稱。並存放在.git/objects
3. 檔案的內容使用壓縮演算法，把原本內容壓縮後的結果
---
`$mkdir config` 建立一目錄 config
`$git status` 查詢目前狀態
![](https://i.imgur.com/1g4w8dO.png)
**空的目錄無法加入到Git之中**

![](https://i.imgur.com/fNmRipO.png)
`$touch config/database.yml`
但若此時在目錄內加入空檔案後，就會顯示在為追蹤檔案上

`$cat config/database.yml | git hash-object --stdin`
計算此檔案的SHA-1值後，獲得 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
檔案排列方式與前例相同，但目錄部分git又該如何記錄？

##### git commit
在執行commit之後，objects內則多了檔案
![](https://i.imgur.com/9E8XKU2.png)
`$git cat-file -t 06398e15e4966eb2762ce3c2af184a33810607fc` 回傳一個tree物件
`$git cat-file -p 06398e15e4966eb2762ce3c2af184a33810607fc`
![](https://i.imgur.com/uR0GRer.png)

![](https://i.imgur.com/0bY8XAq.png)
1. Git將檔案以Blob物件存放
2. 檔案名稱與目錄會以Tree物件存放
3. Tree物件內容指向某個Tree物件或者是Blob物件
由於這些物件之間並無上下層關係，因此此圖稱為[Directed Acyclic Graph(DAG)，有向無環圖](https://zh.wikipedia.org/zh-tw/%E6%9C%89%E5%90%91%E6%97%A0%E7%8E%AF%E5%9B%BE)

在剛剛commit過程中還有多一個檔案
`$git cat-file -t 6db6945f9f0267e374cc98702262b9942f72c33c` 回傳一個commit物件
`$git cat-file -p 6db6945f9f0267e374cc98702262b9942f72c33c` 內容為
![](https://i.imgur.com/5stRtAj.png)

![](https://i.imgur.com/UCwoFHQ.png)

Commit物件會指向Tree物件

---
##### 修改檔案內容
首先我們先將原本index.html內容進行修改，並且進行add與commit動作。
經過`$cat index.html | git hash-object --stdin`得到0341571e1a638abbf83330127f18f5cfde48f3f5

![](https://i.imgur.com/RuMbzT8.png)

查看檔案內多的物件內容

![](https://i.imgur.com/JpxeHSF.png)
會多了Tree物件跟Commit物件

![](https://i.imgur.com/MJclj4Q.png)

Commit物件會指向Tree以外還有前一個Commit物件

---

##### git tag
使用`$git tag -a tag_here -m"tag在這"`在當前Commit加上tag後
會在Objects資料夾多出檔案

![](https://i.imgur.com/B6VW1pR.png)

![](https://i.imgur.com/Z7edx5y.png)

---
#### 總結：
* 檔案在Git中會以Blob物件儲存
* 目錄和檔名會以Tree物件儲存。而Tree可以指向Blob物件或者其他Tree物件
* Commit物件會指向Tree物件，也會指向前一個Commit物件（如果不是第一個Commit的話）
* Tag物件會指向某個Commit物件
* 分支不屬於四大物件但會指向Commit物件
* HEAD不屬於四大物件，但會只向某個分支
* 當git push推送後，會在.git/refs底下多出remote目錄，裡面存放遠端分支，概念與本地相同