Pro Git --- 讀書筆記 (Chaptero3)
Git 分支
- 在執行提交操作的時候,Git會儲存一個提交物件,該物件包含一個指向暫存內容快照的指標,以及它的父物件的我指標。
- 暫存操作會為每一個檔案計算校驗和,然後把當前版本的檔案快照儲存到Git倉庫中,最終將校驗和加入到暫存區等待提交
- 當使用提交操作時,Git會先計算每一個子目錄的校驗和,然後在Git倉庫中儲存這些校驗和為樹物件,隨後,Git會建立一個提交物件,它包含指向這個樹物件的指標
- 現在Git倉庫中有五個物件:三個blob物件(儲存檔案快照)、一個樹物件(記錄目錄結構和blob物件索引)以及一個提交物件(包含著指向樹物件的指標和所有提交資訊)
- git的分支,其實本質上僅僅是指向提交物件的可變指標
分支建立
git branch <branch>
- 建立一個分支,本質是建立一個新的可以移動的指標
- HEAD指標表示當前分支的特殊指標
分支切換
git checkout <branch>
- 切換到某一個分支,這樣HEAD指標就會指向那個分支
- 然後再次提交之後,分支會向前移動,但是另一個分支卻沒有
- 分支切換會改變工作目錄中的檔案
-
專案分叉
-
注意,切換分支之前,要留意工作目錄和暫存區中還沒有被提交的修改,它可能會和即將檢出的分支產生衝突從而阻止Git切換分支,最好在切換分支之前保持一個乾淨的狀態
-
請牢記:當你切換分支的時候,Git會重置你的工作目錄,使其看起來像回到了你在那個分支上最後一次提交的樣子,Git會自動新增、刪除、修改檔案以確保此時你的工作目錄和這個分支最後一次提交時的樣子一模一樣
分支合併
git merge <branch>
- 合併分支
git branch -d <branch>
- 刪除分支
分支管理
git branch
- 列出所有的分支
git branch -v
- 檢視每一個分支的最後一次提交
git branch --no-merged <branch>
- 檢視還沒有合併到特定分支的其他分支
遠端分支
遠端引用是對遠端倉庫的引用(指標),常用做法是利用遠端跟蹤分支。
遠端跟蹤分支是遠端分支狀態的引用,它們是無法移動的本地引用,一旦進行了網路通訊,Git就會幫你移動它們以精確反映遠端倉庫的狀態,可以當作書籤。它們以<remote>/<branch>
- 克隆之後遠端與本地的兩個master指標
- 遠端倉庫有其他人更新了
- 本地執行
git fetch <remote>
之後,拉取了遠端倉庫的更新,遠端指標發生移動
- 推送本地分支到遠端倉庫之前,別人是看不見你的私人分支的,公開分支是需要你主動推送才可以公開
git push <remote> <branch>
// 或者
git push <remote> <local-branch>:<remote-branch>
-
在fetch之後,就算有新的遠端跟蹤分支,本地是不會自動生成一份可編輯的副本。換句話說,這種情況下,不會有一個新的
<branch>
出現,只有一個不可修改的<remote>/<branch>
指標 -
當需要這個分支的時候,需要主動執行
git merge <remote>/<branch>
指令,將這些工作合併到當前所在分支 -
如果想要在自己的分支上工作,可以將其建立在遠端跟蹤分支上
git checkout -b <branch> <remote>/<branch>
// 這個指令本地分支會有一個“跟蹤分支”
-
從一個遠端跟蹤分支檢出一個本地分支會自動建立所謂的“跟蹤分支”(它跟蹤的分支叫做“上游分支”)。如果在一個跟蹤分支上執行
git pull
,Git能自動識別到哪一個分支上抓取,合併到哪一個分支 -
修改已有本地分支的上游分支
git branch -u <remote>/<branch>
- 可以使用
@{upstream}
或者@{u}
來引用它的上游分支
git merge <remote>/<branch>
等價於
git merge @{u}
- 檢視設定的所有跟蹤分支
git branch -vv
- 刪除遠端分支
git push <remote> --delete <branch>
變基
// 以<baseBranch>為基底,將<topicBranch>的補丁重放一遍
git rebase <baseBranch> <topicBranch>
- 整合分支最容易的方法是
merge
命令,它會把兩個分支的最新快照以及二者最近的共同祖先進行三方合併,合併的結果是生成一個新的快照
- 還有另外一種方法就是
rebase
指令,它是通過提取需要合併的分支從共同祖先提交開始的所有引入的補丁和修改,然後在當前分支的基礎上應用一次。也就是將某一分支上的所有修改都轉移到另一分支上,就像“重新播放”一樣
// branch1當前分支,branch2變基操作的目標基底分支
git checkout <branch1>
git rebase <branch2>
// 再進行一次快進合併
git checkout <branch2>
git merge <branch1>
-
與直接
merge
相比較,最終結果都是一樣的,但是經過變基使得提交歷史更加整潔 -
一般這樣做的目的是為了確保在向遠端分支推送的時候能保持提交歷史的整潔
git rebase --onto master server client
- 以上指令的意思是“取出client分支,找出它從server分支分歧之後的補丁,然後把這些補丁在master分支上重放一遍,讓client看起來像是直接基於master修改一樣”
變基的風險
-
如果提交存在於你的倉庫之外,而別人可能基於這些提交進行開發,那麼不要執行變基
-
變基操作的本質是丟棄一些現有的提交,然後相應地新建一些內容一樣但實際上不同的提交。如果你已經將提交推送到某個倉庫,而其他人也已經從該倉庫拉取提交併進行了後續工作,此時,如果你用
git rebase
重新整理了提交併再次推送,你的同伴將不得不再次將他們手頭的工作於你的提交進行整合,如果接下來你還要拉取並整合他們修改過的提交,事情將會變得一團糟 -
如果真的出現了這個情況“有人推送了經過變基的提交,並丟棄了你的本地開發所基於的一些提交”,那麼我們應該執行
git rebase <remote>/<branch>
,Git將會做一些操作- 檢查哪些提交是我們分支上獨有的
- 檢查其中哪些提交不是合併操作的結果
- 檢查哪些提交在對方覆蓋更新時並沒有被納入目標分支
- 把這些提交應用在
<remote>/<branch>
上面
- 面對的情況
- 執行
merge
之後,會變得混亂
-
再次變基之後,Git自動計算之後,會生成友好結果
-
牢記:只對尚未推送或分享給別人的本地修改執行變基清理歷史,從不對已推送至別處的提交執行變基操作