久久亚洲人成国产精品_国产免费一级精品视频_视频一区在线观看_www.久久精品

當前位置:首頁 > 造價工程師 > 正文

造價工程師初始注冊有效期,造價工程師初始注冊

  作者 | Ben Hoyt

  翻譯 | 雁驚寒

  “pygit是一個大約500行Python代碼工具,實現了一些git功能,包括創建庫、將文件添加到索引、提交、將自身推送到GitHub上去。 本文給出了一些代碼編寫過程,并詳細介紹了相關代碼。”

  Git因其具有非常簡單的對象模型而著稱。在學習git時,我發現本地對象數據庫只是.git目錄中的一堆普通文件。除了索引(.git/index)和打包文件(可有可無)外,這些文件的存放規則和格式相當的簡單。

  受Mary Rose Cook的程序啟發,我也想看看是否能夠編寫出創建倉庫,執行提交,并推送到服務器(比如GitHub)的git客戶端。

  Mary的gitlet程序有著很多可供學習的地方,而我的程序需要把自身推送到GitHub上去,所以具有更多的創新功能。在某些方面,她實現了更多的Git功能(包括基本的合并),但在其他方面實現的功能就比較的少。例如,她使用了一個簡單的基于文本的索引格式,而不是用git使用的二進制格式。此外,雖然她的gitlet支持推送,但它只會推送到本地已經存在的倉庫中,而不是到遠程服務器上。

  對于本文涉及的這個練習,我打算編寫一個可以執行所有步驟的版本,包括推送到一個真正的Git服務器上去。我也會使用與git相同的二進制索引格式,這樣,我就可以在每一步驟上都使用git命令來檢查程序的功能。

  我的程序叫pygit,用Python(3.5+)編寫,并且只使用了標準庫模塊。它只有500行代碼,包括空白行和注釋。我至少需要實現init、add、commit和push命令,但pygit還實現了status,diff,cat-file,ls-files和hash-object等命令。后面的命令,本身也非常有用,并且在調試pygit的時候,也起到了幫助作用。

  下面,讓我們來看看代碼吧!您可以在GitHub上查看pygit.py的所有代碼,或者在下文中跟著我一起瀏覽各段代碼。

  初始化倉庫

  初始化本地Git倉庫只需要創建.git目錄以及目錄下的幾個文件和子目錄即可。在定義了read_file和write_file這兩個幫助函數之后,我們就可以編寫init()了:

  

  你可能注意到這段代碼里沒有進行優雅的錯誤處理。畢竟這整個代碼只有500行啊。如果倉庫目錄已經存在,程序會終止,并拋出traceback。

  取對象的散列值

  hash_object函數用來獲取單個文件對象的散列值,并寫入.git/objects目錄下的“數據庫”中。在Git模型中,包含三種對象,分別是:普通文件(blob),提交(commit)和樹(tree,也就是目錄結構)。

  每個對象都有一個文件頭,包括文件類型和文件大小,大概幾個字節的長度。之后是NUL字符,然后是文件的數據內容。所有這些都使用zlib壓縮并寫入到文件.git/objects/ab/cd…中,其中ab是40個字符長的SHA-1散列的前兩個字符,而cd…則是剩余的部分。

  請注意,這里使用了Python標準庫(os和hashlib)。

  

  還有個find_object()函數,它通過散列(或散列前綴)找到某個文件對象,然后用read_object()函數讀取這個對象及其類型。這實際上是hash_object()的反向操作。最后,cat_file是一個與git cat-file具有相同功能的pygit函數:它將對象的內容(或者大小和類型)進行格式化并打印到標準輸出。

  git索引

  接下來我們要做的事情就是要將文件添加到索引或暫存區中。索引就是文件列表,按路徑名排序,每個路徑都包含路徑名,修改時間,SHA-1散列等等。需要注意的是,索引列出了當前樹中的所有文件,而不僅僅是在暫存區中等待提交的文件。

  索引以自定義的二進制格式存儲在.git/index文件中。這個文件雖然并不是很復雜,但它還是涉及到了結構體的用法,通過一定規則的字節偏移,可以在長度可變的路徑名稱字段之后獲得下一個索引條目。

  文件的前12個字節是文件頭,最后20個字節是索引的SHA-1散列,在這中間的字節是索引條目,每個索引條目為62個字節加上路徑的長度再加上填充的長度。下面是namedtuple類型的IndexEntry和read_index函數:

  

  這個函數后面是ls_files,status和diff函數,這些是打印索引狀態的幾個不同的方法:

