# git 實作練習 3 @ver 0.1.3 @date 2020-02-21 22:02:21 (星期5) @ver 0.1.2 @date 2019-04-13 23:21:03 (星期六) @ver 0.1.1 @date 2019-03-04 22:06:13 (星期一) 999. ## git 快速鍵 ### 省時省力快速鍵 以下好用的 git 全域簡捷快速鍵, 請先執行設定, 或者直接複製主機已設好的 `cp -fp /home/alex/.gitconfig ~/.gitconfig` 覆蓋自己的版本 > 如果使用 cp -fp 要再做一次 user.name, user.email 的設定, 否則會變成 alex > > git config --global user.name > > git config --global user.email #### 命令 ``` git config --global --replace-all core.pager "less -F -X" git config --global alias.a "add" git config --global alias.b "branch" git config --global alias.c "commit" git config --global alias.cm "commit -m" git config --global alias.ca "commit -a" git config --global alias.cam "commit -a -m" git config --global alias.co "checkout" git config --global alias.cob "checkout -b" git config --global alias.d "diff" git config --global alias.ds "diff --stat" git config --global alias.dc "diff --cached" git config --global alias.f "fetch" git config --global alias.i "init" git config --global alias.m "merge" git config --global alias.pu "push" git config --global alias.pl "pull" git config --global alias.s "status -s" git config --global alias.st "status" git config --global alias.l1 "log --oneline" git config --global alias.l "log --date=iso --pretty=format:'[%C(red)#%h%C(reset)] %C(bold blue)%cn%C(reset), %C(green)%cr%Creset : %C(yellow)%d%C(reset) %s'" git config --global alias.ld "log --date=iso --pretty=format:'[%C(red)#%h%C(reset)] %C(bold blue)%cn%C(reset), %C(green)%cd%Creset : %C(yellow)%d%C(reset) %s'" git config --global alias.ln "log --date=iso --numstat --pretty=format:'[%C(red)#%h%C(reset)] %C(bold blue)%cn%C(reset), %C(green)%cd%Creset : %C(yellow)%d%C(reset) %s'" git config --global alias.ls "log --date=iso --stat --pretty=format:'[%C(red)#%h%C(reset)] %C(bold blue)%cn%C(reset), %C(green)%cr%Creset : %C(yellow)%d%C(reset) %s'" git config --global alias.lg "log --date=iso --graph --pretty=format:'[%C(red)#%h%C(reset)] %C(bold blue)%cn%C(reset), %C(green)%cr%Creset : %C(yellow)%d%C(reset) %s'" git config --global alias.bx "for-each-ref --sort=-committerdate refs/heads/ --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - [%(color:red)%(objectname:short)%(color:reset)] %(authorname), (%(color:green)%(committerdate:relative)%(color:reset)) : %(contents:subject)'" git config --global alias.li "log --date=iso" ``` 999. ## revision range 釋疑 可以把它廣泛稱做 `修訂提交記錄範圍`, 許多命令及操作都會用到, 例如 `git log` 或 `git diff` ... 等 每一次提交, 就是一次 `revision`, 名詞, 中文翻譯為 `修訂` 或 `修正`. 而 `version` 比較偏向是 `版本`. 所以這裡用修訂. 隨著 git 提交次數變多, 三不五時需要查找過去的 commit 相關資訊或 diff 程式碼差異, 為了避免一次列出 `洛洛長` 太多資訊影響判斷, 我們用 `revision range` 來限制顯示或比對的範圍. ### **重要** : revision range 的符號簡介 * 數量 : 可加在任何 `revision range` 之後, -1 列出最近 1 個提交, -2 列出最近 2 個, -3 列出最近 3 個, -999 列出最近 999 個. 這個命令類似我們常用的 `head -88 filename` 或 `tail -33 filename`. * HEAD : 是一個象徵性的指標, 通常會指向某個 branch (master 也算 branch) 最近一次 commit 的內容, 基本上 HEAD 代表現在工作區的指標, 但在查詢 log 或 diff 時可能會用到其他(例如 : master, origin, origin/master, origin/HEAD). * HEAD^ : 後綴 ^ 往前 1 個提交, ^^ 往前 2 個, ^^^ 往前 3 個 * HEAD~1 : 後綴 ~1 往前 1 個提交, ~2 往前 2 個, ~3 往前 3 個 * HEAD@{1} : 後綴 @{1} 往前 1 個提交, @{2} 往前 2 個, @{3} 往前 3 個 * ^HEAD : 在 HEAD 之前的前綴 ^ 符號, 代表邏輯 not, 跟後綴功能不同, 比較像 regex * 空格 : 標示兩個指標的前後範圍, 從 A 到 B. * .. : 雙點語法, A..B (兩個點) 表示只在 B 有的. 它指定了兩個引用中的任何一個都可以訪問的所有提交, 但不能同時訪問它們. 回顧示例歷史記錄中的示例提交歷史記錄以進行範圍選擇. * ... : 三點語法, 指定範圍, A...B (三個點) 表示只在 A 或 B 其中一邊. 指定兩個引用中的任何一個都可以訪問的所有提交, 但不能同時訪問它們. ### 使用 `revision range` 查看 log `git log` 是用來查看修訂提交歷史記錄. 我們就邊查看 commit 提交 log, 邊學習 `revision range`, 以下都會使用 `~/.gitconfig` 設定的 `alias.l` 以方便驗證並檢視結果, 請務必先設定 #### 命令執行及結果說明 ```shell # 基本用法 git log # 最後一次提交, 反序列出到第一次, 直到永遠 git l # 使用 Alias 最後一次提交, 反序列出到第一次, 直到永遠 # 列出提交數量 git l -1 # 最後一次提交, 反序列出到第一次, 但只列出最近 1 個 git l -2 # 最後一次提交, 反序列出到第一次, 但只列出最近 2 個 git l -3 # 最後一次提交, 反序列出到第一次, 但只列出最近 3 個 git l -4 # 最後一次提交, 反序列出到第一次, 但只列出最近 4 個 git l -999 # 最後一次提交, 反序列出到第一次, 但只列出最近 999 個 # 後綴 ^ 符號, 從那一次提交開始 git l HEAD # 最後一次提交, 反序列出到第一次, 同 git l git l HEAD^ # 倒數第二次提交, 反序列出到第一次 git l HEAD^^ # 倒數第三次提交, 反序列出到第一次 git l HEAD^^^ # 倒數第四次提交, 反序列出到第一次 # 後綴 ~ 符號, 從那一次提交開始(同上) git l HEAD~3 # 倒數第四次提交, 反序列出到第一次, 同上 git l HEAD~999 # 倒數第 999 次提交, 反序列出到第一次 # 後綴 ^~ 符號 + 列出提交數量 git l HEAD -1 # 最後一次提交, 反序列出最近 1 個, 等同於 git l -1 git l HEAD -2 # 最後一次提交, 反序列出最近 2 個, 等同於 git l -2 git l HEAD^ -3 # 倒數第二次提交, 反序列出最近 3 個 git l HEAD~3 -4 # 倒數第四次提交, 反序列出最近 4 個 # 後綴 ^~ 符號 + 空格或雙點語法, 注意 : 在 HEAD 之前的前綴 ^ 代表邏輯 not git l HEAD~6..HEAD~1 # 倒數第二次提交, 倒數第六次結束, 反序列出最近 5 個 git l ^HEAD~6 HEAD~1 # 倒數第二次提交, 倒數第六次結束, 反序列出最近 5 個 git l HEAD~1 --not HEAD~6 # 倒數第二次提交, 倒數第六次結束, 反序列出最近 5 個 git l HEAD~1..HEAD~6 # 不顯示 git l ^HEAD~1 HEAD~6 # 不顯示 git l HEAD~6 --not HEAD~1 # 不顯示 # 後綴 ^~ 符號 + 三點語法 git l HEAD~6...HEAD~1 # 倒數第二次提交, 倒數第六次結束, 反序列出最近 5 個 git l HEAD~1...HEAD~6 # 倒數第二次提交, 倒數第六次結束, 反序列出最近 5 個, 同上 git l HEAD~6...HEAD~6 # 不顯示 ``` 999. ## git log 探索 ### 標準 commit 訊息 `log` 是 `修訂提交歷史記錄` 的檢閱器, 我們先分析它的標準 commit 訊息 #### 命令 ```bash git log [各式各樣的參數] ``` #### 執行結果 ```shell [alex@nvda /tmp/prj1 ]$ git log 1 commit 821764e6ecfc1b3d6dafba18361a5d8f1e494af8 2 Author: alex 3 Date: Fri Mar 1 13:48:47 2019 +0800 4 5 從暫存區(索引)移除不要追踪的檔案 6 7 commit cd002dc3023c214120b3eb9e50a177d28a66fb26 8 Author: alex 9 Date: Fri Mar 1 10:44:21 2019 +0800 10 11 實測 .gitignore 完成 12 13 commit f2ed5d757c9a81de0d1ccd601af1e4a6a48333e4 14 Author: alex 15 Date: Tue Feb 19 16:24:19 2019 +0800 16 17 第一次提交到 git repo [alex@nvda /tmp/prj1 ]$ ``` #### 訊息解釋 ```plaintext 每一組 log 有多行, 包括幾個資訊 第一行 commit 後面是 40 bytes 的 SHA1 Hash. 第二行 Author: 是作者姓名及他的電子郵件, 這個值在 git config --global 設定過. 第三行 Date: 日期, 目前是預設美式日期時間格式. Tue Feb 19 16:24:19 2019 +0800 第四行空行, 接著好幾行是我們提交訊息, 最後再接一個空行. ``` ### 簡易 commit 訊息 為了快速方便查閱, 有很多格式可以設定簡化的顯示訊息, [參考 Git 基礎 - 檢視提交的歷史記錄](https://git-scm.com/book/zh-tw/v1/Git-基礎-檢視提交的歷史記錄) 以下兩個常用範例, 我們已定義在先前的 `git config --global` 裡的 `alias.l` 跟 `alias.ld`, 主要是時間顯示方式, 各有方便之處 #### 命令 ```bash git l [各式各樣的參數] ``` #### 執行結果 ```shell [alexkuo : /tmp/prj1 ] ➠ $ git l 1 [#821764e] alex, 6 weeks ago : (HEAD -> master) 從暫存區(索引)移除不要追踪的檔案 2 [#cd002dc] alex, 6 weeks ago : 實測 .gitignore 完成 3 [#f2ed5d7] alex, 8 weeks ago : 第一次提交到 git repo [alexkuo : /tmp/prj1 ] ➠ $ ``` #### 訊息解釋 ```plaintext 簡化單行之一 log 有 4 或 5 個部份 1. 七碼 HASH : [#821764e] 中括號#為 SHA1 Hash 前七碼 2. 姓名 : alex 為提交者姓名 3. 時間 : 6 weeks ago , 提交時的時間, 但用相對於現在的時間多久來顯示 4. (HEAD -> master) : git HEAD 索引位置指示, 只有第一個會有 5. 提交內容 : 提交內容的第一行, 如果有多行, 也只會顯示第一行 ``` #### 命令 ```bash git ld [各式各樣的參數] ``` #### 執行結果 ```shell [alexkuo : /tmp/prj1 ] ➠ $ git ld 1 [#821764e] alex, 2019-03-01 13:48:47 +0800 : (HEAD -> master) 從暫存區(索引)移除不要追踪的檔案 2 [#cd002dc] alex, 2019-03-01 10:44:21 +0800 : 實測 .gitignore 完成 3 [#f2ed5d7] alex, 2019-02-19 16:24:19 +0800 : 第一次提交到 git repo [alexkuo : /tmp/prj1 ] ➠ $ ``` #### 訊息解釋 ```plaintext 簡化單行之二 log 有 4 或 5 個部份 1. 七碼 HASH : [#821764e] 中括號#為 SHA1 Hash 前七碼 2. 姓名 : alex 為提交者姓名 3. 時間 : 2019-03-01 13:48:47 +0800 , 提交時的時間, 用 iso 格式顯示 4. (HEAD -> master) : git HEAD 索引位置指示, 只有第一個會有 5. 提交內容 : 提交內容的第一行, 如果有多行, 也只會顯示第一行 ``` 999. ## git diff 第一次接觸 ### 基本操作說明 `diff` 用來檢視文件差異 #### 命令 ```bash git diff [各式各樣的參數] ``` ### 工作區已提交到最後版本 #### 命令 ```bash git diff git diff HEAD ``` #### 執行結果 ```shell [alex@nvda ~/ak1 ]$ git diff [alex@nvda ~/ak1 ]$ git diff HEAD [alex@nvda ~/ak1 ]$ ``` 這兩個命令都相同, 表示現在工作區跟最後一次提交的差異, 因為最後版本已提交, 又沒有任何修改, 所以 git 沒有任何回應. 也就是說最後一個參數若為空白, 等同於指向 `HEAD` 現在修改 `routes/web.php` `resources/views/abcd.blade.php` 這兩個檔, 再做一次 `diff` #### 命令 ```bash vi routes/web.php vi resources/views/abcd.blade.php vi resources/views/my.blade.php git diff ``` #### 執行結果 ``` [alex@nvda ~/ak1 ]$ git diff 1 diff --git a/resources/views/abcd.blade.php b/resources/views/abcd.blade.php 2 index d5e6c3e..b42885c 100644 3 --- a/resources/views/abcd.blade.php 4 +++ b/resources/views/abcd.blade.php 5 @@ -1 +1,2 @@ 6 -你好, 我是 ben 7 +你好, 我不是 ben 8 +

