# git 操作跟觀念
## 最重要的concept
- 所有紀錄檔案都可以在.git底下找到
- <font color="#f00">head決定現在的位置,head跟branch一樣都是一個指針指到某一個commit,head決定現在的branch在哪</font>
- <font color="#f00">checkout回去到某一個commit,很容易發生斷頭,若想在某一次commit作更改,記得要開一個branch並且checkout過去來紀錄</font>
- info底下有一個exclude檔案,功用類似.gitignore,但不會push到遠端被別人看到你阻擋哪些東西上傳到遠端
- objects存放各個object的地方
- branchs紀錄branch
- refs放heads跟tag,heads此資料夾底下放各個branch的head
branch就像是一個tag連接在commit身上而已,但跟一般tag不同的是當你在此branch上commit時,branch會跟著你的commit前進
而相對於branch,tag單存是跟某一個commit綁在一起的,並不會跟著commit往前而有所變動
### git 儲存方式
- git並不是利用diff的方式來紀錄每一個commit,而是針對每一個commit裡有跟動過的檔案,自己額外會在作sha壓縮並且存放在.git/object底下
- 當檔案太大或有commit推到遠端的時候,git才會利用diff的方式對資料進行壓縮,減少空間利用
### 查看objects
可以利用
```shell=
git cat-file -p ${sha value}
#可以得到裡面的value
git cat-file -t ${sha value}
#可以得到所屬型態
```
.git/objects/底下會使用前兩個sha的value當作資料夾名稱,裡面檔案名稱則是剩下的sha value,因此當你要得到sha value,必須將資料夾名稱跟此資料夾中的檔案名稱相加起來
### 4 git type
下面這幾個type都紀錄在.git/objects/底下
- blob:物件內容
- tree:資料夾,內容會指到資料夾裡面的物件(可能有多個物件,故此檔案可能有多行)
- commit:也是一個檔案會指到所有跟此commit有關的檔案
***指到的意思:在檔案中會存著這些資料的sha value
- tag:針對某一個commit給一個標籤
### tag
<font color="#f00">常使用在設立某一個里程碑</font>
```shell=
#列出所有標籤
git tag -l "v1.8.5*"
#針對現在這個commit
#big treasure只是一個tag,{$commit content}是commit內容
git tag -a big_treasure -m {{$commit content} ex:"這個commit真棒"}
#針對過去的commit貼標籤
git tag -a v1.2 9fceb02
#將tag貼到遠端
git push origin v1.5
#將所有tags貼到遠端
git push origin --tags
#在某個標籤上開分支
git checkout -b version2 v2.0.0
```
### index
index就是save buffer(緩衝區,在add跟commit之間)
已經add但還沒commit之間會有一個buffer存放準備已經紀錄的資料
可以利用git ls-files查看已經紀錄哪些file進去
### others
- 當檔案為空的時候,"git add某個空的檔案"此指令並不會在.git/objects/下面再新增新的資料夾
- head可以利用@代替
- head前一個commit可以使用此符號@^作代替
## 回到merge,rebase(危險操作)之前的狀態
<font color="#f00">如果才剛merge或rebase可以使用</font>
ORIG_HEAD是在做merge或rebase之前,git會先把head的狀態存在這個到ORIG_HEAD
因此可以利用此方法回溯到危險動作之前的狀態
```shell=
git reset ORIG_HEAD --hard
```
### 想修改最新一次的commit 名稱
```shell=
git commit --amend -m "xxxx"
```
<font color="#f00">注意:對於不同branch,最新的commit都算是自己branch上的</font>
### branch
```shell=
git branch ${name}
#checkout到那個branch
git checkout ${name}
#delete this branch
git branch ${name} -d
#在當前此branch merge 其他的branch
git merge ${branch name}
```
### git stash
有時會不想commmit,但必須立馬切換到某一個commit,這時可以使用stash方式暫時把修改的東西暫存起來
```shell=
#存到stash stack裡面
git stash
#列出所有stash的紀錄
git stash list
#pop出,2換成自己要的數字
git stash pop stash@{2}
#確定不要的
git stash drop stash@{0}
#這個跟pop不一樣的地方在於他不會從stash stack裡刪除,但pop會,所以stack裡面還會有一份
git stash apply stash@{0}
```
### calculate sha value
```shell=
cat ${filepath} | git hash-object --stdin
```
### git alias
```
#put this code on ~/.gitconfig
[alias]
ll = log --graph --pretty=format:\"%h <%an> %ar%n comment: %s%n\"
la = log --graph --oneline --all
ls = log --graph --oneline
```
### log
顯示所有commit
```shell=
git log --oneline
```
### diff
```shell=
#比對兩個commit
git diff ${commit id} ${commit id}
#比對目前目前HEAD所指的這個commit之間跟此commit id之間的差異
git diff ${commit id}
#比對工作目錄跟暫存區之間的差異
git diff
#目前暫存區與HEAD所指向的那個commit之間的差異。
git diff --cached
```
### pull
```shell=
git add .
git commit -m "自訂的檔案名稱"
git pull oringin master
```
### push
```shell=
git add .
git commit -m "自訂的檔案名稱"
git push oringin master
```
### 想要將某一個東西(或修改)加入到最新的commit
有時會忘記有些東西要加入到前一次commit中(最新的commit),這時可以利用下面此方法加進去
```shell=
git add ${filepath}
#no-edit代表不要改變git commit 訊息
git commit --amend --no-edit
```
###### tags: `git`