# Git 筆記 ## 為什要要使用 Git ? ### 記錄 Git 記錄修改,而不是檔案。資料夾對於 Git 來說只是路徑,並不會判別資料夾,除非在資料夾內新增檔案或者資料夾內的檔案有所變動。 ### 回復 寫錯東西或者後悔變動的檔案可以回復之前的樣子。 ### 合作 Git Branch 可以開拓分支進行平行運作而不互相干擾,最後還可以合併在一起。 ## 常用指令 + `git init`:進行版本控制。 + `git status`:狀態檢查,看有無變動。 + `git add 檔案名稱`:指令把檔案從工作目錄移至暫存區。 + `git add .`:將所有變更加入至暫存區。 + `git commit -m '<commit message>'`:指令把暫存區的內容移至儲存庫。 + `git commit --amend -m '<commit message>'`:與上一個 commit 合併。使用時機:Commit message 打錯或者不想一直新增 commit 時。 + `git rm --cached file`:反悔加入暫存區,但保留檔案。 + `git rm -f file`:反悔加入暫存區,而且真的刪除檔案。 + `git hist`:觀看 Commit 歷史。 + 註:使用此指令需先輸入 `git config --global alias.hist "log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short"` (Aliase 設定)。 + 更多方便設定請見 [其它方便的設定](https://gitbook.tw/chapters/config/convenient-settings.html)、[11. Aliases](https://githowto.com/aliases)、[Git Workshop for MFEE25](https://hackmd.io/5uvteB-LSOG9MPy3VBvj9Q?view)。 + `git checkout <commit code>`:回到某個 commit 的版本。 + `git switch <commit code>`:同 git checkout。 + `git clone *repo 網址*`:[從伺服器上取得 Repository](https://gitbook.tw/chapters/github/clone-repository.html)。 + `git merge <branch name>`:將某分支合併。詳細使用方式可參閱 [合併分支](https://gitbook.tw/chapters/branch/merge-branch.html)與 [另一種合併方式 rebase](https://gitbook.tw/chapters/branch/merge-with-rebase.html)。 + `git merge <branch name> --no --ff`:詳細使用方式請見 [【狀況題】為什麼我的分支都沒有「小耳朵」?](https://gitbook.tw/chapters/branch/merge-commit.html)。 + `git rebase *branchName*`:另一種合併方式,詳細請參考 [另一種合併方式(git rebase)](https://gitbook.tw/chapters/branch/merge-with-rebase)。 + `git revert HEAD`:刪除上一個 commit 的所執行動作,但 commit message 會保留且還會新增一個新的 revert commit message,詳細說明可參考 [這裡](https://gitbook.tw/chapters/rewrite-history/reset-revert-and-rebase)。 + `git revert HEAD --no--edit`:可不用自行輸入 revert message。 + `git diff` 相關:比對檔案的修改紀錄,可以比對當前修改的有哪些、或是哪些 commit 區間的修改紀錄,此段落引用自 [[GIT] 跨 Repo 取得 commit 資料 (二) - diff + apply](https://www.gss.com.tw/blog/git-diff-repo-get-commit-diff-apply)。 1. `git diff`:比對當前的修改紀錄,此比對是在執行 git add 之前的檔案。 2. `git diff --cached`:這個比對的時機點是 git add 之後,git commit 之前,適用於執行 commit 之前做的檢查! 3. g`it diff commitId`:這個會比對填入的 commitId ~ 當前工作目錄區間的修改紀錄。若想要看上一個 Commit 的紀錄,可以使用 git diff HEAD^。 4. `git diff *start commitId* *finish commitId*`:這個就是比對兩個 commit 區間的修改紀錄囉。 ### branch 分支相關 + `git branch <branch name>`:建立分支。 + `git branch -d <branch name>`:刪除分支。 + `git branch -v`:列出分支。(包含 master) + `git checkout -b <branch name>`:等同 `git branch <branch name>` + `git checkout <branch name>`。 ## *Git 狀況題* ### 我 commit 了可是又不想 commit 了! + `git reset HEAD^ --soft`:僅移除 commit,保留新增的檔案,已修改的檔案保留修改。 + 新增的檔案與已修改的檔案皆存放在staging area 裡面。 + 註:`HEAD^` 代表回到 HEAD的上一個版本,`HEAD~2`則為回到上兩個版本。 + 註:`HEAD^` 可替換成任一版本的 commit code。 + `git reset HEAD^ --mixed`:沒有設定參數時的預設值,移除 commit,保留新增的檔案,已修改的檔案保留修改。 + 新增的檔案與已修改的檔案皆 *不* 存放在staging area 裡面,需要再使用 `git add .` 指令加入至暫存區。 + `git reset HEAD^ --hard`:移除 commit,移除新增的檔案,已修改的檔案回復到未修改前。 ### 我用了git reset 指令,可是我又後悔了怎麼辦? + `git reflog`:能看到使用 `git reset` 指令前的 commit 歷史。 1. 先使用 `git reflog` 指令。 2. 再使用 `git reset <commit code> --hard` 回到過去版本。詳細說明可考[【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?](https://gitbook.tw/chapters/using-git/restore-hard-reset-commit.html)。 ### 我還沒 commit,但我改的東西我也不想要了! + `git checkout -- <file>`:讓該檔案回到上一個 commit 的狀態。 + `git checkout -- .`:讓所有檔案回到上一個 commit 的狀態。 ### 我想要刪除某幾個 Commit 或是調整 Commit 的順序! + 使用 `git rebase -i *commitCode*`,詳細請參考 [【狀況題】想要刪除某幾個 Commit 或是調整 Commit 的順序](https://gitbook.tw/chapters/rewrite-history/remove-and-reorder-commit)、[6. 使用 rebase -i 修改提交](https://backlog.com/git-tutorial/tw/stepup/stepup7_6.html)。 + 補充 1:若輸入 `git rebase -i HEAD~~`,預設文字編輯器會開啟從 HEAD 到 HEAD~~ 的紀錄。 + 補充 2:[簡明 Vim 文字編輯器操作入門教學](https://blog.techbridge.cc/2020/04/06/how-to-use-vim-as-an-editor-tutorial/)。 ## [Git Commit Message 這樣寫會更好,替專案引入規範與範例](https://wadehuanglearning.blogspot.com/2019/05/commit-commit-commit-why-what-commit.html) > ### Commit Message 規範組成 > ``` > Header: <type>(<scope>): <subject> > - type: 代表 commit 的類別:feat, fix, docs, style, refactor, test, chore,必要欄位。 > - scope 代表 commit 影響的範圍,例如資料庫、控制層、模板層等等,視專案不同而不同,為可選欄位。 > - subject 代表此 commit 的簡短描述,不要超過 50 個字元,結尾不要加句號,為必要欄位。 > > Body: 72-character wrapped. This should answer: > * Body 部份是對本次 Commit 的詳細描述,可以分成多行,每一行不要超過 72 個字元。 > * 說明程式碼變動的項目與原因,還有與先前行為的對比。 > > Footer: > - 填寫任務編號(如果有的話). > - BREAKING CHANGE(可忽略),記錄不兼容的變動, > 以 BREAKING CHANGE: 開頭,後面是對變動的描述、以及變動原因和遷移方法。 > ``` > ### type 只允許使用以下類別: > + feat: 新增/修改功能 (feature)。 > + fix: 修補 bug (bug fix)。 > + docs: 文件 (documentation)。 > + style: 格式 (不影響程式碼運行的變動 white-space, formatting, missing semi colons, etc)。 > + refactor: 重構 (既不是新增功能,也不是修補 bug 的程式碼變動)。 > + perf: 改善效能 (A code change that improves performance)。 > + test: 增加測試 (when adding missing tests)。 > + chore: 建構程序或輔助工具的變動 (maintain)。 > + revert: 撤銷回覆先前的 commit 例如:revert: type(scope): subject (回覆版本:xxxx)。 > > Type 是用來告訴進行 Code Review 的人應該以什麼態度來檢視 Commit 內容。 > 例如:看到 Type 為 fix,進行 Code Review 的人就可以用「觀察 Commit 如何解決錯誤」的角度來閱讀程式碼。若是 refactor,則可以放輕鬆閱讀程式碼如何被重構,因為重構的本質是不會影響既有的功能。利用不同的 Type 來決定進行 Code Review 檢視的角度,可以提升 Code Review 的速度。因此開發團隊應該要對這些 Type 的使用時機有一致的認同。