這是測試

9 diff --git a/routes/web.php b/routes/web.php 10 index 643ecee..0444bda 100644 11 --- a/routes/web.php 12 +++ b/routes/web.php 13 @@ -15,7 +15,7 @@ Route::get('/', function () { 14 return view('welcome'); 15 }); 16 17 -Route::get('/a', function () { 18 +Route::get('/abcd', function () { 19 return view('abcd'); 20 }); 21 [alex@nvda ~/ak1 ]$ $ ``` #### 訊息解釋 ```plaintext 每一組檔案區塊都從 diff --git 開始, 有幾個基本資訊 : 1 diff --git a/resources/views/abcd.blade.php b/resources/views/abcd.blade.php 第一行 diff --git 後面是兩組檔名, a/... 指向最後提交 HEAD 的檔案, b/... 則是工作區檔案 2 index d5e6c3e..b42885c 100644 第二行 index ... 檔案編碼記號, 暫時不用看它 3 --- a/resources/views/abcd.blade.php 第三行 (舊)最後提交在 HEAD 的檔案 4 +++ b/resources/views/abcd.blade.php 第四行 (新)現在工作區的檔案 5 @@ -1 +1,2 @@ 第五行 段落新舊差異位置指引 6 -你好, 我是 ben 7 +你好, 我不是 ben 8 +

這是測試

第六行~第八行 第一個字元 '-' 舊檔案的內容, '+' 新檔案的內容, 這裡表示刪掉第六行, 增加了第七, 八行 一個檔案可能有很多段差異, 都是從 [段落新舊差異位置指引] 的 [@@ ...... @@] 開始 在顯示差異時, 可能會有一些第一個字元不是 '-' 也不是 '+', 代表兩個檔案相同的地方, diff 是用行為單位來比對 9 diff --git a/routes/web.php b/routes/web.php 第九行 又是新的一個檔案差異開始 ``` 剛剛這個指令, 並沒有下任何參數, 預設值就是 `現在工作區` 跟 `最後一次提交(HEAD)` 的所有檔案差異比對 ### 指定檔案差異比對 #### 命令 ```bash git diff routes/web.php ``` #### 執行結果 ```shell [alex@nvda ~/ak1 ]$ git diff routes/web.php 1 diff --git a/routes/web.php b/routes/web.php 2 index 643ecee..0444bda 100644 3 --- a/routes/web.php 4 +++ b/routes/web.php 5 @@ -15,7 +15,7 @@ Route::get('/', function () { 6 return view('welcome'); 7 }); 8 9 -Route::get('/a', function () { 10 +Route::get('/abcd', function () { 11 return view('abcd'); 12 }); 13 [alex@nvda ~/ak1 ]$ $ ``` ### 增加 `revision range` 差異比對, 第一次只設定多一個 HEAD #### 命令 ```bash git diff HEAD ``` #### 執行結果 ```shell [alex@nvda ~/ak1 ]$ git diff HEAD 1 diff --git a/resources/views/abcd.blade.php b/resources/views/abcd.blade.php 2 index d5e6c3e..b42885c 100644 3 --- a/resources/views/abcd.blade.php 4 +++ b/resources/views/abcd.blade.php 5 @@ -1 +1,2 @@ 6 -你好, 我是 ben 7 +你好, 我不是 ben 8 +

這是測試

9 diff --git a/resources/views/my.blade.php b/resources/views/my.blade.php 10 new file mode 100644 11 index 0000000..cf0bcd3 12 --- /dev/null 13 +++ b/resources/views/my.blade.php 14 @@ -0,0 +1,2 @@ 15 +
測試差異
16 +

第二段

17 \ No newline at end of file 18 diff --git a/routes/web.php b/routes/web.php 19 index 643ecee..0444bda 100644 20 --- a/routes/web.php 21 +++ b/routes/web.php 22 @@ -15,7 +15,7 @@ Route::get('/', function () { 23 return view('welcome'); 24 }); 25 26 -Route::get('/a', function () { 27 +Route::get('/abcd', function () { 28 return view('abcd'); 29 }); 30 [alex@nvda ~/ak1 ]$ $ ``` 看起來跟 `git diff` 相同, 但又有點不同, 仔細比較, 才發現多了新建立的 `resources/views/my.blade.php` 檔案差異比對, 其實這可看可以不看, 因為既然是新的, 找不到舊檔, 也沒什麼好比對. 但是它還是不辭辛勞的把它列出來. ### 增加 `revision range` 差異比對, 第二次改用 `HEAD^ HEAD` 兩個 `HEAD^` 就是比對上次(倒數第二次)提交, 跟 `HEAD` 最後(倒數第一次)提交的檔案差異. 習慣把更舊的版本放前面, 較新的版本放後面, 看到記號 `-` 開頭的那一行就當作刪掉內容, 記號 `+` 開頭的那一行就當作新增內容. #### 命令 ```bash git diff HEAD^ HEAD ``` #### 執行結果 ```shell [alex@nvda ~/ak1 ]$ git diff HEAD^ HEAD 1 diff --git a/resources/views/abcd.blade.php b/resources/views/abcd.blade.php 2 new file mode 100644 3 index 0000000..d5e6c3e 4 --- /dev/null 5 +++ b/resources/views/abcd.blade.php 6 @@ -0,0 +1 @@ 7 +你好, 我是 ben 8 diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php 9 index 599264c..5ba7e32 100644 10 --- a/resources/views/welcome.blade.php 11 +++ b/resources/views/welcome.blade.php 12 @@ -82,6 +82,7 @@ 13
14
15 Alex's Laravel 16 + 17
18 19