讀書筆記 --《Pro Git》
關於《Pro Git》的閱讀筆記,查漏補缺,補充Git的相關知識。
資料
物件模型
Git儲存的並不是檔案差異,而是一系列不同時刻的被修改檔案的快照。可以把Git理解為一個本地的內容定址檔案管理系統,管理著眾多版本的檔案。
下圖是Git儲存的物件,其利用樹結構指向不同的版本。

Blob
Blob通常用來儲存檔案內容,做檔案映象使用。

Tree
在工作區做的變更使用樹形來維護,樹可以指向Blob,也就是變更檔案,或者指向其他的樹來關聯未變更的檔案。

Commit物件
Commit物件指向 一個 tree物件,另外Commit中還儲存著相關提交者資訊,以及上一個提交,一個Commit可能存在多個parent物件,比如兩個分支匯聚到一點,產生的這個commit就會有兩個parent。

Tag
Tag指向一個Commit物件。

工作模型
Git的工作模型揭露了我們在git專案中所採取的操作造成的影響。

Work Directory:工作空間,就是被Git所管理的本地專案目錄。
Index:可以理解為Git的暫存區。
Head:當前所在的分支,其指向當前已經commit的最新內容。
1. 本地新增檔案
本地新增只會改變work directory

2. git add
新增到暫存區,本質上是把本地目錄修改的檔案copy一份到Index區域。

3. git commit
Commit之後Head對應的本地分支中也會多一份檔案映象。

瞭解了這些那麼很多命令就很好理解了。
1. git status
status實際上就是比較三個空間的差異,Index區域使用綠色,work directory使用紅色。
2. git reset
reset操作有三個等級, --soft
下只會回滾HEAD區域的檔案內容。 --mixed
會回滾HEAD以及INDEX區域的內容。 --hard
則會回滾全部區域的內容。
3. git revert
revert的操作可以理解在Work Directory把對應commit的修改全部撤銷掉,然後新增到INDEX區域 ,最後合併到HEAD區域產生一個新的commit。
操作
刪除已提交檔案
git rm --cached <檔名># 從已提交的內容中刪除檔案,刪除後重新提交即可刪除遠端倉庫的該檔案。 git rm <檔名># 與上述類似,不過會連本地檔案一起刪除
修補提交
工作中經常遇到提交了commit之後發現有東西忘記提交了,然後又起了一個commit,實際上可以通過修改最後一次提交方式搞定。
# 該命令本質是把暫存區的檔案和最後一次提交併入一起,如果指定了檔名,則把該檔案與最後一次提交併入一起。 git commit --amend [檔名]
變基Rebase
當前在experiment分支,執行
git rebase master
,Git會進行如下操作:
- 找到C4,C3最近的共同祖先C2
- 找到C2-C4之間的所有變更檔案,存為臨時檔案。
- 將當前分支Head指向C3
- 依次把臨時檔案應用在C3,這個過程中會產生衝突,產生則需要手動訂正,然後
git rebase --continue
繼續apply
Rebase原則:“只對尚未推送或分享給別人的本地修改執行變基操作清理歷史,從不對已推送至別處的提交執行變基操作”
pull –rebase
普通的 pull
= fetch
+ merge
, pull --rebase
= fetch
+ rebase
reset –hard誤操作
一個迭代分支可能是 C1 -> C2 -> C3
,然後執行 git reset --hard C1
,那麼C2和C3的修改 就會丟失,此時沒有指向他們的引用,不過因為Git每次都是映象儲存,因此只需要找到C2和C3對應的提交ID,即可恢復。
使用 git reflog
檢視HEAD指標改變的歷史記錄,從中找到對應的CommitId,使用 “git branch newbranch commitId”
建立一個新的分支,指向該次提交,找回丟失的檔案。
引用日誌會被清理的,如果沒有則可以使用 git fsck --full
,該命令列出所有未被其他物件指向的commitId。
大檔案刪除
假設某人誤操作向Git中提交了大檔案,產生了一個commit,然後刪除了該大檔案,又產生了一個commit,對於之後的人clone,由於要拉下來完整的變更,因此每次都需要下載含有大檔案的映象。
解決方案是找到大檔案的歷史提交,然後重寫對應的提交以及之後的提交。
-
git verify-pack -v .git/objects/pack/壓縮pack.idx | sort -k 3 -n | tail -3
,pack指定你自己的,該命令列出比較大的一些commitId -
git rev-list --objects --all | grep commitId
,使用該命令檢視該次commitId提交的大檔名稱 -
git log --oneline --branches -- 檔名
,使用該命令檢視對該檔案進行過改動的提交,記錄下第一個改動的id -
git filter-branch --index-filter \ 'git rm --ignore-unmatch --cached 檔名' -- 第一次改動Id^..
,執行該命令,重寫第一次提交大檔案之後的所有相關修改,使用git rm --cached
來刪除之前的提交記錄。 -
rm -rf .git/refs/original
,rm -rf .git/logs
,git gc
,移除包含有舊提交指標的檔案,並且 重新打包。
撤銷合併
有時候已經合併到了master分支,但是需要回滾程式碼,那麼就涉及撤銷操作。
revert方式
在git提交資訊中,commit分為兩種,一種是開發提交的commit,一種是merge產生的commit,對於merge commit一般會有兩個parent節點。 git revert
一般有兩種形式:
git revert <commit id>
,撤銷指定的commit,Git會把該commit的修改全部撤銷,併產生一個新的commit。
git revert -m 1 <merge commit id>
,-m引數表示兩個合併父節點的第一個還是第二個,該操作會把對應的合併內容全部撤銷,併產生一個新的commit。
注意revert掉的分支在此合併會出現無法合併的現象,因為撤銷後被撤銷的分支實際上與當前倉庫沒有檔案關聯,解決方案是撤銷Revert節點,然後再次合併該分支。