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