借助AI學習開源代碼git0.7之六write-tree

借助AI學習開源代碼git0.7之六write-tree

write-tree.c 的作用是根據當前的索引(cache)內容創建一個樹(tree)對象,并將其寫入Git的對象數據庫。
樹對象代表了項目在某個時間點的目錄結構。

代碼的主要邏輯:

  1. main 函數:

    • 通過 read_cache() 讀取索引(.git/index)的內容到 active_cache 中。
    • 檢查索引中是否存在未合并(unmerged)的文件。如果存在,則報錯并退出,不能無法為一個包含沖突的索引創建樹對象。
    • 調用 write_tree() 函數來遞歸地創建樹對象。
    • write_tree() 的初始調用傳入了
      active_cache(所有索引條目的數組)、條目總數、一個空字符串作為基礎路徑(base)以及0作為基礎路徑長度(baselen)。這表示從項目的根目錄開始處理。
    • 最后,將返回的頂層樹對象的SHA-1值以十六進制格式打印到標準輸出。
  2. write_tree() 函數:

    • 這是一個遞歸函數,負責將一個目錄(及其子目錄)的內容轉換成一個Git的樹對象。
    • 它遍歷 cachep 數組中的索引條目。
    • 對于每個條目,它會檢查該條目是否屬于當前正在處理的目錄(由 base 和 baselen 定義)。
    • 處理子目錄: 如果一個條目的路徑中包含 /,說明它位于一個子目錄中。這時,函數會遞歸調用 write_tree()
      來為這個子目錄創建樹對象。遞歸調用會傳入剩余的索引條目、更新后的基礎路徑和路徑長度。遞歸調用返回后,write_tree 會將子目錄作為一個特殊的條目(模式為
      S_IFDIR)寫入當前正在生成的樹對象中。
    • 處理文件: 如果條目是一個文件,它會直接將文件的模式(mode)、文件名和SHA-1值格式化后添加到一個緩沖區(buffer)中。
    • 在將任何對象(文件或子目錄)添加到樹之前,它會調用 check_valid_sha1() 來確保該對象確實存在于對象數據庫中。
    • 當一個目錄中的所有條目都處理完畢后,write_tree() 會調用 write_sha1_file()。這個函數會計算緩沖區的SHA-1值,并將緩沖區的內容(即樹對象)以 “tree”
      類型寫入對象數據庫。
    • 函數返回它處理的索引條目數量。
  3. check_valid_sha1() 函數:

    • 這是一個輔助函數,通過 sha1_file_name() 構建對象文件的路徑,然后使用 access() 系統調用檢查該文件是否存在且可讀。這是一種快速驗證對象是否有效的方法。

編碼技巧

write-tree.c 的代碼雖然不長,但包含了一些非常經典和高效的C語言編程技巧,這些技巧在早期Git的性能和簡潔性方面起到了關鍵作用。

1. 將扁平數據結構遞歸地轉換為樹狀結構

這是整個文件的核心算法,也是最巧妙的地方。

  • 輸入:一個扁平的、已按字母順序排序的文件路徑列表(active_cache)。
  • 輸出:一個代表目錄層級的樹(tree)對象的SHA-1值。
  • 技巧:代碼沒有在內存中構建一個顯式的樹形數據結構(例如,使用struct Node和子節點指針)。相反,它通過對已排序的扁平列表進行一次遍歷和遞歸來直接生成樹對象。
    • write_tree 函數通過 base 和 baselen 這兩個參數來追蹤當前正在處理的目錄“前綴”。
    • 因為它知道列表是排序的,所以一旦遇到一個文件路徑的前綴與 base 不匹配了(memcmp(base, pathname, baselen)),就意味著當前目錄的所有條目都已處理完畢。
    • 當遇到一個包含子目錄的路徑時(例如,在處理 base=“src/” 時遇到了 src/a/main.c),它會識別出 a 是一個子目錄,然后遞歸調用 write_tree,并將新的 base 設置為
      “src/a/”。這種遞歸調用處理了子目錄,然后將子目錄的樹對象SHA-1返回,父目錄再將這個子目錄作為一個條目記錄下來。

這個方法極大地節省了內存,并且因為只遍歷一次數據,所以非常高效。

2. 高效的指針和字符串操作

代碼中大量使用了指針運算來處理字符串(文件路徑),避免了不必要的內存分配和字符串拷貝,這是C語言性能優化的關鍵。

  • 計算子路徑:filename = pathname + baselen; 這一行不是創建一個新的子字符串,而是簡單地將指針向前移動 baselen 個字節,直接指向了相對于當前目錄的文件名部分。
  • 計算路徑長度:dirname - pathname 直接通過兩個指針的地址差來計算子目錄的長度,非常快。
  • 查找字符:使用 strchr(filename, ‘/’) 來快速定位下一個子目錄分隔符。

3. 動態內存管理(“猜測并增長”策略)

在構建樹對象的內容時,最終的大小是未知的。代碼采用了一種常見的策略:

  1. 初始猜測:size = 8192; buffer = xmalloc(size); 先分配一個比較合理的初始大小(8KB)。
  2. 檢查并擴展:在每次向 buffer 添加新內容之前,都會檢查剩余空間是否足夠 (if (offset + entrylen + 100 > size))。
  3. 按需重新分配:如果空間不足,就使用 xrealloc 來擴展緩沖區。alloc_nr是個宏或函數,用于計算一個更合適的、更大的新尺寸,以避免頻繁地進行 realloc。

這種模式在處理未知大小的輸出時非常高效和靈活。

4. “數組切片”式的遞歸

在遞歸調用 write_tree 時,注意這一行:
write_tree(cachep + nr, maxentries - nr, …)

這里沒有為遞歸調用創建一個新的數組副本。cachep + nr 只是將指向 cachep 數組第 nr
個元素的指針傳遞給下一層函數。
這相當于在說:“請處理從這個點開始的剩余部分”。
這是一種零開銷的“數組切片”方法,是C語言中處理數組子集的標準高效技巧。

5. 混合數據格式的直接構建

Git的樹對象是一種混合了文本和二進制的格式:"<%mode> <%filename>\0<%20_byte_sha1>".

代碼非常直接地構建了這個格式:

  1. sprintf(buffer + offset, “%o %.*s”, mode, entrylen, filename); 用 sprintf 來格式化文本部分(模式和文件名)。
  2. buffer[offset++] = 0; 手動添加空字符(\0)分隔符。
  3. memcpy(buffer + offset, sha1, 20); 用 memcpy 直接拷貝20字節的二進制SHA-1值。

這種方法避免了任何中間轉換或復雜的格式化庫,直接在內存中按字節構建出最終需要的數據,速度極快。

6. 編碼技巧總結

write-tree.c 的代碼是底層系統編程的一個絕佳范例。它展示了如何:

  • 用巧妙的算法設計(遞歸處理排序列表)來避免復雜的數據結構和內存開銷。
  • 通過精細的指針操作來最大化字符串處理效率。
  • 在C語言中有效地管理動態增長的內存緩沖區。

這些技巧共同造就了一個非常快速和資源節約的程序,這對于像Git這樣的性能敏感的工具來說至關重要。

總結

write-tree 的核心思想是:

  • 從一個扁平的、按字母順序排序的索引條目列表開始。
  • 通過遞歸地處理路徑,將這個扁平的列表轉換成一個分層的樹結構。
  • 每個子目錄都變成一個新的樹對象,而文件則作為blob對象被引用。
  • 最終,整個項目的文件結構被表示為一個頂層的樹對象,其SHA-1值就是這次操作的結果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92363.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92363.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92363.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

開源 python 應用 開發(八)圖片比對

最近有個項目需要做視覺自動化處理的工具&#xff0c;最后選用的軟件為python&#xff0c;剛好這個機會進行系統學習。短時間學習&#xff0c;需要快速開發&#xff0c;所以記錄要點步驟&#xff0c;防止忘記。 鏈接&#xff1a; 開源 python 應用 開發&#xff08;一&#xf…

SeaTunnel 云倉連接器使用指南 | AI 助手解讀系列

最近體驗了一下 Deepwiki 的 AI 文檔生成功能&#xff0c;本文展示其自動生成的《SeaTunnel 云端數據倉庫連接器》文檔內容&#xff0c;歡迎大家一起“挑刺捉蟲”&#xff0c;看看 AI 寫技術文檔到底靠不靠譜&#xff1f; 本文檔介紹了 Apache SeaTunnel 的云數據倉庫連接器&a…

每日算法刷題Day51:7.21:leetcode 棧6道題,用時1h40min

二.進階 1.套路 2.題目描述 1.給你一個字符串 s 。它可能包含任意數量的 * 字符。你的任務是刪除所有的 * 字符。 當字符串還存在至少一個 * 字符時&#xff0c;你可以執行以下操作&#xff1a; 刪除最左邊的 * 字符&#xff0c;同時刪除該星號字符左邊一個字典序 最小的字…

網絡基礎DAY16-MSTP-VRRP

STP/RSTP的局限性1.所有VLAN共享一棵生成樹 2.無法實現不同VLAN在多條Trunk鏈路上的負載分擔 3.次優化二層路徑。MSTP的基本概念及優勢MSTP的定義MST域擁有相同MST配置標識的網橋構成的集合。 具體如何分辨是否是同一個域&#xff0c;就看域名&#xff0c;配置修訂號&#xff0…

freertos關鍵函數理解 uxListRemove

//刪除pxItemToRemove節點 UBaseType_t uxListRemove(ListItem_t *pxItemToRemove) { //The list item knows which list it is in. Obtain the list from the list item.//找到節點所在的鏈表//my_printf( "uxListRemove pxItemToRemove %#p\n", pxI…

C語言---番外篇(柔性數組)

前言&#xff1a; 由于這塊內容所謂綜合性比較高&#xff0c;有數組的知識&#xff0c;有結構體的知識&#xff0c;還有動態內存管理的知識&#xff0c;所以我就單獨寫一篇博客&#xff0c;此謂番外篇。 柔性數組的概念 定義在結構體的最后一個元素的位置且大小未知的數組就叫…

單片機的幾種GPIO輸入輸出模型詳解

模式選擇匯總參考表&#xff1a;模式輸出驅動輸入阻抗默認狀態典型應用場景推挽輸出強驅動禁用可配置LED, SPI, 高速信號開漏輸出弱驅動禁用低/懸空IC, 電平轉換, 線與浮空輸入禁用極高不確定外部強驅動信號上拉輸入禁用中高高電平按鍵(接地型), 數字輸入下拉輸入禁用中高低電平…

深度解析ECharts.js:構建現代化數據可視化的利器

引言&#xff1a;數據可視化的新時代挑戰 在數字化轉型浪潮中&#xff0c;數據可視化已成為企業決策和用戶體驗的關鍵環節。面對海量數據的呈現需求&#xff0c;傳統表格已無法滿足用戶對直觀洞察的渴求。作為百度開源的JavaScript可視化庫&#xff0c;ECharts.js憑借其強大的功…

從零構建實時通信引擎:Freeswitch源碼編譯與深度優化指南

一、構建工具&#xff1a;編譯FreeSWITCH及其依賴庫的基礎 1. CMake2. Autoconf 二、匯編器&#xff1a;提升音視頻處理性能 3. YASM / NASM 三、音視頻編解碼器&#xff1a;支撐實時媒體傳輸 4. Opus5. x264 (可選)6. libvpx / libvpx2 (可選) 四、多媒體框架與工具庫&#xf…

網絡原理 HTTP 和 HTTPS

目錄 一 . HTTP 協議 二 . 抓包 三 . HTTP 請求 / 響應的基本格式 &#xff08;1&#xff09;HTTP請求的基本格式 &#xff08;2&#xff09;HTTP響應的基本格式 四 . HTTP 方法 GET 和 POST 的區別&#xff1a; 五 . 請求報頭和響應報頭 &#xff08;1&#…

基于單片機的自動條幅懸掛機

