git 實作練習 3

@ver 0.1.2 @date 2019-04-13 23:21:03 (星期六)

@ver 0.1.1 @date 2019-03-04 22:06:13 (星期一)

  1. 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"
  2. revision range 釋疑

    可以把它廣泛稱做 修訂提交記錄範圍, 許多命令及操作都會用到, 例如 git loggit diff ... 等

    每一次提交, 就是一次 revision, 名詞, 中文翻譯為 修訂修正. 而 version 比較偏向是 版本. 所以這裡用修訂. 隨著 git 提交次數變多, 三不五時需要查找過去的 commit 相關資訊或 diff 程式碼差異, 為了避免一次列出 洛洛長 太多資訊影響判斷, 我們用 revision range 來限制顯示或比對的範圍.

    重要 : revision range 的符號簡介

    • 數量 : 可加在任何 revision range 之後, -1 列出最近 1 個提交, -2 列出最近 2 個, -3 列出最近 3 個, -999 列出最近 999 個. 這個命令類似我們常用的 head -88 filenametail -33 filename.
    • HEAD : 是一個象徵性的指標, 通常會指向某個 branch (master 也算 branch) 最近一次 commit 的內容, 基本上 HEAD 代表現在工作區的指標, 但在查詢 log 或 diff 時可能會用到其他(例如 : master, origin, origin/master, origin/HEAD).
      • HEAD^ : 後綴 ^ 往前 1 個提交, ^^ 往前 2 個, ^^^ 往前 3 個
      • HEAD~1 : 後綴 ~1 往前 1 個提交, ~1 往前 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 以方便驗證並檢視結果, 請務必先設定

    命令執行及結果說明

    # 基本用法
    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                   # 不顯示
  3. git log 探索

    標準 commit 訊息

    log修訂提交歷史記錄 的檢閱器, 我們先分析它的標準 commit 訊息

    命令

    git log [各式各樣的參數]

    執行結果

    [alex@nvda /tmp/prj1 ]$ git log
          1 commit 821764e6ecfc1b3d6dafba18361a5d8f1e494af8
          2 Author: alex <alex@forblind.org.tw>
          3 Date:   Fri Mar 1 13:48:47 2019 +0800
          4
          5     從暫存區(索引)移除不要追踪的檔案
          6
          7 commit cd002dc3023c214120b3eb9e50a177d28a66fb26
          8 Author: alex <alex@forblind.org.tw>
          9 Date:   Fri Mar 1 10:44:21 2019 +0800
         10
         11     實測 .gitignore 完成
         12
         13 commit f2ed5d757c9a81de0d1ccd601af1e4a6a48333e4
         14 Author: alex <alex@forblind.org.tw>
         15 Date:   Tue Feb 19 16:24:19 2019 +0800
         16
         17     第一次提交到 git repo
    [alex@nvda /tmp/prj1 ]$

    訊息解釋

    每一組 log 有多行, 包括幾個資訊
    第一行 commit 後面是 40 bytes 的 SHA1 Hash.
    第二行 Author: 是作者姓名及他的電子郵件, 這個值在 git config --global 設定過.
    第三行 Date: 日期, 目前是預設美式日期時間格式. Tue Feb 19 16:24:19 2019 +0800
    第四行空行, 接著好幾行是我們提交訊息, 最後再接一個空行.

    簡易 commit 訊息

    為了快速方便查閱, 有很多格式可以設定簡化的顯示訊息, 參考 Git 基礎 - 檢視提交的歷史記錄

    以下兩個常用範例, 我們已定義在先前的 git config --global 裡的 alias.lalias.ld, 主要是時間顯示方式, 各有方便之處

    命令

    git l [各式各樣的參數]

    執行結果

    [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 ] ➠ $

    訊息解釋

    簡化單行之一 log 有 4 或 5 個部份
    1. 七碼 HASH : [#821764e] 中括號#為 SHA1 Hash 前七碼
    2. 姓名 : alex 為提交者姓名
    3. 時間 : 6 weeks ago , 提交時的時間, 但用相對於現在的時間多久來顯示
    4. (HEAD -> master) : git HEAD 索引位置指示, 只有第一個會有
    5. 提交內容 : 提交內容的第一行, 如果有多行, 也只會顯示第一行

    命令

    git ld [各式各樣的參數]

    執行結果

    [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 ] ➠ $

    訊息解釋

    簡化單行之二 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. 提交內容 : 提交內容的第一行, 如果有多行, 也只會顯示第一行
  4. git diff 第一次接觸

    基本操作說明

    diff 用來檢視文件差異

    命令

    git diff [各式各樣的參數]

    工作區已提交到最後版本

    命令

    git diff
    git diff HEAD

    執行結果

    [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

    命令

    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 +<p>這是測試</p>
          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 ]$ $

    訊息解釋

    每一組檔案區塊都從 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 +<p>這是測試</p>
    第六行~第八行 第一個字元 '-' 舊檔案的內容, '+' 新檔案的內容, 這裡表示刪掉第六行, 增加了第七, 八行
    一個檔案可能有很多段差異, 都是從 [段落新舊差異位置指引] 的 [@@ ...... @@] 開始
    在顯示差異時, 可能會有一些第一個字元不是 '-' 也不是 '+', 代表兩個檔案相同的地方, diff 是用行為單位來比對
          9 diff --git a/routes/web.php b/routes/web.php
    第九行 又是新的一個檔案差異開始

    剛剛這個指令, 並沒有下任何參數, 預設值就是 現在工作區最後一次提交(HEAD) 的所有檔案差異比對

    指定檔案差異比對

    命令

    git diff routes/web.php

    執行結果

    [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

    命令

    git diff HEAD

    執行結果

    [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 +<p>這是測試</p>
          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 +<div>測試差異</div>
         16 +    <p>第二段</p>
         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 最後(倒數第一次)提交的檔案差異. 習慣把更舊的版本放前面, 較新的版本放後面, 看到記號 - 開頭的那一行就當作刪掉內容, 記號 + 開頭的那一行就當作新增內容.

    命令

    git diff HEAD^ HEAD

    執行結果

    [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              <div class="content">
         14                  <div class="title m-b-md">
         15                      Alex's Laravel
         16 +                    <span>改</span>
         17                  </div>
         18
         19                  <div class="links">
         20 diff --git a/routes/web.php b/routes/web.php
         21 index 810aa34..643ecee 100644
         22 --- a/routes/web.php
         23 +++ b/routes/web.php
         24 @@ -14,3 +14,8 @@
         25  Route::get('/', function () {
         26      return view('welcome');
         27  });
         28 +
         29 +Route::get('/a', function () {
         30 +    return view('abcd');
         31 +});
         32 +
    [alex@nvda ~/ak1 ]$ $

    訊息解釋

    在這兩次不同提交裡, 三個不同檔案的 diff 結果
          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
    第二行 因為剛好 a/resources/views/abcd.blade.php 是新的檔案, 所以會有顯示 new file mode 100644
    第四行 --- /dev/null 表示此檔案, 舊的 HEAD^ 那一階段並不存在
    第五行 +++ b/resources/views/abcd.blade.php 新檔案, 提交在 HEAD 裡
  5. 編寫優良的 git 提交訊息

    原文網頁

    參考 : 撰寫有效的-git-commit-message

    使用 git 提交 (commit) 程式碼修訂時, 有沒有思考一下好好的寫提交訊息嗎 ? 讓工作伙伴看得懂你的修改目的 ?

    文章作者建議好的 git 提交訊息要包含

    1. { style=list-style-type:decimal; } 主旨(Subject) : 必填, 一小段簡短的總結, 小於 50 個字元, 就像電子郵件的主旨一樣, 例如 修正部份會員無法登入完成信用卡刷卡 API工作中...
    2. 說明(Body) : 不一定要有, 主要是寫變更了那些? 為何變更? 建議每行少於 72 個字元, 儘可能詳細, 可以多寫幾行.
    3. 結尾(Bottom line) : 不一定要有, 如果使用問題追踪系統, 這裡可以寫解決了那一個問題的問題編號, 例如 Resolves #N / Closes #N, N 是問題編號.

    作者示範 git commit 的訊息, 如下

    原文訊息

    Fix error when protocol is missing
    
    First, it checks if the protocol is set. If not, it changes the url and
    add the basic http protocol on the beginning.
    Second, it does a "preflight" request and follows all redirects and
    returns the last URL. The process then continues with this URL.
    
    Resolves #17

    訊息對照說明

    第 1 行, `Fix error ...` 是主旨
    第 2 行, 空行, 分隔主旨跟說明
    第 3~6 行, 說明, 清楚描述此次做了那些修正
    第 7 行, 空行, 分隔說明跟結尾
    第 8 行, 結尾, 寫出解決問題編號 #17

    中文翻譯

    修正有時 protocol 協議消失的錯誤
    
    1. 檢查 protocol 是否已設定. 如果沒有, 變更 url 並
    在開始時增加基本 http protocol.
    2. 執行 "preflight" 並跟隨所有重導向及
    返回到最後. 此程序會持續在此 URL 作業
    
    解決 #17

    不良的提交訊息示範

    下列訊息, 很簡短, 但不夠有力, 可能只有提交的人才知道改了什麼

    訊息主旨

    cd3e27a contact page
    aee9d0d comments
    eac95e5 list of online users, some other changes because of server
    fae5636 little edit

    優良的提交訊息示範

    以下這些訊息, 雖然簡短, 但看起來還可理解, 請參考

    訊息主旨

    43ec6aa Fix error when the URL is not reachable
    4fe84ab Add error message if something went wrong
    753aa05 Add server fingerprint check
    df3a662 Fix shadow box closing problem
  6. 版本字號

    維基 - 軟體版本號

    主版本號.子版本號[.修正版本號[.編譯版本號]]

    Major.Minor[.Revision[.Build]]

    例如 : 0.1.8, 1.12.35, 2.0, 7.2.3 build-2189

    版本更動策略建議

    1. First : 專案剛開始建立基礎版本時, 版本號可以為 0.1 或 0.1.0, 也可以為 1.0 或 1.0.0, 如果你為人很低調, 我想你會選擇那個主版本號為 0 的方式 :-D
    2. Revision : 當專案進行中, 做了局部修改或 bug 修正時, 主版本號(Major)和子版本(Minor)號都不變, 修正版本號(Revision)加 1.
    3. Minor : 當專案在原有的基礎上增加部分功能, 主版本號(Major)不動, 子版本號(Minor)加 1, 修正版本號(Revision)再歸零.
    4. Major : 當專案進行了重大修改或局部修正累積較多, 而導致專案整體變化時, 主版本號(Major)加 1, 其餘歸零.
    5. Build : 編譯版本號(build)一般是編譯器在編譯過程中自動產生, 我們只記錄, 不進行人為控制.
    6. 另外在版本號後會加入後綴, 如 Alpha(內部測試版), Beta(外部測試版), Gamma(成熟版), RC (Release Candidate)(發佈候選版), Release(正式版), Stable(穩定版) 等, 大家參考使用.
  7. 本章總結

    本章使用 git 命令總結

    git config --global alias.XYZ = "..."         # 全域設定 git XYZ 簡捷快速鍵
    'revision range'                    # 修訂提交記錄範圍
    git log                             # 修訂提交歷史記錄的檢閱器
    git diff                            # 文件差異檢視, 預設從 `HEAD(舊)` 到 `工作區(新)` 差異, 只有曾經提交過的檔案
    git diff HEAD                       # 從 `HEAD(舊)` 到 `工作區(新)` 差異, 會顯示新建立在工作區的檔案
    git diff routes/web.php             # 從 `HEAD(舊)` 到 `工作區(新)` 差異, 指定 routes/web.php
    git diff HEAD^ HEAD                 # 從 `HEAD^(舊)` 到 `HEAD(新)` 差異
    git diff HEAD^^ HEAD                # 從 `HEAD^^(舊)` 到 `HEAD(新)` 差異
    git diff HEAD^^ HEAD routes/web.php # 從 `HEAD^^(舊)` 到 `HEAD(新)` 差異, 指定 routes/web.php
    good git commit message             # 優良的 git 提交訊息
    Major.Minor.Revision.Build          # 版本字號