# 你應該要把<br>沒用的 commit 壓扁
<div style="font-size: 50%; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;">
微程式 / 研一 / DevOps / 戴均民<br>
投影片:https://ppt.cc/fNqqLx
</div>
---
## 為什麼會想要分享這個主題
---
#### 一條 master 闖天下

---
#### 分支開好開滿

---
## GitLab Flow
## (GitHub Flow)
---
## 我們來模擬一次開發
## 多個功能分支的情況
---
### 建立一個空的 git repo
```shell
mkdir test
cd test
git init
echo "Hello, ${USER}" >> master.txt
git add .
git commit -m "1st"
```
---

---
#### 在 GitLab 上建立一個專案

---
### 於 git repo 中新增 remote
```shell
# 請改成自己的專案網址
git remote add origin git@gitlab.program.com.tw:jimmy.dai/git-test-20180521.git
git push -u origin master
```
---
## 練習時間
:::info
投影片: <https://ppt.cc/fNqqLx>
:::
---
## 接下來我們一起來
## 快速建立三個功能分支
---
### 建立功能 A
```shell
git checkout -b feature/a master
echo "This is feature A" >> featureA.txt
git add .
git commit -m "2nd"
git push -u origin feature/a
echo "這是功能 A" >> featureA.txt
git add .
git commit -m "3rd"
git push
```
---
### 建立功能 B
```shell
git checkout -b feature/b master
echo "This is feature B" >> featureB.txt
git add .
git commit -m "4th"
git push -u origin feature/b
echo "這是功能 B" >> featureB.txt
git add .
git commit -m "5th"
git push
```
---
### 建立功能 C
```shell
git checkout -b feature/c master
echo "This is feature C" >> featureC.txt
git add .
git commit -m "6th"
git push -u origin feature/c
echo "這是功能 C" >> featureC.txt
git add .
git commit -m "7th"
git push
```
---

---
## 練習時間
:::info
投影片: <https://ppt.cc/fNqqLx>
:::
---
## 功能完成時
### 幫分支建立 Merge Request
---

---
### 並且請你的伙伴來幫你看程式碼

:::info
PTAL: Please Take A Look
:::
---
# 討論和審查
1. 通知伙伴你的功能可以審查了<!-- .element: class="fragment" data-fragment-index="1" -->
2. 大家一起評審及討論你的程式碼<!-- .element: class="fragment" data-fragment-index="2" -->
- 可以逐行討論
3. 你仍然可以上傳新程式碼<!-- .element: class="fragment" data-fragment-index="3" -->
- 修正錯誤及伙伴的建議
---
### 當伙伴都看過程式碼
### 覺得可以合併時
### 就回覆 LGTM
:::info
LGTM: Looks Good To Me
:::
---

---
## 練習時間
:::info
投影片: <https://ppt.cc/fNqqLx>
:::
<small style="color: #999">(先別急著合併喔)</small>
---
### 接下來假設三個 MR
### 都已經可以合併了
---
## 在合併分支前
## 需要整理分支
## (Rebase and Squash)
---
## Rebase and Squash
* 將分支 rebase 到最新的 master<!-- .element: class="fragment" data-fragment-index="1" -->
* 保留有意義的 commit<!-- .element: class="fragment" data-fragment-index="2" -->
* 把 commit 訊息寫的更好<!-- .element: class="fragment" data-fragment-index="3" -->
```shell
git fetch --all
git checkout feature/a
git rebase -i origin/master
```
<!-- .element: class="fragment" data-fragment-index="4" -->
---

---
### `git rebase -i`
1. pick: 要使用這個 commit<!-- .element: class="fragment" data-fragment-index="1" -->
2. reword: 要修改 commit 訊息<!-- .element: class="fragment" data-fragment-index="2" -->
3. squash: 要把這個 commit 合併到
前一個 commit 中<!-- .element: class="fragment" data-fragment-index="3" -->
4. fixup: 要把這個 commit 合併到
前一個 commit 中,但是不保留訊息<!-- .element: class="fragment" data-fragment-index="4" -->
5. drop: 把這個 commit 丟棄<!-- .element: class="fragment" data-fragment-index="5" -->
---
### 決定如何 rebase