摘 要 隨著日新月異科技發展&#xff0c;在心率體溫測量方面&#xff0c;我們取得了迅速的發展&#xff0c;就近日而言&#xff0c;脈搏測量儀已經在多個領域大展身手&#xff0c;除了在醫學領域有所建樹&#xff0c;在人們的日常生活方面的應用也不斷拓展&#xff0c;如檢疫…

《C++》面向對象編程--類(中)

文章目錄一、構造函數1.1定義1.2語法1.3特性二、析構函數2.1定義2.2語法2.3特性三、拷貝構造函數3.1定義3.2語法3.3特性3.4淺拷貝3.4.1定義3.4.2淺拷貝的風險3.5深拷貝一、構造函數 1.1定義 在C中&#xff0c;構造函數&#xff08;Constructor&#xff09; 是一種特殊的成員函…

機器學習初學者理論初解

大家好! 為什么手機相冊能自動識別人臉&#xff1f;為什么購物網站總能推薦你喜歡的商品&#xff1f;這些“智能”背后&#xff0c;都藏著一位隱形高手——機器學習&#xff08;Machine Learning&#xff09;。一、什么是機器學習&#xff1f;簡單說&#xff0c;機器學習是教計…

原碼反碼補碼

在Java中&#xff0c;無論是小數還是整數&#xff0c;他們都要帶有符號&#xff08;和C語言不同&#xff0c;C語言有無符號數&#xff09;。首位就作為符號位。原碼反碼&#xff1a;正數的反碼是其原碼本身負數的反碼是在其原碼的基礎上, 符號位不變&#xff0c;其余各個位取反…

使用ubuntu:20.04和ubuntu:jammy構建secretflow環境

一、使用ubuntu:20.04構建隱語編譯環境FROM ubuntu:20.04LABEL maintainer"build SecureProtocolLib on ubuntu:20.04"ARG TARGETPLATFORM# change dash to bash as default shell RUN ln -sf /bin/bash /bin/shRUN apt update \&& apt upgrade -y \&&am…

Hinge Loss(鉸鏈損失函數)詳解:SVM 中的關鍵損失函數

&#x1f4cc; 一、什么是 Hinge Loss&#xff1f;Hinge Loss&#xff08;鉸鏈損失&#xff09;&#xff0c;是 支持向量機&#xff08;SVM, Support Vector Machine&#xff09; 中常用的一種損失函數&#xff0c;用于最大間隔分類。其核心思想是&#xff1a;當預測結果已經正…

days32 :零基礎學嵌入式之網絡2.0

一、wireshark &#xff1a;網絡抓包工具1.功能&#xff1a;抓取通過電腦網卡的網絡數據2.作用&#xff1a;排查故障、抓取數據做數據分析、3.用法&#xff1a;&#xff08;1&#xff09;sudo wireshark&#xff08;2&#xff09;選擇需要抓取的網卡》any&#xff08;3&#xf…

數字護網:一次深刻的企業安全體系靈魂演練

&#x1f9e9; 引言&#xff1a;什么是“護網”&#xff1f;—— 不止是攻防&#xff0c;更是企業安全能力的年度大考 每年&#xff0c;由國家相關部門牽頭的“護網行動”都如期而至&#xff0c;各大企事業單位的安全團隊也隨之進入高度戒備狀態。然而&#xff0c;“護網”遠非…

基于 NumPy 的高效數值計算技術解析與實踐指引

在數據處理與科學計算領域&#xff0c;高效是核心訴求。NumPy 作為 Python 生態高效數值計算的基石&#xff0c;以高性能多維數組對象及配套函數&#xff0c;成為數據從業者的必備工具。其數組支持算術、比較、邏輯等豐富運算&#xff0c;通過向量化操作直接處理每個元素&#…

Kafka MQ 控制器 broker

Kafka MQ 控制器 broker 1 控制器broker的選舉 在 Kafka 集群中會有一個或多個 broker,其中有一個 broker 會被選舉為控制器(Kafka Controller)?,它負責管理整個集群中所有分區和副本的狀態。當某個分區的leader副本出現故障時,由控制器負責為該分區選舉新的leader副本…