在MSys版的Git中使用git pull --rebase進行代碼更新到底是做了什麼?

每次想push代碼時,總需要先git pull --rebase進行更新。網上說git fetch,git merge,git pull,這些命令具體有什麼區別呢?


git pull的默認行為是git fetch + git merge,

git pull --rebase則是git fetch + git rebase.

從目的來說,兩者沒差別,運行之後, 你能獲得一樣的code base。

但從版本管理角度,這兩者有各自的使用意義。

git merge:

簡單來說,它把兩條不同分支歷史的所有提交合併成一條線,並在「末端」打個結,即生成一次合併提交。最後形成一條單一的提交線。

git rebase:

根據參數的不同,行為有些差別。但總的來說,它相當於把分叉的兩條歷史提交線中的一條,每一次提交都撿選出來, 在另一條提交線上提交。最後也形成一條單一的提交線。

對比來看,git merge多了一次提交--「合併提交」。git rebase則沒有。

不過,git merge保存了兩條線的歷史。而git rebase則會破壞歷史。因為每一次rebase, 提交id會變化(因為父提交變了,而父提交Id是用來生成提交id的內容之一)。

那誰好誰壞呢?沒有絕對答案。得看使用者的角色。舉個例子。

git的使用者中,典型的是Linux內核社區。 他們採用的是一種叫司令官與副官工作流(dictator and lieutenat workflow)。在這種模式中, 有若干個管理員, 分別負責項目中的特定部分,是為副官(lieutenant); 所有這些管理員頭上還有一位負責統籌的總管理員,是為司令官(dictator)。司令官維護的版本庫用於提供給所有項目協作者(不僅僅是副官, 還可以包括來自全球的"士兵"), 以供他們拉取集成的項目代碼。

Linus本人就是上述中的司令官了,每次他從其他子系統維護者那拉代碼時,用的是git merge.. 原因是,git merge生成一次合併提交,這就是一個明顯的標誌,告訴其他人,這次從某人合併來了什麼代碼,為什麼要合併這些代碼。等等。他不能使用git rebase, 原因是這樣會改變歷史。比如某一次在某子系統維護者處的ID是AAAA.....AAAAA, 他希望進了Linus代碼庫後還是這個ID,這樣他在郵件或其他地方可以引用這個ID,不用擔心變化。但是,如果使用git rebase, 這個提交ID是會變的,這樣他引用的ID就沒用了。

作為個人開發者,一直follow著Linus的版本庫, 叫mainline,那麼可以自由地選擇git merge或git rebase, 因為你這隻有單一一條時間線,沒差別。但是,一旦你開始作了很多次本地的代碼修改,在本地生成了提交,這就意味著你和mainline分叉了,這樣,你下次更新代碼時,一定要選擇git

rebase, 把你的自己的提交rebase到mainline上, 即始終保持你自己的代碼在mainline之上。不推薦使用git merge, 因為你的版本庫是當作mainline鏡像,你一merge就變成跟mainline不同了,下次再更新代碼就會衝突。


這個問題在SO上有兩個極好的答案,自己看吧:

Difference between git pull and git pull --rebase

What"s the difference between "git merge" and "git rebase"?

還一個中文的,不過這個是不推薦的!!!反例!!!文中作者其實是用SVN的方式來用GIT,完全沒有發揮出Git的好處。文章下面的評論倒是不錯的。

從git merge 和 git rebase想到……


rebase就是假裝你這份代碼是從你指定的那個commitment開始改的,git會重新計算diff,然後存進去。主要是為了減少一些垃圾commitment出現在history裡面。


git初學者,這是我之前找到的一張圖,覺得可以作一部分參考:

兩年以後來更個新,這邊博文很不錯,不過可能需要梯子:https://ihower.tw/blog/archives/3843


初學者,試著回答一下。

rebase:

1. 獲取(fetch)新版遠程庫代碼。

2. 把你針對舊版遠程庫代碼(base)所進行的所有提交修改(re)為(線性的)針對新版遠程庫代碼的提交。

此時可將新的提交push到遠程庫。

這樣做的好處在於可以在遠程庫的提交歷史中保持一條直線,沒有分叉,沒有merge,因為所有提交都是針對提交時最新的遠程庫進行的。


fetch --- 同步遠程commit和branch指針到本地 但不改變本地branch

merge --- 合併branchA到另一個branchB, 使得branchB包含branchA的內容

pull --- fetch 且merge當前branch的遠程版到當前branch


推薦閱讀:

如何使用10個小時搭建出個人域名而又Geek的獨立博客?
GitHub 上有什麼好玩又有挑戰的前端項目?
SourceForge 是如何一步一步被 GitHub 超越的?
自己在github上寫的開源項目沒有人star是怎樣的一種體驗?
github上利用jekyll搭建自己的blog的操作順序?

TAG:版本控制系統 | 軟體開發 | Git | GitHub |