簡體   English   中英

Github fork的解釋以及它們如何存儲文件

[英]Explanation of Github fork and how they store files

我只是想知道在github上完成fork時會發生什么。

例如,當我分叉一個項目時,它是否在github服務器上復制了所有代碼,或者只創建了一個鏈接?

所以另一個問題:在git中,因為如果你向它添加相同的文件它會散列所有文件,它不需要再次存儲文件內容,因為散列已經在系統中了,對嗎?

github是這樣的嗎? 因此,如果我碰巧上傳與另一個用戶完全相同的代碼片段,那么當github gits時,它實際上只是創建一個指向該文件的鏈接,因為它具有相同的散列,或者它是否單獨再次保存所有內容?

任何啟示都會很棒,謝謝!

github.com與git的語義完全相同,但基於Web的GUI界面也是如此。

存儲 :“Git將文件的每個版本存儲為唯一的blob對象”
因此,每個文件都是唯一存儲的,但它使用SHA-1哈希來確定文件之間的更改。

至於github,fork本質上是一個克隆。 這意味着新的fork是其服務器上的一個新存儲區域,並引用了它的ORIGIN。 它絕不會在兩者之間建立聯系,因為git本質上可以跟蹤遙控器。 每個分支都知道上游。

當你說“如果我碰巧上傳與另一個用戶完全相同的代碼”時,術語“上傳”在“git”意義上有點模糊。 如果您正在使用相同的存儲庫,並且git甚至允許您提交相同的文件,這意味着它是不同的並且它在該修訂中簽入。 但是,如果你的意思是在另一個repo的克隆/ fork上工作,那將是相同的情況,但也不會在文件系統上與其他repo建立鏈接。

我不能聲稱對內部系統內部github可能做出的優化有任何了解。 他們可能正在進行中間自定義操作以節省磁盤空間。 但是他們所做的任何事情對你來說都是透明的,並且無關緊要,因為它應該總是在預期的git語義下運行。

github的開發人員寫了一篇關於他們如何在內部執行自己的git工作流的博客文章 雖然它與您關於如何管理服務的實際工作流程的問題無關,但我認為結論的引用非常有用:

Git本身的理解起來相當復雜,使得你使用它的工作流程比必要的更復雜,只會給每個人的日子增加更多的心理開銷。 我總是提倡使用最簡單的系統,這個系統將適用於您的團隊並且這樣做,直到它不再起作用,然后僅在絕對需要時添加復雜性。

我從中得到的是,他們承認復雜的git本身是多么復雜,所以他們最有可能采取最輕微的觸摸來包裹它以提供服務,讓git做本地最好的工作。

我不知道GitHub究竟是怎么做到的,但這是一種可行的方法。 它需要一些git存儲數據的方式的知識。

簡短的回答是,repos可以共享 objects數據庫,但每個都有自己的引用。
我們甚至可以在本地模擬它以獲得概念驗證。

在一個裸倉庫的目錄中(或者如果它不是裸的則在.git/ subdir中),有三件事是repo工作的最小值:

  • objects/子目錄,存儲所有對象(提交,樹,blob ......)。 它們可以單獨存儲為名稱等於對象散列的文件,也可以存儲在.pack文件中。
  • refs/子目錄,存儲簡單文件,如refs/heads/master其內容是它引用的對象的哈希值。
  • HEAD文件,它表示當前提交的內容。 它的值是原始哈希值(對應於分離的頭部,即我們不在任何命名分支上)或者是指向可以找到實際哈希值的ref的文本鏈接(例如ref: refs/heads/master意思是我們在分支master

讓我們假設一個人創造了他原來的(不分叉)回購orig在Github上。
要模擬,我們在當地做

$ git init --bare github_orig

我們想象上面發生在Github服務器上。 現在有一個空的github存儲庫。 然后我們想象從我們自己的PC我們克隆github repo:

$ git clone github_orig local_orig

當然在現實生活中而不是github_orig我們將使用https://github... 現在我們已經在local_orig克隆了github repo。

$ cd local_orig/
$ echo zzz > file
$ git add file
$ git commit -m initial
$ git push
$ cd ..

在這個github_origobject dir將包含我們推送的提交對象之后,一個blob對象用於file和一個樹對象。 refs/heads/master文件將包含提交哈希。

現在讓我們想象當有人點擊Fork按鈕時可能發生的事情。 我們將手動創建一個git repo:

$ mkdir github_fork
$ cd github_fork/
$ cp ../github_orig/HEAD .
$ cp -r ../github_orig/refs .
$ ln -s ../github_orig/objects
$ cd ..

請注意,我們復制 HEADrefs但我們為objects創建了一個符號鏈接 我們可以看到制作一個叉子非常便宜。 即使我們有數十個分支,每個分支只是refs/heads目錄中的一個文件,它包含一個簡單的十六進制散列(40個字節)。 對於objects ,我們只能鏈接到原始對象目錄-我們不會復制任何東西!

現在我們模擬用戶創建fork,在本地克隆forked repo:

$ git clone github_fork local_fork
$ cd local_fork
$ # ls
.git/  file

我們可以看到我們已成功克隆了雖然我們克隆的repo沒有自己的objects但鏈接到原始repo的對象。
現在,分叉用戶可以創建分支,提交然后將它們推送到github_fork 對象將被推送到objects目錄中,對於github_orig來說是相同的! refsHEAD將被修改,不再與github_orig的那些匹配。

因此,底線是屬於同一分叉樹的所有repos共享一個公共對象池,而每個repo包含它自己的引用。 任何將提交推送到他自己的分叉倉庫的人都會修改自己的引用,但會將對象放在共享池中。

當然要真正可用,必須注意更多的事情 - 最重要的是,除非調用它的repo具有所有引用的知識,否則不能調用git垃圾收集器 - 而不僅僅是它自己的。 否則,它可能會丟棄共享池中無法從其引用訪問的對象,但可以從其他repos'refs中訪問。

根據https://enterprise.github.com/releases/2.2.0/notes GitHub Enterprise(我假設GitHub)以某種方式在forks之間共享對象以減少磁盤空間使用:

此版本更改了GitHub Enterprise存儲存儲庫的方式,通過在分叉之間共享Git對象來減少磁盤使用,並在讀取存儲庫數據時提高緩存性能。

還有更多詳細信息,請訪問https://githubengineering.com/counting-objects

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM