以前在學前端的時候,基本上是自己做自己的專案,即使到了和同學協作完成作業的那時候,也因為我那一屆很悲悽的只有我一位前端,所以在git的操作上,並沒有協作的經驗。(因為後端和前端各自開一個repo)所以基本上我就只會最基本的clone、pull、push,嚴格來說也都只是會一些很皮毛的用法。直到這陣子,真的必須有很多需要透過git來大量協作的業務後,才發現自己再不好好搞懂真的不行啊!每次遇到都要問一次同事也不是個好現象QQ
因此就誕生了這篇學習筆記!
這次就先從和別人協作時,比較常會遇到的merge和rebase這兩個動作開始。
merge是什麼?
merge這一個詞中文意思是合併,用途也就是把分支內容合併到指定分支。我自己目前在實務上通常會有兩個情境需要merge。
情境一、將新修改的內容合併回主要分支(merge branch into main branch)
有新的修正內容,或新的開發時,會另外開一個分支作業,當在那個分支上作業完成時,就會在把這個分支合併到主要branch上(實務上,可能會是將修正或是新開發功能的分支合併到develop這個branch上)。
情境二、將已經有更新內容的主要分支合併(同步更新)到新修改內容的分支上(merge main branch into branch)
當在分支上進行要做的修正或新開發時,如果已經有其他人將自己手上的分支合併回去主要分支的時候(也就是第一個情境),自己分支的基礎內容(也就是分支上的主要分支內容),就會有一部分和現在最新的主要分支內容不一樣。因為當我們開分支時,複製出去一份的基礎內容是主要分支被更新前的內容,如果「主要的分支上的新改動與自己分支上的改動檔案有重疊,但又要把自己的分支合併回主要分支前 」或「手上的分支的內容,需要主要分支更新的內容時」,都需要做這個動作。
指令用法:
git checkout 要合併進去的分支名
git merge 要合併的分支名
rebase是什麼?
如果查詢rebase這個詞的中文,會查詢到「變基」這個奇怪的詞,不過如果把rebase這個字,拆成兩個字,"re"和"base",就比較好理解是什麼意思了。簡單來說,就是「重新定義基底」、「重新定義基礎」。這個動作我比較少使用,因為主要使用的情境,透過merge也可以辦得到。主要會需要使用的情境如下:
情境一、將分支的基礎內容重新定義成主要分支(rebase branch to main branch)
這個情境跟前面merge的第二個情境的目的一樣,只是達到目的的實際過程不太一樣,這裡我們先理解成目的一樣就可以了。
指令用法:
git checkout 要重新定義基底的分支
git rebase 要當作基底使用的分支
merge和rebase的使用方式
這邊來用幾個比較具體的情境來看一下怎麼使用merge和rebase。
merge的情境
情境一、在分支中新增一個style檔案進行style調整完成後,將這個分支合併回主要branch
合併前的圖表
步驟:
(1) 切換到要合併進去的分支 git checkout main
(2) 輸入merge指令 git merge phoebe/feat/style
合併後的圖表
可以發現main和分支(phoebe/feat/style)跑到同一個點
*在專案實務中,通常會在這個步驟進行前發PR(pull request),當公司內部的其他協作人員進行code review後,確定沒有問題會幫忙按下approve,達到最低需要的approve 人數後,才可以進行merge的動作。
再來試試另一種merge指令 git merge --no-ff 要合併的分支名
合併前的圖表
步驟:
(1) 切換到要合併進去的分支 git checkout main
(2) 輸入merge指令 git merge --no-ff phoebe/feat/style
合併後的圖表
可以發現main一樣往上長了,但旁邊多了一條代表分支的黃線,並且呈現出main現在的狀況是合併分支後的狀況,而且可以清楚查看到分支的commit歷程,也會在commit紀錄中顯示merge branch "branch name"。
*注意!git merge 預設是用fast-forward的方式進行,就如同第一次嘗試的圖表,只會有一條線出現,若透過指令--no-ff來使用no fast-forward的方式merge,就會如同第二次嘗試的狀況一樣。
情境二、在開【phoebe/feat/new-content】分支,並且新增內容的期間,已經有其他分支【jolin/feat/new style】合併回主線。
- 如果想要把【phoebe/feat/new-content】分支合併回去,擔心會產生衝突,就會需要先把主線合併到【phoebe/feat/new-content】分支。
- 或者是【phoebe/feat/new-content】分支上的開發內容需要【jolin/feat/new style】分支的內容,就會需要在合併回主線前,先把已經含有【jolin/feat/new style】分支的主線內容先合併過來。
合併前的圖表
這裡可以看到main已經跑到【phoebe/feat/new-content】分支的前面,所以【phoebe/feat/new-content】分支和主線相異的內容除了這次在分支上修改的內容外,還有其他分支合併回去的內容。
步驟:
(1) 切換到要合併進去的分支 git checkout phoebe/feat/new-content
(2) 輸入merge指令 git merge main
合併後的圖表
這裡可以看到commit紀錄多了merge branch 'main'into phoebe/feat/new-content。
rebase的情境
情境一、在分支【phoebe/feat/new-style-2】被創建後,且在分支【phoebe/feat/new-style-2】上進行開發的期間,已經有其他跟這次的開發內容相關的分支【phoebe/fix/style】合併回主要分支,需要讓合併回主要分支的【phoebe/fix/style】分支內容也同步到【phoebe/feat/new-style-2】分支,因而進行rebase。
合併前的圖表
(1) 切換到要重新定義基底的分支 git checkout phoebe/feat/new-style-2
(2) 輸入rebase指令 git rebase main
(3) 最後再把rebase過的分支push
合併後的圖表
這時候可以發現rebase完成後的分支【phoebe/feat/new-style-2】會從當前的main長出來,代表他的基底是最新的main。
這邊最後再補充一個最近的使用情境
我和後端同事在一條從主線開的分支上,做同一張單的功能,我已經把我做好的內容push上去,過沒多久後端同事跟我說他推上我們共用的這個分支時,不小心覆蓋掉我推上去的內容了。但是在我local端的這隻分支上還存在著剛剛推上去的修改內容,所以這個時候只要把我local的這隻分支進行rebase,把基底同步成remote上的這個分支(也就是已經有後端同事修改內容的分支),最後在進行push,分支上就會有後端同事的修改內容和我自己的修改內容了。
merge和rebase的差異
最後來比較一下這兩個操作的差異。
1. 使用merge,若使用--no-ff(no fast forward)可以保留分支的commit歷程,且在圖表上可以明顯看得出是哪個分支合併到哪個分支。
2. 雖然rebase的操作結果,也可以透過merge達到,但是透過rebase,會代表一個更明確的意思就是「重新定義基底」,因此圖表會變成從要變更的基底長出來。
我自己目前的使用情境大多數都是以merge為主,偶爾才會遇到用rebase比較適當的情境。
好啦!這是近期使用merge和rebase時,有出現一些搞不懂的狀況,而寫的學習筆記。
打完收工!
留言列表