:::danger
注意: squash 前一個必須是 pick 或是 reword
:::
---
### 修改訊息

---

---

---
### 將 rebase 後的結果
### push 到 GitLab 上面
### (`--force`)
```shell
git status # 先確認自己在正確的分支
git push -f
```
:::warning
使用 `git push --force` 務必再次檢查
:::
<!-- .element: class="fragment" data-fragment-index="1" -->
---

---
## 接著在 MR 上按下 Merge

---

---
## 然後本地端需要 fetch
```shell
# 可以加上 --prune 同時刪除遠端沒有的分支(選用)
git fetch --all
```
---

---
## 然後把已經合併的分支刪除
```shell
git checkout master
git branch -D feature/a
```
---

---
#### 更新本地的 master 分支
```shell
git checkout master
git pull
```
---
#### 把開發中的分支移植到最新的 master 上
```shell
git checkout feature/b
git rebase master
git checkout feature/c
git rebase master
```
---

---
#### 然後把移植的分支推送到遠端
```shell
git checkout feature/b
git push -f
git checkout feature/c
git push -f
```
:::warning
使用 `git push --force` 務必再次檢查
:::
<!-- .element: class="fragment" data-fragment-index="1" -->
---

---
## 練習時間
:::info
投影片: <https://ppt.cc/fNqqLx>
:::
:::success
練習把 `feature/b` 和 `feature/c` 也合併
:::
---

---

---
# Q&A
:::info
投影片: <https://ppt.cc/fNqqLx>
:::
<small style="color: #999">(別走開,後面還有)</small>
---
# 換我提問了
---
# Q1
#### 一定要 Squash 到剩下一個 commit 嗎?
Note:
這個步驟的目的只是為了留下有意義的 commit,剩下幾個 commit 都沒問題。重點是要合併錯誤修正以及一些不太重要的 commit,避免 git 歷史記錄過於混亂。
---
# Q2
#### 為什麼還沒合併的功能性分支<br>要移植到 origin/master 上面?
Note:
1. 方便識別那些 commit 是有相關的,便於 revert 或是 cherry-pick
2. 確保功能性分支在合併回 master 不會發生檔案衝突
3. 可以提前測試功能性分支合併至 master 後沒有 bug
4. 如果有寫 CI test,可以模擬合併後會不會 pass test
---
# 小技巧
---
# Protect Branch
* 避免主要的分支被 force push<!-- .element: class="fragment" data-fragment-index="1" -->
* 只允許特定的成員 push 及 Merge<!-- .element: class="fragment" data-fragment-index="2" -->
---

---

---

---
## Merge commit<br>with semi-linear history
---
使用 non fast forward (`--no-ff`)<br> 的方式來 Merge
但是僅在能夠透過 fast forward (`--ff`)<br> 時才允許 Merge
---
## 這樣不能 Merge

---
## 這樣才能夠 Merge

---

---

---

---
# 參考資料
:::info
其實這份簡報有一些 GitLab Flow 的內容沒有提到:如 production 分支,這裡附上一些參考連結,裡面有更詳細的說明。
:::
* [Git 工作流程 | 阮一峰的網絡日誌](http://www.ruanyifeng.com/blog/2015/12/git-workflow.html)
* [Understanding the GitHub Flow](https://guides.github.com/introduction/flow/)
* [GitLab Flow](https://about.gitlab.com/2014/09/29/gitlab-flow/)
* [Introduction to GitLab Flow](https://docs.gitlab.com/ee/workflow/gitlab_flow.html)
---
# Q&A
:::info
投影片: <https://ppt.cc/fNqqLx>
:::
{"metaMigratedAt":"2023-06-14T16:00:25.756Z","metaMigratedFrom":"YAML","title":"你應該要把沒用的 commit 壓扁","breaks":true,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"0d9a5e06-1f92-4142-b9df-fed4c8873573\",\"add\":3,\"del\":17}]"}