---
# System prepended metadata

title: 你應該要把沒用的 commit 壓扁
tags: [簡報]

---

---
title: 你應該要把沒用的 commit 壓扁
tags: 簡報
langs: zh
slideOptions:
  transition: slide
---

# 你應該要把<br>沒用的 commit 壓扁

<div style="font-size: 50%; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;">
  微程式 / 研一 / DevOps / 戴均民<br>
  投影片：https://ppt.cc/fNqqLx
</div>

---

## 為什麼會想要分享這個主題

---

#### 一條 master 闖天下

![](https://i.imgur.com/cTkzKv5.png)

---

#### 分支開好開滿

![](https://i.imgur.com/qwtMF9t.png =900x600)

---

## GitLab Flow
## (GitHub Flow)

---

## 我們來模擬一次開發
## 多個功能分支的情況

---

### 建立一個空的 git repo

```shell
mkdir test
cd test
git init
echo "Hello, ${USER}" >> master.txt
git add .
git commit -m "1st"
```

---

![](https://i.imgur.com/7I7HP5J.png)

---

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

![](https://i.imgur.com/cOT0Miz.png)

---

### 於 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
```

---

![](https://i.imgur.com/6a0uWTe.png)

---

## 練習時間

:::info
投影片: <https://ppt.cc/fNqqLx>
:::

---

## 功能完成時
### 幫分支建立 Merge Request

---

![](https://i.imgur.com/vyTdHMw.png)

---

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

![](https://i.imgur.com/vE0sXqQ.png)

:::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
:::

---

![](https://i.imgur.com/IbECJ6n.png =450x640)

---

## 練習時間

:::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" -->

---

![](https://i.imgur.com/tU1atlZ.png)

---

### `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

![](https://i.imgur.com/vvI23Vl.png =384x100)

:::danger
注意: squash 前一個必須是 pick 或是 reword
:::

---

### 修改訊息

![](https://i.imgur.com/0otD7ez.png)

---

![](https://i.imgur.com/e2sezjT.png)

---

![](https://i.imgur.com/I3HpTRN.png)

---

### 將 rebase 後的結果
### push 到 GitLab 上面
### (`--force`)

```shell
git status # 先確認自己在正確的分支
git push -f
```
:::warning
使用 `git push --force` 務必再次檢查
:::
<!-- .element: class="fragment" data-fragment-index="1" -->

---

![](https://i.imgur.com/JyBoCtX.png)

---

## 接著在 MR 上按下 Merge

![](https://i.imgur.com/ccDxY3f.png)

---

![](https://i.imgur.com/KdfbCVN.png)

---

## 然後本地端需要 fetch

```shell
# 可以加上 --prune 同時刪除遠端沒有的分支（選用）
git fetch --all
```

---

![](https://i.imgur.com/WEYKUTq.png)

---

## 然後把已經合併的分支刪除

```shell
git checkout master
git branch -D feature/a
```

---

![](https://i.imgur.com/SE5moP4.png)

---

#### 更新本地的 master 分支

```shell
git checkout master
git pull
```

---

#### 把開發中的分支移植到最新的 master 上

```shell
git checkout feature/b
git rebase master
git checkout feature/c
git rebase master
```

---

![](https://i.imgur.com/wPGsvSb.png)

---

#### 然後把移植的分支推送到遠端

```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" -->

---

![](https://i.imgur.com/r7hXYQ8.png)

---

## 練習時間

:::info
投影片: <https://ppt.cc/fNqqLx>
:::

:::success
練習把 `feature/b` 和 `feature/c` 也合併
:::

---

![](https://i.imgur.com/0m405N8.png)

---

![](https://i.imgur.com/28GQAPL.png)

---

# 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" -->


---

![](https://i.imgur.com/7MSeSq2.png)

---

![](https://i.imgur.com/BtJrLUy.png)

---

![](https://i.imgur.com/eQ4I8iN.png)

---

## Merge commit<br>with semi-linear history

---

使用 non fast forward (`--no-ff`)<br> 的方式來 Merge

但是僅在能夠透過 fast forward (`--ff`)<br> 時才允許 Merge

---

## 這樣不能 Merge

![](https://i.imgur.com/SE5moP4.png)

---

## 這樣才能夠 Merge

![](https://i.imgur.com/r7hXYQ8.png)

---

![](https://i.imgur.com/bFsJvwo.png)

---

![](https://i.imgur.com/xwLUUKJ.png)

---

![](https://i.imgur.com/h2Cu6il.png)

---

# 參考資料

:::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>
:::