ls_files函數只是打印索引中的所有文件(如果指定了-s,則連同一起打印它們的模式和散列)

status函數使用get_status()來比較索引中的文件和當前目錄樹中的文件是否一致,打印有哪些文件被修改,新增或刪除

diff函數打印每個修改過的文件中變動的地方,顯示索引中的內容與當前工作副本中的內容的不同點(使用Python的difflib模塊來完成這個功能)

  git對索引的操作和這些命令的執行在效率上比我這個程序要高很多。我使用os.walk()函數來列出目錄中的所有文件的完整路徑,做一些設置操作,然后比較他們散列值。例如,這個是我用來獲取有過修改的路徑列表的代碼:

  最后還有一個write_index函數用于回寫索引。它調用了add()函數將一個或多個路徑添加到索引中。add()函數首先讀取整個索引,將路徑添加進去,然后重新排序并回寫索引。

  此時,我們已經將文件添加到索引中了,下面,我們可以開始實現commit操作了。

  提交

  執行提交操作需要編寫兩個對象:

  首先是樹對象,它是提交時當前目錄(或者是索引)的一個快照。這棵樹遞歸列出了目錄中的文件和子目錄的散列。

  所以每個提交都是整個目錄樹的快照。 這種使用散列值來存儲東西的好處是,如果樹中的任意一個文件發生改變,則整個樹的散列也會跟著發生改變。相反,如果一個文件或子目錄沒有改變,則散列也不會改變。所以你可以高效地存儲目錄樹中的變更。

  這是一個用cat-file pretty 2226命令打印出來的樹對象的示例(每一行打印的內容為:文件模式、對象類型、散列和文件名):

  

  函數write_tree用于寫樹對象。Git文件格式的奇怪之處在于它混合了二進制和文本,例如,樹對象中的每一“行”首先是文本:“模式、空格、路徑”,然后是NUL字節,然后是二進制SHA-1散列。 這是我們的write_tree()函數:

  

  其次是提交對象。 它記錄了樹的散列值、父提交、作者、時間戳,以及提交信息。合并功能是Git的優點之一,但是pygit只支持單一的線性分支,所以只有一個父提交(如果是第一次提交,則沒有父提交)。

  這是一個提交對象的例子,再次使用cat-file pretty aa8d命令打印出來:

  

  這個是我們的提交函數,再次感謝Git的對象模型,相當的簡單:

  

  與服務器交互

  接下來是稍微有點困難的部分了,因為我們要讓pygit與一個真正的Git服務器進行通信(我將把pygit自身推送到GitHub,但它也適用于Bitbucket和其他服務器)。

  其基本思想是首先查詢服務器上即將要提交的主分支,然后確定等待提交的本地對象集,最后,更新遠程的提交散列值,并發送包含所有缺少的對象的“打包文件”。

  這被稱為“智能協議”。直到2011年,GitHub才停止了對“愚蠢”傳輸協議的支持,該協議是將.git目錄中的文件直接傳輸過去,所以實現起來更加容易。這里,我們必須得使用“智能協議”將對象打包到一個文件中。

  在最后的工作階段,我使用了Python的http.server模塊實現了一個小型的HTTP服務器,這樣,我就可以運行其他的git客戶端與這個服務器進行交互,以此來查看真正的請求與相應數據。

  pkt-line格式

  傳輸協議的關鍵部分之一是“pkt-line”格式,它是用于發送元數據(如提交散列)的數據報文格式。報文的開頭是長度值。每“行”開頭是4個十六進制字符表示的長度值(所表示的長度要包含這個長度值字段),所以,包的長度必須小于這4個字符表示的數值。 每行的最后都有一個LF字符。數據結尾的0000是段結束標記。

  例如,這個是GitHub對git-receive-pack GET請求的響應報文。請注意,額外的換行符和縮進并不是報文的一部分。

  

  很明顯,我們需要兩個轉換函數:一個將pkt-line數據轉換為一行一行的數據,另一個則是反過來,將一行一行的數據轉換為pkt-line格式:

  

  實現HTTPS請求

  由于我只想使用標準庫, 所以接下來的代碼就是在不使用requests庫的情況下實現身份驗證HTTPS請求:

  

  以上這段代碼說明了requests庫的存在是非常有意義的。你可以使用標準庫的urllib.request模塊來實現這些操作,但有時候會很痛苦。大多數Python標準庫是很好用的,有一些則不是,雖然數量并不多。如果使用request的話,甚至都不需要幫助函數:

  

  我們可以使用上面的函數來向服務器詢問它的主分支到哪個版本了,代碼如下(這個功能還比較脆弱,但是可以很容易地修改的更為通用一點):

