Git with SmartGit === 綱要: [TOC] 安裝Git === **Mac OSX** --- Mac有內建Git的關係,可以不需要額外安裝Git主程式、也不需做任何設定 **Windows** --- 安裝檔下載網址:https://git-scm.com/download/win Win10/11還需要設定系統環境變數的關係,安裝好Git之後我們必須進入到電腦的系統環境變數去新增 bin 位置,首先進入到「設定」,然後搜尋「系統環境變數」,點進會看到這個視窗: ![](https://i.imgur.com/BCkEMfK.png) 接著在系統變數處按下編輯 ![](https://i.imgur.com/NpSxzdz.png) 到Git安裝好的目錄下找出bin的路徑,複製後點一下新增貼到空白處 重開機後打開終端機,也就是命令提示字元(一定要以系統管理員身份開啟)後輸入 `git` ![](https://i.imgur.com/69ZFJ23.png) 看到這串訊息後代表Git安裝成功了。 安裝SmartGit === https://www.syntevo.com/smartgit/ SmartGit是個簡潔、功能又齊全的Git版本控制圖形介面軟體,所有操作可以在同一個畫面裡面完成,不像 [GitKraken](https://www.gitkraken.com/) 或 [SourceTree](https://www.sourcetreeapp.com/) 那般外觀設計精美,卻也非常強大且容易使用,學習成本低。 ![](https://i.imgur.com/m1NheHm.png) 如果你還沒打算付費使用的話,可以在安裝時選擇試用或者非商用(非商用每次啟動都有三十秒的告示),日後有興趣再來取得授權。 安裝過程都蠻直覺,唯獨初學者最好途中在顯示樣式的選項中選擇「Working Tree」 --- **1. 選擇安裝路徑** ![](https://i.imgur.com/Yfdp9oj.png) ![](https://i.imgur.com/hUDeMkw.png) 一般都是預設在`C:\Program Files\SmartGit`,可以自行變更 --- **2. 完成安裝後的設定** 打開SmartGit後會有許可授權種類的選擇,如果你已經有付費取得的序號就可以在這使用,或者你打算日後再來考慮付費,可以先使用非商業授權版本,只是非商業授權版本每次啟動後會有30秒的擋屏訊息、且必須只能使用每次更新的新版本。 ![](https://i.imgur.com/Kb4kb7U.png) 接著設定你的使用者名稱和信箱,假如你在公司辦公,使用者名稱和信箱最好使用你的AD帳號或公司派發的帳號,正常情況下SE會幫你綁定GitLab、Mentis或red mine(兩者都是BUG工單系統)、Jira(專案管理軟體)等帳號。 ![](https://i.imgur.com/OkFdOG7.png) SSH Clinet端的配置以SmartGit為主 ![](https://i.imgur.com/FWxHosA.png) 顯示樣式選擇「Working Tree」 ![](https://i.imgur.com/b1SbNqQ.png) ![](https://i.imgur.com/bub9kqZ.png) 按下 Finish 後即可。 --- GitLab環境 === **1. 複製既有專案下來本地端** --- 登入GitLab後,到你自己所屬的專案列表或群組列表尋找目標專案進入。 ![](https://i.imgur.com/VlskiYX.png) 在專案畫面右側會看到一個藍色的Clone按鈕,按一下並且複製 **Clone With HTTP** 如果你的電腦中有設置SSH Key的話可以貼入公鑰後使用SSH的位置來clone 接著打開SmartGit > repository > clone ![](https://i.imgur.com/RxJXtA7.png) 貼入剛才在GitLab複製的位置 ![](https://i.imgur.com/ZiAj0FK.png) ![](https://i.imgur.com/zW37BOj.png) Clone下來的目標位置可以自己命名,按下Finish即完成。 ![](https://i.imgur.com/Nbw9SuD.png) 接著畫面上左下角的branch分支管理就會看的到當前在哪個分支,以及遠端資訊 ![](https://i.imgur.com/5fCtx4I.png) --- **2. 建立新的專案** --- ![](https://i.imgur.com/ofYnEU8.png) 首先我們需要建立一個新的group,建好後才會在裡面創一個新專案空間 ![](https://i.imgur.com/HvLXjRu.png) 按下右側的New project來創新專案 ![](https://i.imgur.com/hE7Ibbe.png) 因為是全新的空專案,這裡選擇 Create blank project ![](https://i.imgur.com/5Wlb1zw.png) 輸入專案名稱以後按下 Create project ![](https://i.imgur.com/djTeW2t.png) 剛建立好的空專案會顯示這樣的畫面,提示你接下來有幾種方式可以把檔案推到這個倉庫,這裡我們常用的是 **Push an existing folder** 將既有的目錄內容推到GitLab。 而這些指令便是要你打開電腦的終端機輸入,一步一步設定後推送Commit內容到master主幹。 以 Win10 為例,我們打開電腦內的專案,啟動終端機指向這個專案的位置: ![](https://i.imgur.com/7Ybnz8R.png) 接著逐行輸入以下內容,輸入一行按一下**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 ![](https://i.imgur.com/DpO7z3S.png) 透過檔案瀏覽找到專案位置的目錄按下ok ![](https://i.imgur.com/RWeAmXe.png) 接著會看見我們目錄中的檔案都被設置了Untracked的狀態 ![](https://i.imgur.com/5YqqpLg.png) 然後,我們需要新增一個remote遠端倉庫位置,按下Remote > Add ![](https://i.imgur.com/YPJMvpi.png) 把GitLab上的專案位置貼入這裡,按下Add ![](https://i.imgur.com/eFc5yU9.png) 任何變更要推入到遠端,無論是哪個分支,都必須先commit一次,這邊我們將兩個檔案選取起來後按右鍵 > commit ![](https://i.imgur.com/3c61GuP.png) 輸入這個變更的敘述才能按下commit,養成良好習慣,盡量寫有意義的註解喔 ![](https://i.imgur.com/IkmrSdX.png) 接著左下會看見原本origin的字樣處變成了master 這代表剛才我們已經在本地創建好了主幹,現在對著它點右鍵 > push ![](https://i.imgur.com/hduFdkE.png) 看到master = origin就代表成功了 ![](https://i.imgur.com/4tSOoNp.png) 回到GitLab查看專案頁面已經有檔案被記錄在上面儲存 ![](https://i.imgur.com/iSypCJM.png) --- GitHub環境 === **1. 複製既有專案下來本地端** --- ![](https://i.imgur.com/zSXDLPO.png) 按一下綠色的`CODE`按鈕,複製HTTPS的連結後,同GitLab操作貼到SmartGit進行Clone --- **2. 建立新的專案** --- 畫面右上在你的頭貼點一下 >> Your Repositories,開啟連結看到這個畫面並按下綠色的**New** ![](https://i.imgur.com/fr20PoD.png) 接著可以輸入你的專案名稱,如果輸入框右側出現綠色的勾勾代表名稱可以使用。 然後輸入這個專案的**用途敘述**,狀態設定為**Public**(公開) 接著直接跳過其他欄位按下**Create repository**(創建專案) ![](https://i.imgur.com/z6EbGSP.png) 最後看到空專案裡面,系統會提示你按照以下不同方式來推送專案到這個Repository ![](https://i.imgur.com/fodHx6l.png) 依序是: 快速開始,直接Clone這個空專案到本地連結遠端 使用CMD指令新增專案 使用CMD指令推送一個既有專案上來 (這裡直接參照上面GitLab的做法即可) 從其他專案匯入程式碼 --- 基本的版本控制與管理 === 通常有新的需求,或者需要修復BUG,我們會開一支Branch(分支)來作業。 名稱以這個作業的主要修復版本號+工單號碼來命名,當然每間公司和團隊之間都會有不同的規定,按照訂好的規則走就行了。 **1. 分支(Branch)** --- 我們可以在左下Local Branches處點右鍵 > Add Branch ![](https://i.imgur.com/fejQeFZ.png) 注意黑色實心箭頭目前指向的是誰,就是以誰為BASE去開分支 我們輸入分支名稱 **dev_0.0.1** 後按下 **Add branch & checkout**,也就是新增分支並切換到該分支進行作業的意思 ![](https://i.imgur.com/WdT2xeV.png) 建好後就可以push到遠端去,之後可以在GitLab的Branches看到剛才建立好的分支 ![](https://i.imgur.com/LoWTFbL.png) :::info 注意!假如你已經先修改了檔案,但你修改後才驚覺自己沒有開分支就進行了作業,此時很可能因為畫面上清單出現了被變更的檔案,導致無法切換分支,以下方法可以解決這個疏忽造成的問題: ::: 如果忘了新增分支就先改了檔案,會像這個樣子 ![](https://i.imgur.com/RnoiYdF.png) 這時我們只要在被變更的檔案上選取後(多個檔案時可多選) 右鍵 > stash selection ![](https://i.imgur.com/vqTVFAp.png) 輸入Stash註解後按下 **stash selection** ![](https://i.imgur.com/Hn62PAx.png) 接著我們按兩下左鍵從master切換到dev_0.0.1去 ![](https://i.imgur.com/BmxT0WY.png) 把剛才我們存入Stash的變更引用進來,打開Stash找到剛才有寫過註解的那筆記錄,點右鍵 > Apply stash ![](https://i.imgur.com/r1Owtab.png) 這裡有兩個分別,左邊Apply是引入變更,中間Apply & Drop會在引入後把這個記錄刪除,看狀況使用 ![](https://i.imgur.com/iD9nt9D.png) 看,我們的修改記錄又回來了! ![](https://i.imgur.com/6Ky5nux.png) 之後同樣在你完成作業後對檔案右鍵 > commit > 輸入備註 > commit & push 如果想要待會再push,想繼續完成其他作業步驟,可以僅按下commit就好。 --- **2. 在專案中設置.gitignore排除特定檔案或路徑** --- ![](https://i.imgur.com/uS4cC9x.png) 有時候一些透過編譯後會自動產生的檔案、或者相對不重要的檔案,我們會透過建立 **.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** ![](https://i.imgur.com/3GobW2B.png) ![](https://i.imgur.com/3jPtGSD.png) 接著選擇我們的來源分支,然後提交到目標的master ![](https://i.imgur.com/f7chM6m.png) 提交畫面上需要寫清楚標題、敘述(你修了什麼或做了什麼) 用 Assignee 指定誰處理這個MR、找誰Review ![](https://i.imgur.com/AMlQZCY.png) 畫面底下的changes也能看到有多少變更、可以在這看到修改前後的差別,確認你確實有修改到正確的檔案。 沒問題的話就可以按下 **Create merge request** ![](https://i.imgur.com/vzX7MuZ.png) 負責管理的人可以在開好的MR檢閱你的code,如果你剛好就是Maintainer,閱覽過所有資訊和code後按下**Approve**(同意),然後再按下**Merge**,專案就會接受這個合併。 ![](https://i.imgur.com/vES0yw1.png) 合併後的樣子: ![](https://i.imgur.com/CVSL929.png) 最後很重要的一個步驟,就是因為剛才的合併,你需要更新一下本地端Git的code,讓它們跟專案主線維持同個進度。 我們打開SmartGit,按下 **Pull** > **Fetch Only** ![](https://i.imgur.com/0H6OIVh.png) ==Pull是抓下來後**merge更新**,Fetch是**僅下載而不會merge**== 此時你會看到master主線顯示了`< 2`代表有兩個變更 ![](https://i.imgur.com/t4riNpV.png) 接著對master按下右鍵 > **Fast-forward Merge** ![](https://i.imgur.com/uhVJNmG.png) 可以看到本地端的master已經和遠端的GitLab同步更新了 ![](https://i.imgur.com/fvUoNUi.png) :::info 假如有其他同事更新並且讓Maintainer合併了新進度。 你在Fetch或Pull更新master後,還需要將它拉到現在工作的分支。 現在我們來試一次: ::: 你正在dev_0.0.1這個分支上開發,確認現在有同事提交了MR且合併後,透過Pull > Fetch Only 看到了有 1 個變更,我們將它做一次 **Fast-Forward** 更新 ![](https://i.imgur.com/QPzFLNM.png) 對著master,右鍵按下 **merge** 並選擇 **Merge to working tree** ![](https://i.imgur.com/gSpjSSi.png) ![](https://i.imgur.com/2mT8aWN.png) 此時會看到具體被變更了哪一支檔案,點選檔案還可以看見修改內容 ![](https://i.imgur.com/s6dLrSC.png) 對著檔案做選取後(可以用shift多選,Mac OSX則能使用滑鼠範圍選取)右鍵 > Commit 來合併這個變更。 如果暫時不想合併,可以按下右上的Abort跳出這次合併,恢復到沒Merge的狀態。 ![](https://i.imgur.com/cBrQPPj.png) 可以看見變更合併到本地端成為新的commit了,再使用右鍵 > push,即可將遠端分支也一併更新成最新的狀態! ![](https://i.imgur.com/8bEp4aZ.png) --- **4. 衝突解決** --- 有時候運氣不好,跟同事沒協調好你們各自的工單是否會改到同一支檔案,或者你太久沒更新主線的code進來合併,造成merge時產生 Conflict(衝突) ![](https://i.imgur.com/ilBq6Vz.png) 衝突發生時Working Tree檔案列表處會顯示紅色的驚嘆號,告訴你這支檔案現在有衝突,需要解決。 打開編輯器看看該檔案,IDE或者VSCODE應該會顯示這樣的畫面 ![](https://i.imgur.com/03YJypy.png) `<<<<<<< HEAD (Current Change)` 代表你目前的變更。 `>>>>>>> conflict (Incoming Change)` 代表來源的變更。 在SmartGit上對著該檔案右鍵 > **Conflict solver** 開啟這個畫面 ![](https://i.imgur.com/5RjodxN.png) ![](https://i.imgur.com/NDg98Ob.png) 我們可以在Solver上加入或者移除變更,然後按下存檔Save,此時會問你要不要將這個檔案設為Stage,選擇是以後就可以解決這個衝突,然後commit。 :::info 如果你不習慣這個方法,參照以下方式: ::: 直接在IDE介面內解決 我們須確定這個變更是有必要的,且和你現有的變更是否需同時存在,假設你該做的部分剛好被其他同事 **「順手修掉」** 那可以選擇放棄現在的部分變更,採用**Accept incoming Change**,將對方的CODE覆蓋到自己的變更上。 如果必須同時存在彼此的變更,則按下 **Accept Both Changes** 僅保留自己的變更,捨棄對方來源變更,則是 **Accept Current Changes** 處理好後畫面上的色條就會消失,改好後存檔 ![](https://i.imgur.com/cYSjH9I.png) 對著標示衝突的檔案右鍵 > Stage 後 commit 即可完成解決衝突 ![](https://i.imgur.com/SnQQcb1.png) Commit 註解會自動產生關於衝突的記錄,Push後即完成這次的合併 ![](https://i.imgur.com/rCKK8Pj.png) 常見的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 進來擇日釋出 ![](https://i.imgur.com/v3odEN5.png) 流程概略 --- ![](https://i.imgur.com/Ztx4GWu.png) **準備開發階段:** 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: ![](https://i.imgur.com/xH6uBtG.png) 按下 Fork 會進入到這個新開專案的頁面,選好這個 Forked Repo 的所屬 Group 後即可 ![](https://i.imgur.com/NueBk1N.png) 接著複製這個 fork 好的專案 Git 位置,切換到 SmartGit 的選單clone到本地端 forked位置: `10.10.1.13/fortes-work/dummy-project.git` 主幹位置:`10.10.1.13/git_test/dummy-project.git` ![](https://i.imgur.com/aiWmrlk.png) --- 回 **GitLab 主幹 Repo** 上複製主幹的git位置,到SmartGit Remote > Add 將位置貼到 URL 欄位,命名 fork-source,按下 Add ![](https://i.imgur.com/uKz9ySh.png) origin下方會出現 fork-source,然後我們按一下Pull > Fetch Only 完成連接遠端 ![](https://i.imgur.com/UrSAwxO.png) 展開 fork-source,對裡面的 dev_0.0.1 點兩下,將這個分支命名為 source-dev_0.0.1,以後 Pull 更新的依據就是這個 source ![](https://i.imgur.com/4QZR1Ts.png) --- Fork 作業搞定後,我們來看看 GitHub Flow 究竟有什麼不同: 首先可以看到第一個不同點: 我們需要 ==**拉一支遠端的 fork-source 新增到本地端**== ![](https://i.imgur.com/LqiLUZB.png) 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 --- 流程概略 --- ![](https://i.imgur.com/adlnJlL.png) **準備開發階段:** 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`