1. 檢查版號指令
1 | git --version |
2. 使用者設定指令
1 | git config --global user.name "kite" |
如果不小心設定錯誤名稱,再執行同樣的指令,就可以接做修改囉。
3. 查看config
如果要找到實際檔案的修改位置以windows
來說在使用者目錄底下的.gitconfig
檔
或者下指令也是可以的
1 | git config --list |
4. 縮短指令
可以把常用的指令進行縮寫設定
1 | git config --global alias.co checkout |
設定完之後,之後就打指令git co
就可以代表git checkout
。這些設定儲存在.gitconfig
裡哦。
5. 刪除指令
以指令方式
1 | git config --global --unset alias.co |
或者去打開.gitconfig
t檔進行編輯也是可以的
6. 小技巧
1 | [alias] |
可以用 sample_code 的方式去抓一個固定的git 內容
code = !code ,只要前面加驚嘆號就是呼叫外部程式的方式
6.1. 常用指令參考
1 | [alias] |
7. 也可以在系統層級自創指令
~/.bash_profile
1 | alias hello="echo Hello Boudhayan!! How are you?" |
8. 也可以使用shell function 包裝git 指令
1 | function gcp() { |
1 | gcp "initial commit" |
可以參考 An intro to Git Aliases: a faster way of working with Git 這篇
9. 依專案設定使用者指令
1 | git config --local user.name Snow |
我們可以看到在專案底下的.git\config
檔案打開,這邊就多一個user
設定
10. 全新開始
1 | git init |
11. ⽬錄不想再被 Git 控制?
砍掉.git
資料夾就好囉
12. 確認目錄的狀態
這張圖有助於了解後續指令的相關概念
1 | git status |
增加或修改檔案預設會在Unstaged files
狀態
13. 追蹤檔案(stage file)
13.1. 所有檔
把目前所有更新的檔案都加入到Staged files
狀態可使用以下指令
1 | git add . |
1 | git add -A |
或者是
1 | git add --all |
其實 git add .
跟 git add -A
效果是不同的
13.2. 單個檔
git add file name
1 | git add index.html |
13.3. 多個檔
git add file1
file2
1 | git add index.html readme.md |
13.4. 針對副檔名批次追蹤
1 | git add *.html |
14. 提交到倉庫
1 | git commit -m "message" |
下完這個指令之後是提交到local repo 倉庫
15. 歷史記錄
1 | git log |
1 | git log --graph |
16. 如何自定指令
比如hexo 這樣
17. git 重要四個物件
blob
、tree
、commit
、tag
blob(binary large object)
查閱物件常用指令
1 | git cat-file<SHA1> |
1 | git cat-file -t |
1 | git cat-file -p |
1 | git cat-file -s |
17.1. commit 物件
舉例來說:
1 | kite-nb@DESKTOP-ORUP4EV MINGW64 ~/Downloads/gitTest/.git/objects (GIT_DIR!) |
17.2. tree 物件
舉例來說:
1 | kite-nb@DESKTOP-ORUP4EV MINGW64 ~/Downloads/gitTest/.git/objects (GIT_DIR!) |
18. 目前GIT 使用的是sha1的雜湊演算法
檔案內容碰撞的實例
1 | $ shasum shattered-* |
如果用 sha256
就不會碰撞
1 | $ shasum -a 256 shattered-* |
檔案名稱沒有碰撞
1 | $ git ls-files -s |
1 | $ git cat-file 8982 -p |
19. Git 裡的四種物件的關係
- 把檔案加入 Git 之後,檔案的內容會被轉成 Blob 物件儲存。
- ⽬錄以及檔名會存放在 Tree 物件內,Tree 物件會指向 Blob 物件,或是其它的 Tree 物
件。 - Commit 物件會指向某個 Tree 物件。除了第⼀個 Commit 之外,其它的 Commit 都會指向
前⼀次的 Commit 物件。 - Tag 物件(Annotated Tag)會指向某個 Commit 物件。
- 分⽀雖然不屬於這四個物件之⼀,但它會指向某個 Commit 物件。
- 當開始往 Git Server 上推送之後,在 .git/refs 底下就會多出⼀個 remote 的⽬錄,裡⾯
放的是遠端的分⽀,基本上跟本地的分⽀是差不多的概念,同樣也會指向某個 Commit 物
件。 - HEAD 也不屬於這四個物件之⼀,它會指向某個分⽀。
20. 垃圾回收機制
當每次使⽤ git add 指令把檔案加到暫存 區的時候,即使檔案的內容只改了⼀個字,因為算出來的 SHA-1 值不同,所以 Git 也會為它做 出⼀顆全新的 Blob 物件,⽽不是只記錄「差異」。也因為 Git 在切換 Commit 的時候會像「拎 葡萄」⼀樣整串抽出來,不需要⼀個⼀個去拼湊歷史紀錄,所以在做 Checkout 的時候效能相對 的比較好。有些⼈也會⽤快照(Snapshot)來形容這個「拎葡萄」的概念。
我們來了解一下目前的檔案狀況:
1 | git ls-files -s |
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (master) |
使用git gc
指令,進行手動回收垃圾,如下:
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (master) |
透過git verify-pack -v
查閱路徑objects/pack/
底下打包好的壓縮物件內容
1 | git verify-pack -v |
執行如下:
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (master) |
我們看這行56efbdba61ff12f90f864930b9a85eac0259666d blob 18 30 623 1 5bbd493e709d6f1d06c653ef6cc0df91f1b3a065
這個blob只有18btyes 檔案大小,原因是因為它參照了5bbd
這個blob 物件進行儲存,做到了類似差異備份的機制,因此檔案變小了。
最後,說明什麼時機點git 會自動執行gc的機制:
當在 .git/objects ⽬錄的物件或是打包過的 packfile 數量過多的時候,Git 會⾃動觸發資源回收指令。
當執⾏ git push 指令把內容推⾄遠端伺服器時(如果你有仔細觀察過 Push 指令的訊息的話…)。
話說回來,其實 Git 也不是真的很在意浪費空間這回事,反正現在硬碟這麼便宜,能夠快速、
有效率的操作才是 Git 關切的重點。
21. git branch
git branch(list and branches we have)
git branch
git branch -D
git branch –delete dev
git branch -m
21.1. 刪除分支
1 | git branch -d <branch_name> |
21.2. 強制刪除分支
1 | git branch -D <branch_name> |
22. git merge
先切換到master
分支,再下指令進行合併:
1 | git merge cat |
如果在master分支上都未做變動,進行merge時,會是fast-forward
(快轉)
如果在master分支上有做變動,進行merge時,會是3 ways merge
以sourcetree
進行操作
22.1. 快轉模式(fast-forward)情況下,還是想要有小耳朵
1 | git merge cat --no-ff |
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (master) |
sourcetree
方式
merge
、rebase
發生衝突時,具體步驟如下:
1.優先解決衝突檔案的內容修正
- 接著進行
git add
指令
3-1 git merge 的情境,則繼續下git commit
指令
3-2 git rebase的情境,指令為 git rebase --continue
ORIG_HEAD
Git 有另⼀個特別的紀錄點叫做 ORIG_HEAD ,當你在做⼀些比較「危險」的操作(例如像 merge 、 rebase 或 reset 之類的),Git 就會把 HEAD 的狀態存放在這裡,讓你隨時可以跳回危險動作之前的狀態。
git rebase
互動模式
1 | git rebase -i <commit_sha1> |
pick
:預設都是這個指令,代表會使用這個 Commit。reword
:使用這個 Commit,但是執行到此 Commit 時會開啟 vim 供更改 Commit 訊息。edit
:使用這個 Commit,但是執行到此 Commit 時會暫停,直到執行 git rebase –continue。squash
:將這個 Commit 與前一個 Commit 合併,訊息也會合併。fixup
:與 squash 相同,但會捨棄這個 Commit 的訊息。drop
:刪除這個 Commit,結果同直接刪除行。
23. 狀況題
23.1. 如果在 git add 之後⼜修改了那個檔案 的內容?
23.2. 我想要找某個⼈或某些⼈的 Commit
1 | git log --oneline --author="Sherly" |
23.3. 想找commit罵髒話
1 | git log --oneline --grep="WTF" |
23.4. 想找commit 提到ruby
1 | git log -S "Ruby" |
23.5. 看你早上commit 了什麼
1 | git log --oneline --since-="9am" --until="12am" --after="2017-01" |
23.6. 我不是真的想把這個檔案刪掉,只是不想讓這個檔案再被Git控管了
1 | git rm welcome.html --cached |
23.7. 修改Commit紀錄
要修改Commit紀錄有好幾種⽅法:
把.git⽬錄整個刪除(誤)。
使⽤
git rebase
來修改歷史。先把Commit⽤
git reset
拆掉,整理後再重新Commit。使⽤
--amend
參數來修改最後⼀次的Commit。1
git commit --amend -m "Welcome To Facebook"
雖然在commit 數上沒有變動,訊息上也更改了,但注意觀查其實在sha值上已經換過了,畢竟已經有做
修改
動作
23.8. 追加檔案到最近⼀次的Commit
先將目前的檔案加入到staged
狀態
1 | git add . |
接著下這個指令就會合併到最後一次commit 囉
1 | git commit --amend --no-edit |
在sourcetree
軟體部分,一樣使用amend last commit
,可以達到同樣的效果,合併到最後一次commit
23.9. 新增目錄卻沒有被追蹤?
請記得⼀件很重要的觀念,就是Git在計算、產⽣物件的時候,是根據「檔案的內容」去做計算的,所以光是新增⼀個⽬錄,Git是沒辦法處理它的。
如果需要git追蹤這個目錄的話可以在目錄底下加上.gitkeep
檔案
23.10. 有些檔案我不想放在Git裡⾯
可能的狀況
資料庫存取密碼
AWS伺服器的存取金鑰
程式編譯的中間檔或暫存檔(因為每次的編譯都會產生新檔,對於專案來說沒有利用價值)
要做到忽略追蹤要新增.gitignore
檔,填寫忽略規則
1 | #忽略secret.yml檔案 |
23.11. 可以忽略這個忽略嗎?
直接硬闖關
1 | git add -f 檔案名稱 |
23.12. 為什麼.gitignore 沒效果?
有一種狀況你先建了index.html 也commit 了。
之後再新增.gitignore 說忽略index.html,
這時如果去異動index.html,會發現還是會被追蹤。
如果是這樣的話,可以使用指令停止追蹤
1 | git rm --cached index.html |
對應sourcetree
軟體 是Stop Tracking
功能
23.13. 一口形清除忽略的檔案
如果想要⼀⼝氣清除那些已經被忽略的檔案,可以使⽤ git clean 指令並配合 -X 參數:
1 | git clean -fX |
那個額外加上的 -f 參數是指強制刪除的意思,這樣⼀來就可清除那些被忽略的檔案。
23.14. 新增檔案時,檔案還沒加入追蹤,想清空工作目錄
1 | git clean -f |
23.15. 檢視特定檔案的commit 記錄
1 | git commit index.html |
如果要看更詳細的可以加上p
1 | git commit -p index.html |
使用sourcetree
查看的方式,在檔案上右鍵找Log selected
23.16. 這行程式是誰寫的?
1 | git blame index.html |
如下:
1 |
|
如果行數太多,加上L
參數
1 | git blame -L 1,1 index.html |
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (main) |
在sourcetree
上的操作
23.17. 不小心把檔案或目錄刪掉了…
刪除檔案指令
1 | rm *.html |
指令過程
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (main) |
單一檔案救回指令
1 | git checkout index.html |
全數救回指令
1 | git checkout . |
sourcetree
還原某個檔案至前面的版本
1 | git checkout HEAD~2 index.html |
index.html
檔距離現今前二次的版本
距離現在兩個版本以前的那個 welcome.html 檔案來覆蓋現在的⼯作⽬錄裡的 welcome.html 檔案
1 | git checkout HEAD~2 . |
目前工作區
檔案距離現今前二次的版本
拿距離現在兩個版本以前的檔案來覆蓋現在⼯作⽬錄的檔案,同時也更 新暫存區裡的狀態
23.18. 剛才的commit 後悔了,想拆掉重做…
相對的作法
1 | git reset e12d8ef^ |
以這個object位置前往一次
如果要前往二次
以上,舉例來說五次的寫法如下
1 | git reset e12d8ef~5 |
以上的寫法也可以成寫
1 | git reset head~5 |
或
1 | git reset master~5 |
HEAD
、master
指針指向e12d8ef
情況下,效果是一樣的。
sourcetree
reset 三種模式
模式 | mixed模式 | soft模式 | hard模式 |
---|---|---|---|
commit 拆出來的檔案 | 丟回工作目錄 | 丟至暫存區 | 直接丟掉 |
23.19. 不小心使用hard模式reset了某個commit救得回來嗎?
git reset 之前的sha1 值就可以了,舉例來說:
1 | git reset a95148f --hard |
如果忘記、甚至沒記當時的sha1值,怎麼辦?
使用reflog
指令,執行如下:
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (master) |
試了很多次,所以會看到很多次reset資料,
當 HEAD
有移動的時候(例如切換分⽀或是 reset 都會造成 HEAD
移動),Git 就會在 Reflog
裡記上⼀筆。
git log 如果加上 -g 參數,也可以看到 Reflog 喔!
可以只commit 一個檔案的部分內容嗎?
使用 git add -p
方式,舉例如下:
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (master) |
這時候會開啟檔案,再將要刪掉的行數刪掉,儲存關掉即可。
sourcetree
23.20. 那如果改⼀半切換分⽀會發⽣什麼事?
舉例來說,在cat
分支時,新增了cat3.html
、修改index.html
檔案,這時切換分支至master
,結果仍保留之前在工作區
的更新檔案。
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (cat) |
不⼩⼼把還沒合併的分⽀砍掉了,救得回來嗎?
1 | kite@DESKTOP-I40U13Q MINGW64 /d/kite/tmp/test (master) |
當在刪除的時候,我們會看到後面有一個當時的sha1值。
如果真的不小心誤砍了,可以透過以下指令進行回復:
1 | git branch cat 6e34a |
如果真的連sha1值都記不下來,其實還是可以用git reflog
指令找出重要操作的log。(Reflog 預設會保留 30 天,所以 30 天內應該都還找得到)
24. 問題
24.1. 其實 git add .
跟 git add -A
效果是不同的
git add .
這個指令會把⽬前當下這個⽬錄,以及它的⼦⽬錄、⼦⼦⽬錄、⼦⼦⼦⽬ 錄…裡的異動全部加到暫存區,但在這個⽬錄的以外的就不歸它管了。
git add --all
就沒這個問題,這個指令不管在專案的哪⼀層⽬錄執⾏,效果都是⼀樣的,在這個專案裡所有 的異動都會被加⾄暫存區。
24.2. ⼀定要⼆段式嗎?
1 | git commit -a -m "update content" |
這樣即使沒有先 add 也可以完成 Commit。但要注意的是這個 -a 參數只對已經存在
Repository 的檔案有效,對還是新加入的檔案(也就是 Untracked file)是無效的。
25. 參考網站
An intro to Git Aliases: a faster way of working with Git
10 git aliases for a faster and productive git workflow
https://dev.to/lydiahallie/cs-visualized-useful-git-commands-37p1#merge
How to Animate Your Git Commit History with git-story
https://www.freecodecamp.org/news/animate-your-git-repo-with-git-story/
https://www.youtube.com/watch?v=3o_01F04bZ4&ab_channel=VisualStudioCode