理解 Git

主要內容介紹

1.設計思想

2.數據流向

3.git flow

4.其他介紹

5.思考討論

6.參考資料

1.設計思想

1.快照記錄,每一次commit ,記錄工作目錄的完整快照。
2.不變模式,任何改變都將生成一個新的對象(類似java string 設計)。
3.分布式 ,幾乎所有操作都在本地倉庫完成(非常高效且無依賴),不同節點可以通過同步來更新內容。
4.復用,使用對象池復用對象,相同內容的文件,在對象池中只會存儲一份。

2.數據流向

git數據交互.png

2.1術語

  • work-dir :
    表示工作目錄,與.git 綁定的目錄,其他名稱(working-tree,工作空間)
    不一定與.git 目錄在相同的位置(默認是相同的)

  • repo:
    表示.git 目錄里面的內容

  • commit-tree:
    每一次提交對應的tree,其他名稱(tree,tree-ish,commit),commit 結構見 4其他介紹

  • index/cache:
    對應.git/index 文件,其他名稱(cache,index,stage(區別于 stash))

  • object-pool:
    對應.git/objects/ 目錄下面的內容,里面存有的對象有 blob(文件),tree(dir and subdir) ,commit ,tag

2.2數據流向

1.repo(object-pool) —> work-dir
2.work-dir —>repo(object-pool)
3.git-inter(object-pool) —>merge object (object-pool)-->new object(object-pool)

2.3 主要操作:

  1. 無work-dir, 向repo 寫入內容,
  2. 使用work-dir 向repo 寫入內容
  3. repo內容檢出到work-dir
  4. work-dir,index(cache),repo(commit-tree),比較
  5. commit-tree 構建,新增,合并,重建,撤銷
  6. commit-log 查看

2.4 測試結果查看關鍵命令

查看work-dir 查看repo 內容
ls git ls-files :查看index 文件內容。git ls-files -s:查看index 文件內容,并且顯示blob id
tree git ls-tree [commit-id] :查看commit 對應的tree 結構,以及在tree 上面所有的文件
cat git cat-file -t <blob-id>:查看blob 文件類型,blob-id 為對象池里面對應對象的id
find find .git/objects -type f : 查找文件 find ./ -mmin -1 -type f :查找最近一分鐘修改的文件 git log:查看commit log, (其他命令git show ) git log --all --graph —oneline:查看所有提交日志 git log --graph --oneline :查看當前分支提交日志
git diff: 比較[repo ,work-dir], [repo,repo],[repo,index],[index,worlk-dir] 其他比較命令:diff-tree/diff-files/diff-index
git status : work-dir ,index,tree 對比后的狀態查看
git for-each-ref :查看所有引用(指針)

2.5 測試以及命令解釋

2.5.1 無work-dir, 向repo 寫入內容

詳細描述: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
主要命令:

  • git hash-object : 向object-pool 寫入文件對象
  • git update-index : 向 index 文件添加 blob 記錄(關聯到blob)
  • git ls-files -s : 查看index 文件內容
  • git write-tree: 用index 文件內容向 object-pool 寫入tree 對象
  • git read-tree : 用commit-tree 生成內容,寫入index 文件
  • git ls-tree: 查看tree 內容
  • git commit-tree : 寫入commit 對象
  • git log : 查看commit 日志

2.5.2 使用work-dir 向repo 寫入內容

  • git stash : 暫時保存work-dir /index 內容,產生一次特殊的commit(stash commit)


    stash-commit.png
  • git add : 工作空間內容添加到object-pool,index (cache)文件記錄添加的文件以及blob-id

  • git commit:生成 commit 對象,用index中的文件內容構建commit-tree(tree)

注:流程:工作空間—>緩存(index)—>存儲

2.5.3 repo內容檢出到work-dir

  • git checkout :檢出repo 到work-dir,index,修改相關指針(HEAD ,分支),repo 對象(blob,tree)
  • git checkout-index: 用index 文件記錄的內容,覆蓋work-dir,repo 對象 為 blob,tree
  • git reset:git add 的逆操作 ,修改index,修改work-dir,修改指針(HEAD),repo 對象為 blob,tree
  • git revert :git commit 的逆操作,repo 對象為 tree

注:
1.blob 可以用文件路徑引用,tree 用commit-id引用,tree 對象比較時,如果是文件增加減少一般可以自動完成操作,如果涉及同一個文件的多次修改,操作可能失敗,需要合并tree。
2.流程:工作空間<—緩存(index)<—存儲