造價工程師初始注冊有效期,造價工程師初始注冊  第1張

  

  確定丟失的對象

  接下來,我們需要確定:服務器需要,但是在服務器上又不存在的對象。 pygit假定所有東西都在本地(它不支持“pulling”),所以,我寫了read_tree函數(與write_tree相反),然后,用以下這兩個函數在指定的樹和指定的提交中遞歸尋找對象散列集合:

  

  然后,我們需要做的就是獲取本地提交引用的對象集合,用這個集合減去遠程提交中引用的對象集。這兩者的差異是遠端丟失的對象。雖然肯定還有更加有效率的方式來生成這個對象集合,但這個邏輯對于pygit來說已經足夠了:

  

  推送自身

  在推送之前,我們需要發送一條pkt-line請求來說明“將主分支更新為此提交散列”,然后發送包含上述所有缺失對象的打包文件。

  打包文件有一個12個字節長的頭(從PACK開始),接著是各個對象,每個對象包括長度以及用zlib算法壓縮的對象數據,最后是整個打包文件的散列值,長度是20個字節。雖然,基于對象差異的算法可以讓數據報文來得更小,但對我們而言就是過度設計了:

  

  然后,最后一步,push()自身,為了簡潔起見,我刪除了一點代碼:

  

  命令行解析

  pygit,包括子命令(pygit init,pygit commit等),是一個使用標準庫argparse模塊的例子。我沒有把代碼復制到這里,你可以查看源代碼中argparse的相關部分。

  pygit用法

  在大多數地方,我盡量讓pygit命令行語法與git語法相同或接近相同。以下是將pygit提交到GitHub的命令:

  

  結束語

  這些就是所有的代碼邏輯了!如果你從頭閱讀到這里,那你僅僅只是瀏覽了500行Python代碼,并沒有任何價值。哦,等等,除了受到教育和工匠精神的價值。希望你學到了有關Git內部邏輯方面的知識。

發表評論

