若你的 Git 專案有多人同時開發同一分支,在將修改結果 Push 到版控伺服器 (Github/TFS) 時應常會遇到以下狀況:

詳細訊息如下:

Error: failed to push some refs to 'https://github.com/darkthread/StepperExample.git'
Error: hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

原因很簡單,就是在取回最新版到修改完 Push 這段期間,版控主機上的分支已被其他人更新過,此時必須先將最新版 Pull 回本機才能 Push。

在 Visual Studio 遇到這種情況,解法是先點 Incoming Commits / Pull 抓回最新版,再點 Outgoing Commits / Push 上傳,或是直接點 Sync 一次做完 Pull + Push:

但有件煩人的事,每次 Pull 會產生一個名為 Merge branch 'master' of ... 的 Commit,若一堆人改得如火如荼,版本歷程圖便會生出一堆分叉線:

這樣有兩個缺點,一是平白增加一堆意義不大的 Commit,版本線圖也因此變得雜亂;第二,同是 master 分支,取回最新版也會產生 Merge 行為有違一般人對 Merge 的傳統認知 - 「融入其他 Branch 的內容」,常會使新手困惑。

針對這些缺點,git 提供了 pull --rebase 模式,以 Rebase 取代 Merge。( 對 Rebase 不熟悉的同學可參考龍哥的文章 另一種合併方式(使用 rebase) )。在 Visual Studio 2017+ ,如果想改用 pull --rebase,可透過 GUI 指定「Rebase local branch when pulling」:

修改後,Visual Studio 在 Pull 時會改以 Rebase 方式融入更新,不再產生額外的 Merge Commit,結果清爽許多:

至於改用 pull --rebase 的缺點,是遇到修改衝突時 Merge 只需解決衝突一次即可;Rebase 因需重算每一個尚未送出的本機 Commit,如果累積了五個 Outgoing Commits,就得解決衝突五次。若累積 Commit 較多又存在大量衝突,使用 Merge 較省事,實務上可視狀況彈性決定該用何者。


Comments

# by ypochien

我也是都預設用 pull --rebase,然而 Commit 衝突時,又不想一個一個 Commit 解決,只好先在本地端 rebase -i 透過 sqush 整理成 一個本機 Commit 再重新 Pull --rebase

# by Jeffrey

to ypochien, 先squash成一包是好方法,謝謝你的經驗分享。

# by abc0922001

我覺得最好的方式是先 git fetch 遠端分支,再依情況選擇 merge 或 rebase

# by Chaol

"多人同時開發同一分支" <- 應該要再把這個分支當作主線, 再分別做出個人的分支吧?

# by Jeffrey

to Chaol, 要做任何修改都先開分支是種策略,有優點也有成本,端賴團隊共識。

# by Jeffrey

to abc0922001, 可否分享 fetch 後分析該 merge 還是 rebase 的判斷訣竅?感謝

# by abc0922001

@Jeffrey,如果想讓 log 好看一點,rebase 是好選項;一方面讓 log 線不會有分岔線,另一方面可以整理 local 端的 log,重新思考什麼 commit 可以合併,什麼 commit message 要重寫或補充。有時候做到一半如果其他人 push,你也可以用 rebase 在最新的版本上繼續你的工作。 如果兩個分支在分歧點之後都有 Commit 上 remote 端,那 rebase 會改變父提交,push 就會失敗(用 push -f 不是好作法),所以只能用 merge 了

# by Jeffrey

to abc0922001,「rebase 在最新的版本上繼續工作」儘可能與 Remote 端同步這點還蠻重要的,脫節太嚴重,合併會變困難,有時還需從頭測試。謝謝你的分享。

Post a comment