2.5.4 比較working-tree ,index, tree

  • git diff : 默認 working-tree diff index ,—cached [commit-id] : index diff tree,
  • git diff [commit-id] :tree diff commit-id-tree
  • git diff-index :git diff-index [commit-id],當前index 比較 commit-id-index
  • git diff-files :working-tree-file diff index-file
  • git diff-tree [commit-id]:比較tree,commit-id-tree diff commit-id-parent-tree


work-dir,working-tree 表示相同含義
index ,cache,cache-tree表示相同含義
commit-tree,tree,commit 表示相同含義

2.5.5 tree (commit / commit-tree) 構建,新增,合并,重建,撤銷

  • git commit:生成 commit 對象,用index中的文件內容構建commit-tree(tree)
  • git merge : 當前分支的HEAD(tree) 合并 其他分支的HEAD(tree),生成一個新的tree ,且當前分支的指針移動到新的tree
  • git rebase :以 onto 為新的基點,重新構建 [to'parent ,to] 這一范圍的tree
  • git cherry-pick:以cherry-pick 的commit ,重新構建當前分支的tree
  • git revert:將 revert [commit] 的內容,從當前分支tree移除,并產生一次新的提交來構建新的tree

2.5.6 commit-log 查看

  • git log ,- - online :一行日志 ,- - graph 圖形展示,—pretty=raw 原始格式 - -all 所有分支,默認為當前分支
  • git show :見 git help show
  • git whatchanged:見git help show

3. git flow

  • 指針介紹:指向某一個提交的commit (也就能找到對應的tree)
  • 分支(如下圖)
    master :指向F ,通過尋找parent commit 就可以構建一條完整的鏈路。
    experiment: 指向D,通過尋找parent commit 就可以構建一條完整的鏈路


    branch.png
  • 當前分支:當前分支指針位置(最后一次commit-id),值保留在HEAD 里面
  • stash 指針:git stash 產生的提交,最后的commit-id
    標簽:也是指向一次commit-id 的位置,是不可變的(普通的分支還能進行提交)
    注:分支存儲位置 .git/HEAD ,refs/*,里面都是保留最新的commit-id
  • 分支其他引用表示:
    commit-id :commit-id的前幾位可以定位,只要依據前幾位能夠定位到內容
   $ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
   $ git show 1c002dd4b536e7479f
   $ git show 1c002d

HEAD@{5}/stash@{1}:reflog 與stash 引用
HEAD^[number] :head 的父節點,可以引用多個父節點(一個節點可能有多個直接父節點)
HEAD~[number] :head的父節點,只能指明第一個父節點
詳見: https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection

3.1 分支協作

  • 單遠程倉庫:
    master:穩定分支,默認分支
    feature:功能分支,一般完成合并后,刪除
    hotfix: 緊急bug 修復分支
    develop:開發分支

  • 多遠程倉庫:一個本地倉庫可以對應多個遠程倉庫,可以同時在多個倉庫協作開發。比如github fork, pull request 等操作

    注:多倉庫配置見 git help config ,git help remote

4 其他介紹

  • .git目錄
    HEAD :保存當前分支指針,指向refs
    index :緩存當前work-tree 目錄結構以及文件,以及文件狀態
    objects: git 的數據庫,保存所有對象(tree,blob, tag ,commit) 。
    refs: 保存所有分支/tag(每個分支/tag記錄自己當前指針位置)

  • 配置 見 git help config

  • git數據結構

    • blob對象:
      header={[blob-type][空格][content.length][\0]}
      body={[content]}
      sha1 = Digest::SHA1.hexdigest(header+body)
      store=Zlib::Deflate.deflate(header+body)

    • commit 對象:
      tree: 指向tree 對象的id
      parent:父commit (可能有多個parent,比如合并)
      author: 作者
      committer:提交者
      msg/log: 備注信息,日記顯示內容
      commit-結構示例(如下圖):


      commit-結構示例
    • tree 對象:
      記錄文件,目錄關系,以及文件對應的屬性(修改時間,創建時間,文件類型等)

    • index 文件:
      記錄working-tree 目錄下面所偶遇文件以及文件對應的屬性(修改時間,創建時間,文件類型等)
      文件不同區域對應的id, tree-hash-id,cache-hash-id,wdir-hash-id,通過對比不同區別的id 值來判斷文件狀態

5 思考/討論

1、怎么合并tree ,以及找到tree 不同,git怎么決定沖突的?

1、 commit1-tree1,commit2-tree2
2、如果commit1是commit2 的祖先,直接使用commit2-tree2 (直接前驅,使用最新版本,無沖突)
3、commit1 與commit2 不是直接沒有直接的祖父關系,則比較 tree1 ,tree2 ,
4、tree1,tree2 上面含有相同的文件路徑,但是文件內容不同,則產生沖突。需要手動處理。(無法判斷那一次的內容是最新版本,)
5、沖突處理方式, 使用 tree1(ours) ,使用tree2 (others),使用手動處理的版本
6、tree1,tree2 合并后產生一個新的tree-new。

2、git status 顯示文件狀態依據?

依據working-tree ,index(cache),tree 里面的對應的hash 值來判斷。

3、怎么顯示增量更新內容?

比較兩次提交的tree。

4、 commit 操作具體是如何構建tree 的?

從當前 index 文件 構建tree

5、如何實現 git 與遠程分支數量對比,本地落后遠程幾次提交,本地多于遠程幾次提交?

1、找到遠程head 與本地head 共同的祖先A
2、 [A,remote-head] commit 數量為本地落后遠程分支數量
3、 [A,local-head] commit 數量為本地多于遠程分支數量
4、 git log 可以實現

6、delta storage VS snapshot storage,snapshot 有何優勢 ?

1、snapshot 實現簡單,高效(復用已有對象),保留了全部內容。可實現的功能更多
2、delta 模式,記錄復雜,實現復雜。
3、delta storage VS snapshot storage:

delta vs snapshot.png

7、javer 如何開發git 適用工具 ?

dea4git 實現:
ProcessBuilder pb = new ProcessBuilder(cmdLine)
執行git 命令
解析git 命令輸出結果

8、比較算法為何高效?

tree 比較算法介紹: http://thume.ca/2017/06/17/tree-diffing/
文件比較算法介紹: patience|minimal|histogram|myers https://blog.jcoglan.com/2017/09/19/the-patience-diff-algorithm/

9、如何更改commit 日志信息?

git rebase -i (reword):edit the commits which are rebased
git commit --amend : 修改提交commit-msg
注 amend:修改,修正,git rebase 交互模式詳情:https://git-scm.com/docs/git-rebase

10、如何讓work-tree clean ,不丟內容?

git stash,將work-dir 內容commit 。并checkout HEAD 內容到working-tree

11、如何debug git ?

1、查看.git/logs/ 目錄下面日志 ,git 命令執行日志,不是commit(git log 命令) 日志。
2、使用git core (Plumbing Commands)命令
3、使用debug 選項 git ls-files —debug

12、git gc 與jvm gc 有何異同 ?

jvm gc 基于內存,會涉及內存碎片整理,有多種垃圾處理策略(標記整理,標記復制等)
git gc基于磁盤存儲,不用整理磁盤碎片
都是基于tree 來查找垃圾對象

6、參考資料

1、Pro Git :https://git-scm.com/book/en/v2
2、 Manual Page https://git.github.io/htmldocs/
3、Pro Git 作者talk : https://www.youtube.com/watch?v=xbLVvrb2-fY
4、幫助 man git 、 git help [command]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • git 使用筆記 git原理: 文件(blob)對象,樹(tree)對象,提交(commit)對象 tree對象 ...
    神刀閱讀 3,798評論 0 10
  • 因為原文太長超出字數,Lesson 3 就放在另一篇文章里 How to Use Git and GitHub 標...
    赤樂君閱讀 5,282評論 1 5
  • 什么是Git 基于文件快照的分布式版本控制工具 Git基礎概念 三個重要的工作區: 數據倉庫:保存了所有Git提交...
    無為無味無心閱讀 572評論 0 1
  • 1.Git簡介 Git是一個開源的分布式版本控制系統,可以有效、高速的處理從很小到非常大的項目版本管理。Git 是...
    qfstudy閱讀 257評論 0 0
  • 看完了《擺渡人》這本書,內心久久不能平靜。 如果人生是一條孤獨的長河,誰會是你靈魂的擺渡人?我想在我們的一...
    MissS啦閱讀 228評論 0 0