久久亚洲人成国产精品_国产免费一级精品视频_视频一区在线观看_www.久久精品
国产亚洲欧美aaaa| 国模精品娜娜一二三区| 欧美午夜电影在线观看| 国产在线欧美日韩| 亚洲欧美在线免费| 蘑菇福利视频一区播放| 国产精品免费在线| 亚洲一区999| 欧美 日韩 国产精品免费观看| 国产精品久久激情| 亚洲一本大道在线| 欧美成人官网二区| 国产一区二区三区久久久| 亚洲综合色激情五月| 欧美jizz19性欧美| 国产一区视频在线观看免费| 久久国产免费看| 国产精品爱久久久久久久| 亚洲视频电影图片偷拍一区| 女生裸体视频一区二区三区| 国产一区二区高清视频| 久久青青草原一区二区| 国产精品色婷婷久久58| 性欧美暴力猛交另类hd| 欧美午夜无遮挡| 亚洲综合国产激情另类一区| 欧美久久电影| 在线一区亚洲| 欧美激情一区二区三区蜜桃视频| 国内精品久久久久影院 日本资源| 久久精品国产亚洲5555| 国产精品男女猛烈高潮激情| 欧美一区亚洲| 国产精品日韩欧美一区二区| 欧美一区二区三区在线播放| 国产精品福利影院| 欧美在线免费观看视频| 国产精品欧美久久久久无广告| 欧美一区二区日韩一区二区| 国产精品丝袜久久久久久app| 欧美在线一区二区| 国产伦精品一区二区三区四区免费 | 欧美精品情趣视频| 亚洲视频免费观看| 欧美视频中文在线看 | 欧美电影免费观看网站 | 欧美成人四级电影| 亚洲天堂偷拍| 欧美午夜免费电影| 久久激情婷婷| 黑人极品videos精品欧美裸| 欧美大色视频| 亚洲欧美中日韩| 国产老女人精品毛片久久| 另类国产ts人妖高潮视频| 激情成人在线视频| 欧美日韩国语| 久久国产日韩| 黄色成人免费观看| 欧美三级日本三级少妇99| 欧美在线一二三区| 国产专区综合网| 欧美国产日韩免费| 欧美亚洲三区| 国外精品视频| 欧美色图五月天| 久久女同互慰一区二区三区| 国产精品99久久久久久久女警 | 国产精品jizz在线观看美国 | 国产午夜精品久久久| 欧美二区视频| 欧美一级一区| 一区二区三区在线观看视频| 欧美三区美女| 老**午夜毛片一区二区三区| 亚洲一区二区三区中文字幕在线| 国产免费成人| 欧美日韩精品二区| 久久天堂av综合合色| 亚洲影视综合| 国产一区日韩欧美| 欧美性视频网站| 欧美韩日高清| 久久久精品午夜少妇| 宅男噜噜噜66国产日韩在线观看| 国产精品欧美日韩一区二区| 欧美激情在线有限公司| 久久精品视频亚洲| 亚洲自拍偷拍麻豆| 尤物视频一区二区| 国产日韩av一区二区| 欧美色视频日本高清在线观看| 老司机一区二区三区| 欧美专区在线观看一区| 亚洲影院色无极综合| 国内外成人免费激情在线视频网站| 欧美日韩在线视频观看| 欧美不卡福利| 久久久蜜桃精品| 午夜精品在线| 亚洲一区二区视频在线| 精品成人在线观看| 国产午夜精品久久| 国产精品视频内| 欧美天天综合网| 欧美精品在线网站| 欧美承认网站| 牛夜精品久久久久久久99黑人| 久久久久久9| 久久久.com| 久久激情婷婷| 久久疯狂做爰流白浆xx| 午夜在线观看免费一区| 亚洲特级片在线| 韩国欧美国产1区| 国产性做久久久久久| 国产精品视频男人的天堂| 国产精品国产福利国产秒拍| 欧美日韩麻豆| 欧美日韩精品一区二区| 欧美激情一区| 欧美精品aa| 欧美激情视频在线播放| 欧美成人综合一区| 欧美aⅴ一区二区三区视频| 老司机久久99久久精品播放免费| 久久免费精品日本久久中文字幕| 久久久91精品| 久久久久久综合| 久久久精品日韩欧美| 久久久久久亚洲综合影院红桃 | 一区二区三区在线免费视频| 国内成+人亚洲| 韩国福利一区| 国产综合久久久久久鬼色| 国产一区二区精品丝袜| 国产亚洲欧美中文| 国产一区二区久久精品| 黄色小说综合网站| 亚洲图片欧美日产| 亚洲欧美综合另类中字| 性伦欧美刺激片在线观看| 欧美一区二区私人影院日本| 久久国产精品亚洲va麻豆| 久久麻豆一区二区| 欧美成年人网| 欧美片在线观看| 欧美午夜精品理论片a级大开眼界 欧美午夜精品理论片a级按摩 | 久久精品国产综合精品| 久久久精品tv| 欧美成人小视频| 欧美日本亚洲韩国国产| 欧美视频一区二区| 国产精品在线看| 国产在线视频欧美| 中文精品99久久国产香蕉| 亚洲欧美激情精品一区二区| 欧美主播一区二区三区美女 久久精品人| 久久精品日韩一区二区三区| 美女精品网站| 欧美日韩成人综合在线一区二区| 欧美色另类天堂2015| 国产精品尤物福利片在线观看| 激情成人亚洲| 小处雏高清一区二区三区| 久久综合久久久久88| 欧美精品一区视频| 国产精品视频一二| 一区二区在线不卡| 午夜亚洲一区| 欧美成人一区二区在线| 国产精品久久久久久亚洲毛片 | 老司机精品福利视频| 欧美日韩色一区| 久久精品99国产精品| 欧美成人精品福利| 欧美午夜一区| 又紧又大又爽精品一区二区| 欧美在线观看一区二区三区| 欧美黄色影院| 国产九九精品视频| 亚洲免费影视| 免费成人网www| 国产精品欧美一区喷水| 精品va天堂亚洲国产| 久久精品观看| 欧美日韩精品一区二区在线播放 | 亚洲午夜精品久久| 久久久亚洲欧洲日产国码αv| 欧美喷水视频| 国内揄拍国内精品久久| 久久国产日韩欧美| 欧美日韩中文字幕日韩欧美| 狠狠色综合色区| 久久精品视频网| 国产精品成人播放| 亚洲特色特黄| 欧美电影电视剧在线观看| 国产免费亚洲高清| 欧美在线亚洲综合一区|