git查看分支记录_git原理
標(biāo)準(zhǔn)用法請(qǐng)參考git-scm。本文記錄筆者對(duì)git的一些理解,如有錯(cuò)誤,歡迎指正。
引用內(nèi)容已用markdown記號(hào)標(biāo)出。版權(quán)所有,轉(zhuǎn)載請(qǐng)注明出處。
文章完成中
First Edition:2021-01-27
文中的記號(hào)約定
<當(dāng)前分支>:用尖括號(hào)包裹,需要被替換
軟件環(huán)境
筆者將介紹 命令行,TortiseGit,VS中g(shù)it的使用
git學(xué)習(xí)指引
更適合把git當(dāng)作某種數(shù)據(jù)結(jié)構(gòu)來(lái)理解,從底層理解git
git中的一些概念
git分支并不是一個(gè)實(shí)體,而是一個(gè)指針,分支只存放了指向某個(gè)commit的指針,不保存其他信息。在master分支創(chuàng)建新提交后,分支指針指向?yàn)樾碌腸ommit。
HEAD表示當(dāng)前指向的位置,master/main一般用于主分支。不要混淆兩者概念
working-tree index lib
working-tree為工作目錄,即可以直接操作
index,也稱(chēng)stage,git commit將當(dāng)前index狀態(tài)保存,即git commit不處理工作目錄
git基本命令
- add 添加文件到index
- commit 將當(dāng)前index提交到Local Repository
- checkout 修改HEAD指針 底層修改 ./git/HEAD
- switch 修改HEAD指針,使其指向某個(gè)分支而不是某個(gè)結(jié)點(diǎn)
- branch 創(chuàng)建分支
- reset 修改當(dāng)前分支的指針 底層修改文件 ./git/refs/head/<分支名>
git指令
git rebase
git revert
git reset
git checkout
git merge
git cherry-pick
git merge命令
當(dāng)前工作再branch_master分支,此分支指向commitA,develop分支指向commitB,(AB字母僅供標(biāo)識(shí),沒(méi)有其他含義)。使用指令git merge develop,創(chuàng)建一個(gè)新的commitC,commitC以commitA和commitB為父結(jié)點(diǎn)。再次強(qiáng)調(diào),git的分支是一個(gè)指針,存放在./git/refs文件夾下。分支所包含的結(jié)點(diǎn)是以類(lèi)似鏈表的方式的進(jìn)行查找的,并不是線性記錄在某個(gè)文件中。
git中刪除分支并不會(huì)直接刪除commit object,不過(guò)分支指針丟失了,難以進(jìn)行查找,并且git有g(shù)c垃圾回收機(jī)制,會(huì)清理懸掛對(duì)象。(git誤操作后恢復(fù)數(shù)據(jù)原理,分支指針被清除,對(duì)象并未清除,而且在./git/logs文件夾內(nèi)有日志。) git fsck 命令驗(yàn)證數(shù)據(jù)庫(kù)中對(duì)象的連通性和有效性。
git revert命令
當(dāng)前master分支有commitA commitB commitC
使用git revert commitA命令生成commitD,commitD的父節(jié)點(diǎn)為commitC,commitD的內(nèi)容與A一致,但并不破壞歷史記錄.
注:git對(duì)象是以鏈表的形式組織。鏈表上的結(jié)點(diǎn)不能自由移動(dòng),但可以對(duì)讀取結(jié)點(diǎn)上的內(nèi)容,創(chuàng)建新結(jié)點(diǎn),這看起來(lái)像是回到了某次提交。
git reset命令
修改當(dāng)前分支指向的結(jié)點(diǎn)(分支指針總是指向該分支的最后一個(gè)結(jié)點(diǎn),或者說(shuō)分支指針記錄了該分支最后一個(gè)結(jié)點(diǎn),checkout命令是移動(dòng)HEAD指針)
當(dāng)前master分支有commitA commitB commitC
git reset commitA后,如果沒(méi)有分支線包含commitB,commitC,那么B、C不會(huì)顯示在git log中(因?yàn)間it log是動(dòng)態(tài)搜索),B、C可能會(huì)被清除。
注:git使用鏈接式的數(shù)據(jù)結(jié)構(gòu)。
git cherry-pick命令
git區(qū)域
這幾個(gè)區(qū)域是使用概念上的區(qū)別。
git Working-Tree 即工作文件夾
git index index區(qū)內(nèi)容,注意這里不是空的,使用git add 命令,將file1添加到object和index內(nèi)。
git commit區(qū)域 git commit將index內(nèi)容打包到tree obejct,建立commit object,修改當(dāng)前分支的指針,在logs文件夾內(nèi)寫(xiě)入HEAD和當(dāng)前分支的變更日志。
在git中,數(shù)據(jù)存放在以sha1為鍵名的數(shù)據(jù)庫(kù)中,以鏈表方式組織數(shù)據(jù)。這樣數(shù)據(jù)更加靈活。
git reflog是保存到本地的,不保存到遠(yuǎn)程。git log是動(dòng)態(tài)計(jì)算的
git對(duì)象 blob tree commit
git引用 分支引用 HEAD引用 標(biāo)簽引用 遠(yuǎn)程引用
git本地的遠(yuǎn)程分支也僅保存指針,不保存數(shù)據(jù)。數(shù)據(jù)保存在object中。遠(yuǎn)程分支標(biāo)記了commit object。(由于sha1的特點(diǎn),一般地,不同的文件不會(huì)具有相同的sha1)
Git分支與數(shù)據(jù)不直接關(guān)聯(lián)。
數(shù)據(jù)中文件內(nèi)容和文件元信息不直接關(guān)聯(lián)。
commit不和文件直接關(guān)聯(lián)。
遠(yuǎn)程分支建立在本地objects上,而不是簡(jiǎn)單粗暴地下載遠(yuǎn)程文件與本地文件比對(duì)。
git fetch操作是下載遠(yuǎn)程分支所關(guān)聯(lián)地object(如果有某個(gè)結(jié)點(diǎn)有兩個(gè)父節(jié)點(diǎn),那么這兩個(gè)方向的結(jié)點(diǎn)都會(huì)被下載),然后下載遠(yuǎn)程分支指針。
git是以節(jié)點(diǎn)鏈表為核心,不是以孤立的分支為核心。
git保證了與分支所關(guān)聯(lián)的commit可以被安全保存。
patch分支修改了某項(xiàng)功能,隨后在master分支上merge patch分支,刪除patch分支。這三個(gè)節(jié)點(diǎn)都得到了保留。
附加:
TortiseGit
文件修改 文件增加 文件刪除 文件重命名
git演示1
- 命令行中g(shù)it init
- TortiseGit ,右鍵菜單Create repo
- vs中 (待補(bǔ)充)
- 手動(dòng)新建文件
- 或者 echo “<字符>” >> new.txt
- 或從 touch new.txt (windows下可能沒(méi)有此命令)
打開(kāi)文件,寫(xiě)入new conent并保存
注意:此時(shí) ./.git/objects文件夾內(nèi)并沒(méi)有生成對(duì)應(yīng)的文件
注意./git/objects/文件夾內(nèi)變化,增加了名為47的文件夾
查看該文件夾的內(nèi)容
使用git底層命令查看該文件的內(nèi)容git cat-file -p 47d2739ba2c34690248c8f91b84bb54e8936899a
使用同樣的方法創(chuàng)建new.txt文件,并將其添加到index。在objects內(nèi)生成了23/b6fc220420f74c5af7f34c106ef931a1fa15ea文件
注:47d2739ba2c34690248c8f91b84bb54e8936899a為內(nèi)容的sha1,實(shí)際上objects文件夾為數(shù)據(jù)庫(kù),sha1與內(nèi)容構(gòu)成了鍵值對(duì),按照<前2位sha1>/<后38位sha1>的方式存儲(chǔ)。
注:將文件提交到index后,new.txt文件的內(nèi)容已經(jīng)被保存到了數(shù)據(jù)庫(kù)中。即git add的作用并不是僅對(duì)文件做標(biāo)記,而是將其內(nèi)容保存到數(shù)據(jù)庫(kù)中。可以將其分解為底層命令git hash-object,并未保存樹(shù)對(duì)象
4.提交index到Local Repo
此時(shí),查看objects文件夾的內(nèi)容
新增了5d/ d4/文件夾
查看5d文件夾下新增文件的內(nèi)容
使用git cat-file -p <sha1>指令查看新增objects的內(nèi)容
使用git cat-file -t 指令查看新增objects的類(lèi)型
查看d4文件夾下新增文件的內(nèi)容
查看refs/heads文件夾
查看master文件的內(nèi)容
發(fā)現(xiàn)其內(nèi)容與新增的commit object的sha1一致。
總結(jié):使用git commit指令后 objects內(nèi)新增兩個(gè)文件,分別為tree object,commit object。refs/heads文件夾內(nèi)分支指針內(nèi)容被改寫(xiě)。
注:HEAD 與heads不同
6.繼續(xù)測(cè)試,使用git commit --allow-empty -m "empty commit"指令進(jìn)行一次空提交
注:使用windows下軟件everything 可以查看新增加的文件
以下文件的修改時(shí)間與剛才的操作時(shí)間匹配
分別為:
- ./refs/heads/master
- /logs/refs/heads/master
- /logs/HEAD
- 新增的object
- COMMIT_EDITMSG (猜測(cè),此文件可能供git comment --amend 選項(xiàng)使用)
查看master文件內(nèi)容,發(fā)現(xiàn)其指向了新的commit object
logs文件夾內(nèi),有兩個(gè)文件發(fā)生了變化
查看HEAD文件內(nèi)容,記錄了HEAD指針的變化,新記錄增加到文件末尾。第一個(gè)sha1值表示父commit,第二個(gè)sha1表示當(dāng)前的commit。第一次提交沒(méi)有父commit,所以用全0的sha1值表示。
查看master文件內(nèi)容,記錄了master指針的變化,新記錄增加到文件末尾
使用git log命令
其內(nèi)容與logs內(nèi)文件內(nèi)容相似,不過(guò)最新的提交在頂部,從新到舊。
使用命令git reflog
記錄了HEAD指針的變化。
注:HEAD@{N}表示HEAD之前的值
提問(wèn):logs記錄的日志是否供git使用
驗(yàn)證:將logs文件夾移動(dòng)其他位置,運(yùn)行g(shù)it log指令和git reflog指令
運(yùn)行g(shù)it log指令,變更內(nèi)容仍可輸出
運(yùn)行g(shù)it reflog指令,無(wú)內(nèi)容輸出。
將logs文件夾移回,git reflog命令可正常使用
總結(jié):git log遍歷objects來(lái)建立日志,git reflog查詢.git/logs文件夾下內(nèi)容
注:git中箭頭含義,箭頭表示指向該節(jié)點(diǎn),不能把箭頭當(dāng)作時(shí)間方向
TortiseGit介紹
學(xué)習(xí)指導(dǎo):要從底層理解Git工作原理,將高層指令細(xì)分了若干低層操作。Git指令過(guò)多,且指令效果復(fù)雜,如果把Git當(dāng)作黑箱,則有些功能難以理解。從Git的基本工作原理入手
Git Commit
這里ReCommit表示完成此次提交后不關(guān)閉當(dāng)前窗口,可進(jìn)行下一次提交。(與amend last commit不同)
Set author
Set author date 在Message中添加作者和日期。
Amend Last Commit (git commit --amend 修改上次提交)
Show Unversioned Files 是否顯示未受版本控制的文件
Message only 只提交Message,不提交文件
show log同git log
show reflog 同git reflog
Browser References:瀏覽引用,即瀏覽分支
Revision graph,顯示修訂版本圖(從圖中也可以看出,分支只是指針,不是分支實(shí)體)
Repo Browser 倉(cāng)庫(kù)瀏覽器,可快速查看不同修訂版本的內(nèi)容,不需要修改Working-Tree內(nèi)容。
git底層命令
git hash-object 寫(xiě)入object
git write-tree 將index內(nèi)容寫(xiě)入一個(gè)樹(shù)對(duì)象
git update-index 更新index
git cat-file [-p] [-t] [-s](pretty-print type size 查看文件
git 內(nèi)部原理分析(參考git-scm)
https://git-scm.com/book/zh/v2/Git-內(nèi)部原理-底層命令與上層命令1. git命令
分為底層命令(plumbing),上層命令(porcelain)
2. git文件目錄
(注意,info/ 表示文件夾 HEAD 表示文件。根據(jù)末尾的/來(lái)區(qū)分文件和文件夾)config(config 文件包含項(xiàng)目特有的配置選項(xiàng))description(僅供 GitWeb 程序使用)HEAD(HEAD指針,指向目前被檢出的分支hooks/(包含客戶端或服務(wù)端的鉤子腳本)info/(目錄包含一個(gè)全局性排除(global exclude)文件, 用以放置那些不希望被記錄在 .gitignore 文件中的忽略模式(ignored patterns)objects/(目錄存儲(chǔ)所有數(shù)據(jù)內(nèi)容)refs/(存儲(chǔ)指向數(shù)據(jù)(分支、遠(yuǎn)程倉(cāng)庫(kù)和標(biāo)簽等)的提交對(duì)象的指針)index(文件保存暫存區(qū)信息)3. git對(duì)象
- git對(duì)象(object)存放在./git/object/ 文件夾。以<hash的前兩位>/<hash的后38位>的結(jié)構(gòu)存儲(chǔ)
- 對(duì)象分為 數(shù)據(jù)對(duì)象(blob object),樹(shù)對(duì)象(tree object),提交對(duì)象(commit object)
- 數(shù)據(jù)對(duì)象僅保存了文件的內(nèi)容,沒(méi)有保存文件名。
- git cat-file -p <指定的sha1> 從Git中取回?cái)?shù)據(jù)(-p 表示pretty-print 自動(dòng)判斷類(lèi)型 -t表示查看object的類(lèi)型
- git hash-object -w test.txt 將test.txt寫(xiě)入Git
- 樹(shù)對(duì)象(tree object)
- 樹(shù)對(duì)象將文件組織到一起,一個(gè)樹(shù)對(duì)象包含了一條或多條樹(shù)對(duì)象記錄。每條記錄含有一個(gè)指向數(shù)據(jù)對(duì)象或者子樹(shù)對(duì)象的 SHA-1 指針,以及相應(yīng)的模式、類(lèi)型、文件名信息 * Git 根據(jù)某一時(shí)刻暫存區(qū)( index 區(qū)域,也稱(chēng)為stage區(qū)域,使用git
add命令后文件被添加到這里)所表示的狀態(tài)創(chuàng)建并記錄一個(gè)對(duì)應(yīng)的樹(shù)對(duì)象。 * 底層命令 git
update-index,必須為上述命令指定 --add - 文件模式為 100644,表明這是一個(gè)普通文件。 其他選擇包括:100755,表示一個(gè)可執(zhí)行文件; 120000,表示一個(gè)符號(hào)鏈接
- git write-tree 命令將暫存區(qū)內(nèi)容寫(xiě)入一個(gè)樹(shù)對(duì)象
- 樹(shù)對(duì)象將文件組織到一起,一個(gè)樹(shù)對(duì)象包含了一條或多條樹(shù)對(duì)象記錄。每條記錄含有一個(gè)指向數(shù)據(jù)對(duì)象或者子樹(shù)對(duì)象的 SHA-1 指針,以及相應(yīng)的模式、類(lèi)型、文件名信息 * Git 根據(jù)某一時(shí)刻暫存區(qū)( index 區(qū)域,也稱(chēng)為stage區(qū)域,使用git
- 提交對(duì)象(commit object)
- 調(diào)用 commit-tree 命令創(chuàng)建一個(gè)提交對(duì)象。為此需要指定一個(gè)樹(shù)對(duì)象的 SHA-1 值,以及該提交的父提交對(duì)象(如果有的話)。
- 如果你做完了以上所有操作,那么現(xiàn)在就有了三個(gè)樹(shù)對(duì)象,分別代表我們想要跟蹤的不同項(xiàng)目快照。 然而問(wèn)題依舊:若想重用這些快照,你必須記住所有三個(gè) SHA-1 哈希值。
并且,你也完全不知道是誰(shuí)保存了這些快照,在什么時(shí)刻保存的,以及為什么保存這些快照。 而以上這些,正是提交對(duì)象(commit
object)能為你保存的基本信息。 - 提交對(duì)象 保存tree的sha1值,作者,保存時(shí)間,提交備注
- 提交對(duì)象類(lèi)似于數(shù)據(jù)結(jié)構(gòu)中鏈表的結(jié)點(diǎn),保存自身信息和父節(jié)點(diǎn)的位置
總結(jié)
4.git引用(references,簡(jiǎn)寫(xiě)為refs)
筆者注:git引用可以理解為C語(yǔ)言的指針,指向某個(gè)地址。引用存放在.git/refs/heads/
對(duì)分支進(jìn)行操作時(shí)就是在操作【references】
如果想更新某個(gè)引用,Git 提供了一個(gè)更加安全的命令 update-ref 來(lái)完成此事:
Git 分支的本質(zhì):一個(gè)指向某一系列提交之首的指針或引用。
HEAD 引用
HEAD 文件通常是一個(gè)符號(hào)引用(symbolic reference),指向目前所在的分支。 所謂符號(hào)引用,表示它是一個(gè)指向其他引用的指針。
標(biāo)簽引用
然而實(shí)際上還有第四種。 標(biāo)簽對(duì)象(tag object) 非常類(lèi)似于一個(gè)提交對(duì)象——它包含一個(gè)標(biāo)簽創(chuàng)建者信息、一個(gè)日期、一段注釋信息,以及一個(gè)指針。 主要的區(qū)別在于,標(biāo)簽對(duì)象通常指向一個(gè)提交對(duì)象,而不是一個(gè)樹(shù)對(duì)象。 它像是一個(gè)永不移動(dòng)的分支引用——永遠(yuǎn)指向同一個(gè)提交對(duì)象,只不過(guò)給這個(gè)提交對(duì)象加上一個(gè)更友好的名字罷了。遠(yuǎn)程引用
遠(yuǎn)程引用是只讀的。 雖然可以 git checkout 到某個(gè)遠(yuǎn)程引用,但是 Git 并不會(huì)將 HEAD 引用指向該遠(yuǎn)程引用。因此,你永遠(yuǎn)不能通過(guò) commit 命令來(lái)更新遠(yuǎn)程引用。 Git 將這些遠(yuǎn)程引用作為記錄遠(yuǎn)程服務(wù)器上各分支最后已知位置狀態(tài)的書(shū)簽來(lái)管理。參考資料
總結(jié)
以上是生活随笔為你收集整理的git查看分支记录_git原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 为什么开不了4g网络_为什么4G网络越来
- 下一篇: kafka offset保存在哪里_《K