Git with SmartGit
===
綱要:
[TOC]
安裝Git
===
**Mac OSX**
---
Mac有內建Git的關係,可以不需要額外安裝Git主程式、也不需做任何設定
**Windows**
---
安裝檔下載網址:https://git-scm.com/download/win
Win10/11還需要設定系統環境變數的關係,安裝好Git之後我們必須進入到電腦的系統環境變數去新增 bin 位置,首先進入到「設定」,然後搜尋「系統環境變數」,點進會看到這個視窗:

接著在系統變數處按下編輯

到Git安裝好的目錄下找出bin的路徑,複製後點一下新增貼到空白處
重開機後打開終端機,也就是命令提示字元(一定要以系統管理員身份開啟)後輸入 `git`

看到這串訊息後代表Git安裝成功了。
安裝SmartGit
===
https://www.syntevo.com/smartgit/
SmartGit是個簡潔、功能又齊全的Git版本控制圖形介面軟體,所有操作可以在同一個畫面裡面完成,不像 [GitKraken](https://www.gitkraken.com/) 或 [SourceTree](https://www.sourcetreeapp.com/) 那般外觀設計精美,卻也非常強大且容易使用,學習成本低。

如果你還沒打算付費使用的話,可以在安裝時選擇試用或者非商用(非商用每次啟動都有三十秒的告示),日後有興趣再來取得授權。
安裝過程都蠻直覺,唯獨初學者最好途中在顯示樣式的選項中選擇「Working Tree」
---
**1. 選擇安裝路徑**


一般都是預設在`C:\Program Files\SmartGit`,可以自行變更
---
**2. 完成安裝後的設定**
打開SmartGit後會有許可授權種類的選擇,如果你已經有付費取得的序號就可以在這使用,或者你打算日後再來考慮付費,可以先使用非商業授權版本,只是非商業授權版本每次啟動後會有30秒的擋屏訊息、且必須只能使用每次更新的新版本。

接著設定你的使用者名稱和信箱,假如你在公司辦公,使用者名稱和信箱最好使用你的AD帳號或公司派發的帳號,正常情況下SE會幫你綁定GitLab、Mentis或red mine(兩者都是BUG工單系統)、Jira(專案管理軟體)等帳號。

SSH Clinet端的配置以SmartGit為主

顯示樣式選擇「Working Tree」


按下 Finish 後即可。
---
GitLab環境
===
**1. 複製既有專案下來本地端**
---
登入GitLab後,到你自己所屬的專案列表或群組列表尋找目標專案進入。

在專案畫面右側會看到一個藍色的Clone按鈕,按一下並且複製 **Clone With HTTP**
如果你的電腦中有設置SSH Key的話可以貼入公鑰後使用SSH的位置來clone
接著打開SmartGit > repository > clone

貼入剛才在GitLab複製的位置


Clone下來的目標位置可以自己命名,按下Finish即完成。

接著畫面上左下角的branch分支管理就會看的到當前在哪個分支,以及遠端資訊

---
**2. 建立新的專案**
---

首先我們需要建立一個新的group,建好後才會在裡面創一個新專案空間

按下右側的New project來創新專案

因為是全新的空專案,這裡選擇 Create blank project

輸入專案名稱以後按下 Create project

剛建立好的空專案會顯示這樣的畫面,提示你接下來有幾種方式可以把檔案推到這個倉庫,這裡我們常用的是 **Push an existing folder** 將既有的目錄內容推到GitLab。
而這些指令便是要你打開電腦的終端機輸入,一步一步設定後推送Commit內容到master主幹。
以 Win10 為例,我們打開電腦內的專案,啟動終端機指向這個專案的位置:

接著逐行輸入以下內容,輸入一行按一下**ENTER**
```shell=
git init --initial-branch=master
git remote add origin http://10.10.1.13/git_test/dummy-project.git
git add .
git commit -m "Initial commit"
git push -u origin master
```
:::info
如果你真的很不喜歡敲指令,那就回到我們強大的SmartGit圖形介面來處理吧,以下示範怎麼使用:
:::
回到SmartGit,選擇Repository > Add or Create

透過檔案瀏覽找到專案位置的目錄按下ok

接著會看見我們目錄中的檔案都被設置了Untracked的狀態

然後,我們需要新增一個remote遠端倉庫位置,按下Remote > Add

把GitLab上的專案位置貼入這裡,按下Add

任何變更要推入到遠端,無論是哪個分支,都必須先commit一次,這邊我們將兩個檔案選取起來後按右鍵 > commit

輸入這個變更的敘述才能按下commit,養成良好習慣,盡量寫有意義的註解喔

接著左下會看見原本origin的字樣處變成了master
這代表剛才我們已經在本地創建好了主幹,現在對著它點右鍵 > push

看到master = origin就代表成功了

回到GitLab查看專案頁面已經有檔案被記錄在上面儲存

---
GitHub環境
===
**1. 複製既有專案下來本地端**
---

按一下綠色的`CODE`按鈕,複製HTTPS的連結後,同GitLab操作貼到SmartGit進行Clone
---
**2. 建立新的專案**
---
畫面右上在你的頭貼點一下 >> Your Repositories,開啟連結看到這個畫面並按下綠色的**New**

接著可以輸入你的專案名稱,如果輸入框右側出現綠色的勾勾代表名稱可以使用。
然後輸入這個專案的**用途敘述**,狀態設定為**Public**(公開)
接著直接跳過其他欄位按下**Create repository**(創建專案)

最後看到空專案裡面,系統會提示你按照以下不同方式來推送專案到這個Repository

依序是:
快速開始,直接Clone這個空專案到本地連結遠端
使用CMD指令新增專案
使用CMD指令推送一個既有專案上來 (這裡直接參照上面GitLab的做法即可)
從其他專案匯入程式碼
---
基本的版本控制與管理
===
通常有新的需求,或者需要修復BUG,我們會開一支Branch(分支)來作業。
名稱以這個作業的主要修復版本號+工單號碼來命名,當然每間公司和團隊之間都會有不同的規定,按照訂好的規則走就行了。
**1. 分支(Branch)**
---
我們可以在左下Local Branches處點右鍵 > Add Branch

注意黑色實心箭頭目前指向的是誰,就是以誰為BASE去開分支
我們輸入分支名稱 **dev_0.0.1** 後按下 **Add branch & checkout**,也就是新增分支並切換到該分支進行作業的意思

建好後就可以push到遠端去,之後可以在GitLab的Branches看到剛才建立好的分支

:::info
注意!假如你已經先修改了檔案,但你修改後才驚覺自己沒有開分支就進行了作業,此時很可能因為畫面上清單出現了被變更的檔案,導致無法切換分支,以下方法可以解決這個疏忽造成的問題:
:::
如果忘了新增分支就先改了檔案,會像這個樣子

這時我們只要在被變更的檔案上選取後(多個檔案時可多選)
右鍵 > stash selection

輸入Stash註解後按下 **stash selection**

接著我們按兩下左鍵從master切換到dev_0.0.1去

把剛才我們存入Stash的變更引用進來,打開Stash找到剛才有寫過註解的那筆記錄,點右鍵 > Apply stash

這裡有兩個分別,左邊Apply是引入變更,中間Apply & Drop會在引入後把這個記錄刪除,看狀況使用

看,我們的修改記錄又回來了!

之後同樣在你完成作業後對檔案右鍵 > commit > 輸入備註 > commit & push
如果想要待會再push,想繼續完成其他作業步驟,可以僅按下commit就好。
---
**2. 在專案中設置.gitignore排除特定檔案或路徑**
---

有時候一些透過編譯後會自動產生的檔案、或者相對不重要的檔案,我們會透過建立 **.gitignore** 來排除它們避免誤入版控。
打開VSCODE或你習慣使用的IDE編輯器,在根目錄下新增 **.gitignore**,並逐行輸入你要排除的對象副檔名
```shell=
## 示範用,請按照真實情況寫入
__pycache__/
*/__pycache__/
*.pyc
*.html
pyc
```
---
**3. 提交Merge Request 與分支合併**
---
通常在公司做多人開發時一定會有這個需要,大家講好了一個既定的Flow後,由一位Maintainer負責Merge和審閱大家的code後才接受Merge Request。
而我們在開好分支後進行工作,完成時提交code該怎麼做?
首先Gitlab左側選單有個 **Merge Requests**
點進去後按下畫面中間的 **New merge request**


接著選擇我們的來源分支,然後提交到目標的master

提交畫面上需要寫清楚標題、敘述(你修了什麼或做了什麼)
用 Assignee 指定誰處理這個MR、找誰Review

畫面底下的changes也能看到有多少變更、可以在這看到修改前後的差別,確認你確實有修改到正確的檔案。
沒問題的話就可以按下 **Create merge request**

負責管理的人可以在開好的MR檢閱你的code,如果你剛好就是Maintainer,閱覽過所有資訊和code後按下**Approve**(同意),然後再按下**Merge**,專案就會接受這個合併。

合併後的樣子:

最後很重要的一個步驟,就是因為剛才的合併,你需要更新一下本地端Git的code,讓它們跟專案主線維持同個進度。
我們打開SmartGit,按下 **Pull** > **Fetch Only**

==Pull是抓下來後**merge更新**,Fetch是**僅下載而不會merge**==
此時你會看到master主線顯示了`< 2`代表有兩個變更

接著對master按下右鍵 > **Fast-forward Merge**

可以看到本地端的master已經和遠端的GitLab同步更新了

:::info
假如有其他同事更新並且讓Maintainer合併了新進度。
你在Fetch或Pull更新master後,還需要將它拉到現在工作的分支。
現在我們來試一次:
:::
你正在dev_0.0.1這個分支上開發,確認現在有同事提交了MR且合併後,透過Pull > Fetch Only 看到了有 1 個變更,我們將它做一次 **Fast-Forward** 更新

對著master,右鍵按下 **merge** 並選擇 **Merge to working tree**


此時會看到具體被變更了哪一支檔案,點選檔案還可以看見修改內容

對著檔案做選取後(可以用shift多選,Mac OSX則能使用滑鼠範圍選取)右鍵 > Commit 來合併這個變更。
如果暫時不想合併,可以按下右上的Abort跳出這次合併,恢復到沒Merge的狀態。

可以看見變更合併到本地端成為新的commit了,再使用右鍵 > push,即可將遠端分支也一併更新成最新的狀態!

---
**4. 衝突解決**
---
有時候運氣不好,跟同事沒協調好你們各自的工單是否會改到同一支檔案,或者你太久沒更新主線的code進來合併,造成merge時產生 Conflict(衝突)

衝突發生時Working Tree檔案列表處會顯示紅色的驚嘆號,告訴你這支檔案現在有衝突,需要解決。
打開編輯器看看該檔案,IDE或者VSCODE應該會顯示這樣的畫面

`<<<<<<< HEAD (Current Change)` 代表你目前的變更。
`>>>>>>> conflict (Incoming Change)` 代表來源的變更。
在SmartGit上對著該檔案右鍵 > **Conflict solver** 開啟這個畫面


我們可以在Solver上加入或者移除變更,然後按下存檔Save,此時會問你要不要將這個檔案設為Stage,選擇是以後就可以解決這個衝突,然後commit。
:::info
如果你不習慣這個方法,參照以下方式:
:::
直接在IDE介面內解決
我們須確定這個變更是有必要的,且和你現有的變更是否需同時存在,假設你該做的部分剛好被其他同事 **「順手修掉」** 那可以選擇放棄現在的部分變更,採用**Accept incoming Change**,將對方的CODE覆蓋到自己的變更上。
如果必須同時存在彼此的變更,則按下 **Accept Both Changes**
僅保留自己的變更,捨棄對方來源變更,則是 **Accept Current Changes**
處理好後畫面上的色條就會消失,改好後存檔

對著標示衝突的檔案右鍵 > Stage 後 commit 即可完成解決衝突

Commit 註解會自動產生關於衝突的記錄,Push後即完成這次的合併

常見的Git Flow
===
分為正規Flow和Github Flow兩種
一、正規Flow
===
特色是所有人都在同一個專案 Repository 作業
實務上Git中大概會有這些分支:
==**feature**==
新功能需求性質的工單類別
==**fix**==
BUG修正的工單類別
==**dev**==
dev分支不會只有一支,通常會有各種版號做後綴命名,比如 **dev_0.0.1**
==**qat**==
送到 QA 那進行測試用的分支,會有一個 server 位置用來部署前後端環境
dev 分支送測時需要 merge 到 qat
==**master**==
主幹,通常是 Production,也就是正式對外 Release 的版本
必須經過 qat 讓QA完整測試到沒問題後才能 merge 進來擇日釋出

流程概略
---

**準備開發階段:**
Pull或Fetch檢查dev是否有更新。
如 Master 有更版過,則以 **Master 先合併到 dev 為第一步驟**
> A. 有更新,Fast-Forward-Merge,合併更新到dev後,feature 工單分支
以 dev 為base 開新的來作業
>
> B. 沒更新,直接拿 dev 為 base 在 feature 開新分支
**開發完成階段:**
> 1. fetch dev 看有沒有其他人更新code,有的話合併過來保持最新
> 2. commit + push 到自己的feature下工單分支遠端
**提交 Merge Request 給 Maintainer:**
> 1. 進入GitLab,提交Merge Request
> 2. 設定自己的工單分支,提交到dev
> 3. 指定一位 Reviewer 和 Maintainer 送出MR
**Maintainer 該做的事:**
> 1. 收到 MR,檢視 Commits 變更
A:看起來 OK,同意合併更新到dev
B:有點狀況, 退回請對方修改後重發一次MR
> 2. 發個 MR 從 dev 合併到 qat 並且打上指定版號+時戳的 TAG
> 3. 合併後啟動 Git hook 連動 Docker 或 Jenkins 部署到 QAT 機器
> 4. 填寫送測單給 QA,BUG 若完全修復則可以 Merge 到 Master 部署 Prod
> 5. 將 master 的新版本更新到 dev
---
二、Github Flow
===
最為常見,也是比較推薦的方式
與主幹建立Fork關係
---
指定專案中的團隊成員,並請他們以 Fork 的形式複製主幹 Repo 到自己的 Group 底下,然後 Clone 這份 Forked 來的 Repo 到本地端進行作業。
可以在 GitLab 專案頁面的右上找到 Fork:

按下 Fork 會進入到這個新開專案的頁面,選好這個 Forked Repo 的所屬 Group 後即可

接著複製這個 fork 好的專案 Git 位置,切換到 SmartGit 的選單clone到本地端
forked位置: `10.10.1.13/fortes-work/dummy-project.git`
主幹位置:`10.10.1.13/git_test/dummy-project.git`

---
回 **GitLab 主幹 Repo** 上複製主幹的git位置,到SmartGit Remote > Add
將位置貼到 URL 欄位,命名 fork-source,按下 Add

origin下方會出現 fork-source,然後我們按一下Pull > Fetch Only 完成連接遠端

展開 fork-source,對裡面的 dev_0.0.1 點兩下,將這個分支命名為 source-dev_0.0.1,以後 Pull 更新的依據就是這個 source

---
Fork 作業搞定後,我們來看看 GitHub Flow 究竟有什麼不同:
首先可以看到第一個不同點:
我們需要 ==**拉一支遠端的 fork-source 新增到本地端**==

dev 和 qat 在這個 Flow 中亦受保護,平常不允許直接 merge。
同樣必須透過發MR的方式提交並由 Maintainer 審閱後,才併入 dev。
開發作業用的 Repo 和遠端主幹Repo的各種分支用途解釋:
**1. 開發用的 Forked Repository**
==**feature**==
新功能需求性質的工單類別
==**fix**==
BUG修正的工單類別
==**dev**==
你自己的dev,時常要 follow source-dev,分支通常會有各種版號做後綴命名,比如 **dev_0.0.1** ,隨著每次改版增加,建議最好留最近三個版本之後將其餘的刪除。
==**source-dev**==
透過 Remote Add 來的主幹 dev,我們會拉進來後命名為 **source-dev_版號** 日後遠端有變更時透過 Pull 或 Fetch 來更新,
==**master**==
基本上這個 flow 中幾乎用不到自己的 master,保持和主幹的 master 同步即可。
---
**2. 遠端主幹 Remote Repository**
==**dev**==
受保護,所有人開發完後都必須先提交 MR 給這個分支
==**qat**==
受保護,Maintiner 需提交 MR ,從 dev 推給這個分支來合併
==**master**==
一般來說都是準備進 Production 正式環境時才從 qat 推 MR 到這 merge
---
流程概略
---

**準備開發階段:**
Pull 或 Fetch 檢查 source-dev 是否有更新。
如 Master 有更版過,**Maintainer 會幫大家在遠端更新 dev 和 Master,這裡只檢查 source-dev 即可**
> A:有更新,Fast-Forward-Merge 過來,合併更新到本地dev
> B:沒更新,直接拿 source-dev 開新分支
> 1. 以 source-dev 為base開新的分支
> 2. 輸入工單分支名稱: feature/ xxx-xxxxx 並推送給自己的 remote
**開發完成階段:**
> 1. fetch 看看 source-dev 有沒有其他人更新 code,有的話合併過來自己的工單分支保持最新
> 2. 切換到本地 dev 分支,把工單分支合併過來 push 到自己的 forked repo
**提交 Merge Request 給 Maintainer:**
> 1. 進入GitLab,提交Merge Request
> 2. 設定自己的 dev 要提交到主幹的 dev
> 3. 指定一位 Reviewer 和 Maintainer 送出MR
**Maintainer 該做的事:**
> 1. 收到 MR,檢視 Commits 變更
A:看起來 OK,同意合併更新到dev
B:有點狀況, 退回請對方修改後重發一次MR
> 2. 發個 MR 從 dev 合併到 qat 並且打上指定版號+時戳的 TAG
> 3. 合併後啟動 Git hook 連動 Docker 或 Jenkins 部署到 QAT 機器
> 4. 填寫送測單給 QA,BUG 若完全修復則可以 Merge 到 Master 部署 Prod
> 5. 將 master 的新版本更新到 dev,確定大家都能從他們各自 forked repo 中的 source-dev 取得更新
---
###### tags: `Git`