---
title: Git 學習筆記
tags: Note, git
---
# Git 學習筆記
記錄一些Git 指令,太常用GUI操作有夠容易忘記指令的..
:::spoiler **Learning Resource**
- [從 0 到 1 的 GitHub Pages 教學手冊](https://hackmd.io/@Albertnotes/B1_iKcAwI)
- [Git & GitHub 教學手冊 - 六角學院](https://w3c.hexschool.com/git/cfdbd310)
- [為你自己學 Git - 作者高見龍](https://gitbook.tw/)
- [連猴子都能懂的 Git 入門指南](https://backlog.com/git-tutorial/tw/)
- [Git 官方中文教學](https://git-scm.com/book/zh-tw/v2)
- [30 天精通 Git 版本控管 - 作者黃保翕 ( Will 保哥 )](https://github.com/doggy8088/Learn-Git-in-30-days/blob/master/zh-tw/README.md)
:::
## Git 常用指令
src: https://codertw.com/程式語言/639003/
1. `git remote -v` 查看origin指向URL
1. `git status` :查看目前工作目錄有無未被追蹤或已被修改的檔案
2. `git add [檔名or目錄名]` :新增追蹤的檔案,將檔案暫存
3. `git commit` :將 `git add` 加進去的檔案記錄在快照內。可使用 `-m` 參數添加此次commit的註記
* `git commit -am.`
4. `git push` :將commit完的分支推送到遠端倉庫上
5. 危險操作(ex. `merge`, `rebase`, `reset`等)之後回到上一步[(src)](https://hackmd.io/E9Q4BbyvTbWHVTk0ElaXng?view#%E4%BF%AE%E6%94%B9commit%E7%B4%80%E9%8C%84)
```
git reset ORIG_HEAD --hard
```
> [2021.10.15]
> 由於Github前陣子取消了https上傳的方式,只好改來設定SSH金鑰[(SSH Key設定)](/qd9jrBOfQiSCFDIc6trkGg)
## 合併其他分支到main分支
src: https://gitbook.tw/chapters/branch/merge-branch.html
1. commit 目前所有更改的檔案
2. 切回 `main` 分支
```
git checkout main
```
3. 合併分支
```
git merge [your-branch-name]
```
## 切換遠端資料庫
1. 在github上建立完新repo之後
2. 初始化git
```
git init --initial-branch=main
```
3. 切換到新的repo url
```
git remote set-url origin [new-remote-repo-url]
```
4. 建立分支
```
git branch -M main
```
5. 上傳本地資料夾檔案到repo
```
git push -u origin main
```
</br>
也可以透過刪除的方式:
1. 查看所有遠端目錄 `git remote -v`
2. 刪除遠端 `git remote rm [remote-repo-name]`
3. 新增遠端 `git remote add origin [remote-repo-url]`
## 刪除遠端分支
1. 將 local branch 改名
```
git branch -m {old_branch_name} {new_branch_name}
```
2. 將新 branch push 至 server 並從 server 上刪除 branch
```
git push origin {new_branch_name} :{old_branch_name}
```
## 本地分支與遠端分隻的操作
> src: [git Local 端與 Remote 端的分支操作](https://sean22492249.medium.com/git-local-%E7%AB%AF%E8%88%87-remote-%E7%AB%AF%E7%9A%84%E5%88%86%E6%94%AF%E6%93%8D%E4%BD%9C-3dc360be3b5b)
* 連結local branch到 remote
```bash
git branch --set-upstream-to=origin/uat uat
```
* 如果remote有一個新的分支還沒追蹤,local也沒有建立這個分支,可以直接輸入
```
git checkout -track origin/uat
```
直接將remote branch拉到本地,並建立連結。
## 回到上一版或指定版本
回到上一版
```
git reset --hard HEAD~
```
參數
```
git reset --參數 節點ID
```
- `hard`: 強制回朔,不保留修改,刪除暫存
- `soft`: 回朔,且保留修改,不刪除暫存
- `mixed`: 強制回朔,保留修改,但刪除暫存
## 修改 commit 方法
有三種方式: `reset`, `rebase`, `revert`
| 指令 | 改變歷史紀錄 | 說明 |
| -------- |:--------:| -------- |
| Reset | 是 | 把目前的狀態設定成某個指定的 Commit 的狀態,通常適用於尚未推出去的 Commit。 |
|Rebase |是 |不管是新增、修改、刪除 Commit 都相當方便,用來整理、編輯還沒有推出去的 Commit 相當方便,但通常也只適用於尚未推出去的 Commit。|
|Revert|否|==新增一個 Commit== 來反轉(或說取消)另一個 Commit 的內容,==原本的 Commit 依舊還是會保留在歷史紀錄中==。雖然會因此而增加 Commit 數,但通常比較適用於已經推出去的 Commit,或是不允許使用 Reset 或 Rebase 之修改歷史紀錄的指令的場合。|
## Git clone 失敗
解決方法:https://www.cnblogs.com/anliux/p/11668058.html
# 在Intellij IDEA中使用Git
## Git的基本工作流程

- `git clone`: 將遠端的`master` 分支複製到本地的repository
- `git checkout`: 切換到分支
- `git add`: 將文件加入git版控(stage)
- `git commit`: 將版控中有改變的code提交到本地的repository
- `git push`: 將本地repository的code提交到遠端repository
在IDEA中,會看到檔案變標著不同顏色:紅色、綠色、藍色,分別代表以下意思:
- 紅色:未加入版控的檔案
- 綠色:新加入版控的檔案,還未提交到remote repository
- 藍色:修改過的檔案,即 remote repository已有此檔案,我們對這檔案做了修改但還未提交。
一般再提交程式碼前最好先更新遠端repository的程式碼到本地,這樣可以減少不必要的衝突
- `fetch`: 取得遠端repository的最新歷史紀錄
- `merge`: 將遠端repository合併到目前所在的分支
- `pull` = `fetch` + `merge`
將遠端repository更新到本地的步驟如下:[src](http://italwaysrainonme.blogspot.com/2012/12/gitmerge_20.html)
### 更新
## Git 分支
根據 **[Git Flow](https://ithelp.ithome.com.tw/articles/10227605)** 建議的git branch命名及使用方式如下:
- Master 分支
主要是用來放穩定、隨時可上線的版本。這個分支的來源只能從別的分支合併過來,開發者不會直接 Commit 到這個分支。因為是穩定版本,所以通常也會在這個分支上的 Commit 上打上版本號標籤。
- Develop 分支
這個分支主要是所有開發的基礎分支,當要新增功能的時候,所有的 Feature 分支都是從這個分支切出去的。而 Feature 分支的功能完成後,也都會合併回來這個分支。
- Hotfix 分支
當線上產品發生緊急問題的時候,會從 Master 分支開一個 Hotfix 分支出來進行修復,Hotfix 分支修復完成之後,會合併回 Master 分支,也同時會合併一份到 Develop 分支。
為什麼要合併回 Develop 分支?如果不這麼做,等到時候 Develop 分支完成並且合併回 Master 分支的時候,那個問題就又再次出現了。
那為什麼一開始不從 Develop 分支切出來修?因為 Develop 分支的功能可能尚在開發中,這時候硬是要從這裡切出去修再合併回 Master 分支,只會造成更大的災難。
- Release 分支
當認為 Develop 分支夠成熟了,就可以把 Develop 分支合併到 Release 分支,在這邊進行算是上線前的最後測試。測試完成後,Release 分支將會同時合併到 Master 以及 Develop 這兩個分支上。Master 分支是上線版本,而合併回 Develop 分支的目的,是因為可能在 Release 分支上還會測到並修正一些問題,所以需要跟 Develop 分支同步,免得之後的版本又再度出現同樣的問題。
- Feature 分支
當要開始新增功能的時候,就是使用 Feature 分支的時候了。Feature 分支都是從 Develop 分支來的,完成之後會再併回 Develop 分支。

由於 Git Flow 流程較為複雜,後來推出的 **[GitLab Flow](https://ithelp.ithome.com.tw/articles/10228195)**,將流程簡化。
只分兩種主要分支: `master`, `production`。
- **Master**: 所有開發需求都從 `master` 分出來
- **Production**: 針對發佈的版本建立`

## Git 標籤
- tag: 就是貼紙的概念,為指向某一commit的指標
- 用處:通常用來標記軟體版號,例如軟體版號 `1.0.0` 或是 `beta-release` 之類的
- 分成兩種:輕量標籤(lightweight tag)、附註標籤(annotated tag)
- 輕量標籤:沒有附註,僅是一個指向某個 Commit 的指標,沒有含有其它的資訊
- 附註標籤:包含更多關於這張標籤的資訊,例如是誰在什麼時候貼這張標籤,以及為什麼要貼這張標籤
- 刪除標籤:不會造成commit或檔案不見
不管是哪種標籤,都跟branch一樣以檔案方式存在 `.git/refs/tags` 目錄下。
檔案的內容也跟分支一樣,是一個 40 個字元的 SHA-1 值,指向某個地方。但差別是,輕量標籤指向的是某一個 Commit,但附註標籤是指向某個 Tag 物件,而這個 Tag 物件才再指向那個 Commit。
`annotated tag` -> `lightweight tag` -> `commit`
:::info
**標籤、分支的差別**
「分支會隨著commit移動,標籤不會」
:::
## Git commit 規範
Commit訊息規範的重要性,可參考:[Git Commit Message 這樣寫會更好,替專案引入規範與範例](https://wadehuanglearning.blogspot.com/2019/05/commit-commit-commit-why-what-commit.html)
### 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 的使用時機有一致的認同。
### commit格式
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: 開頭,後面是對變動的描述、以及變動原因和遷移方法。
範例:
- 橘色部分份為 "必填"
- 藍色部分份為 "選填"

### 使用Plugin寫符合規範的commit
有許多幫助或檢查commit有沒有符合規範的套件,terminal或IDE內的都有,可視自己常用的開發工具或流程而定:
- IDE: 推薦安裝 Conventional Commits,在VScode 或Intellij IDEA都有此套件
- terminal: https://github.com/Everduin94/better-commits