設定和配置
獲取和建立專案
基本快照
分支與合併
共享和更新專案
檢查和比較
打補丁
除錯
電子郵件
外部系統
伺服器管理
指南
管理
底層命令
- 2.43.1 → 2.52.0 無更改
-
2.43.0
2023-11-20
- 2.38.1 → 2.42.4 無更改
-
2.38.0
2022-10-02
描述
Git 支援透過 ssh://, git://, http:// 和 file:// 傳輸協議傳輸 packfile 中的資料。存在兩套協議,一套用於將資料從客戶端推送到伺服器,另一套用於從伺服器獲取資料到客戶端。這三種傳輸協議(ssh、git、file)使用相同的協議傳輸資料。http 在 gitprotocol-http[5] 中進行了文件說明。
在標準的 Git 實現中,用於獲取資料的伺服器端程序是 upload-pack,客戶端程序是 fetch-pack;用於推送資料的伺服器端程序是 receive-pack,客戶端程序是 send-pack。該協議的功能是讓伺服器告知客戶端當前伺服器上有什麼,然後雙方協商傳送最少的資料量以完全更新其中一方。
pkt-line 格式
以下描述基於 gitprotocol-common[5] 中描述的 pkt-line 格式。當語法指示 PKT-LINE(...) 時,除非另有說明,通常的 pkt-line LF 規則適用:傳送方 SHOULD 包含 LF,但接收方 MUST NOT 在其不存在時抱怨。
錯誤包是一個特殊的 pkt-line,包含一個錯誤字串。
error-line = PKT-LINE("ERR" SP explanation-text)
在整個協議中,在預期 PKT-LINE(...) 的地方,MAY 傳送錯誤包。一旦客戶端或伺服器傳送了此包,本協議定義的資料傳輸過程將終止。
傳輸協議
packfile 協議透過三種傳輸協議啟動。Git 傳輸協議是一個簡單的、未認證的伺服器,它接收客戶端希望通訊的命令(幾乎總是 upload-pack,儘管 Git 伺服器可以配置為全域性可寫,此時也允許 receive-pack 的啟動)並執行它,然後將其連線到請求程序。
在 SSH 傳輸協議中,客戶端只是透過 SSH 協議在伺服器上執行 upload-pack 或 receive-pack 程序,然後透過 SSH 連線與該呼叫程序通訊。
file:// 傳輸協議在本地執行 upload-pack 或 receive-pack 程序,並透過管道與其通訊。
附加引數
該協議提供了一種機制,允許客戶端在其傳送給伺服器的第一個訊息中傳送額外資訊。這些被稱為“附加引數”,並得到 Git、SSH 和 HTTP 協議的支援。
每個附加引數的形式為 <key>=<value> 或 <key>。
接收到任何此類附加引數的伺服器 MUST 忽略所有未識別的鍵。當前,唯一識別的附加引數是“version”,其值為 1 或 2。有關協議版本 2 的更多資訊,請參閱 gitprotocol-v2[5]。
Git 傳輸協議
Git 傳輸協議首先使用 pkt-line 格式在網路上傳送命令和倉庫,然後是一個 NUL 位元組和一個主機名引數,最後以 NUL 位元組終止。
0033git-upload-pack /project.git\0host=myserver.com\0
該傳輸協議可以透過新增額外的 NUL 位元組,然後新增一個或多個以 NUL 終止的字串來發送附加引數。
003egit-upload-pack /project.git\0host=myserver.com\0\0version=1\0
git-proto-request = request-command SP pathname NUL
[ host-parameter NUL ] [ NUL extra-parameters ]
request-command = "git-upload-pack" / "git-receive-pack" /
"git-upload-archive" ; case sensitive
pathname = *( %x01-ff ) ; exclude NUL
host-parameter = "host=" hostname [ ":" port ]
extra-parameters = 1*extra-parameter
extra-parameter = 1*( %x01-ff ) NUL
host-parameter 用於 git-daemon 基於名稱的虛擬託管。請參閱 git daemon 的 --interpolated-path 選項,以及 %H/%CH 格式字元。
基本上,Git 客戶端透過 Git 協議連線到伺服器端的 upload-pack 程序所做的事情如下:
$ echo -e -n \ "003agit-upload-pack /schacon/gitbook.git\0host=example.com\0" | nc -v example.com 9418
SSH 傳輸協議
透過 SSH 啟動 upload-pack 或 receive-pack 程序是透過 SSH 遠端執行在伺服器上執行二進位制檔案。它基本上等同於執行以下命令:
$ ssh git.example.com "git-upload-pack '/project.git'"
為了讓伺服器支援給定使用者的 Git 推送和拉取,該使用者需要能夠透過其登入時提供的 SSH shell 執行一個或兩個命令。在某些系統上,該 shell 訪問被限制為只能執行這兩個命令,甚至只能執行其中一個。
在 ssh:// 格式的 URI 中,它在 URI 中是絕對的,因此主機名(或埠號)之後的 / 作為引數傳送,然後由遠端 git-upload-pack 正確讀取,因此它實際上是遠端檔案系統中的絕對路徑。
git clone ssh://user@example.com/project.git | v ssh user@example.com "git-upload-pack '/project.git'"
在“user@host:path”格式的 URI 中,它相對於使用者的主目錄,因為 Git 客戶端將執行:
git clone user@example.com:project.git
|
v
ssh user@example.com "git-upload-pack 'project.git'"
唯一的例外是當使用 ~ 時,在這種情況下,我們將不帶前導 / 來執行它。
ssh://user@example.com/~alice/project.git,
|
v
ssh user@example.com "git-upload-pack '~alice/project.git'"
根據 protocol.version 配置變數的值,Git 可能會嘗試在 GIT_PROTOCOL 環境變數中將附加引數作為冒號分隔的字串傳送。只有當 ssh.variant 配置變數指示 ssh 命令支援將環境變數作為引數傳遞時,才會執行此操作。
這裡有幾點需要記住:
-
“命令名稱”用連字元拼寫(例如 git-upload-pack),但這可以由客戶端覆蓋;
-
倉庫路徑始終用單引號括起來。
從伺服器獲取資料
當一個 Git 倉庫想要獲取另一個倉庫擁有的資料時,第一個倉庫可以從第二個倉庫 fetch。此操作確定伺服器擁有而客戶端沒有的資料,然後以 packfile 格式將該資料流式傳輸到客戶端。
引用發現
當客戶端首次連線時,伺服器將立即響應一個版本號(如果“version=1”作為附加引數傳送),以及它擁有的每個引用的列表(所有分支和標籤)以及每個引用當前指向的物件名稱。
$ echo -e -n "0045git-upload-pack /schacon/gitbook.git\0host=example.com\0\0version=1\0" |
nc -v example.com 9418
000eversion 1
00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack
side-band side-band-64k ofs-delta shallow no-progress include-tag
00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
0000
返回的響應是描述每個 ref 及其當前值的 pkt-line 流。該流 MUST 按照 C 語言 locale 的排序順序進行排序。
如果 HEAD 是一個有效的引用,HEAD MUST 出現在廣告列表的第一個引用中。如果 HEAD 不是一個有效的引用,HEAD MUST 完全不出現在廣告列表中,但其他引用仍然可能出現。
該流 MUST 在第一個引用後的 NUL 處包含能力宣告。如果引用是一個註解標籤,則該引用的剝離值(即“ref^{}”)MUST 出現在引用本身之後。符合規範的伺服器 MUST 在引用是註解標籤時對其進行剝離。
advertised-refs = *1("version 1")
(no-refs / list-of-refs)
*shallow
flush-pkt
no-refs = PKT-LINE(zero-id SP "capabilities^{}"
NUL capability-list)
list-of-refs = first-ref *other-ref
first-ref = PKT-LINE(obj-id SP refname
NUL capability-list)
other-ref = PKT-LINE(other-tip / other-peeled)
other-tip = obj-id SP refname
other-peeled = obj-id SP refname "^{}"
shallow = PKT-LINE("shallow" SP obj-id)
capability-list = capability *(SP capability)
capability = 1*(LC_ALPHA / DIGIT / "-" / "_")
LC_ALPHA = %x61-7A
伺服器和客戶端 MUST 對 obj-id 使用小寫,兩者都 MUST 將 obj-id 視為不區分大小寫。
有關允許的伺服器能力及其描述列表,請參閱 protocol-capabilities.txt。
Packfile 協商
在引用和能力發現之後,客戶端可以透過傳送 flush-pkt 來決定終止連線,告知伺服器現在可以優雅地終止並斷開連線,當它不需要任何 pack 資料時。這可以與 ls-remote 命令一起發生,也可以在客戶端已更新時發生。
否則,它將進入協商階段,客戶端和伺服器確定傳輸所需的最小 packfile,透過告知伺服器它想要的物件、其淺層物件(如果有)以及它想要的提交最大深度(如果有)。客戶端還將傳送一個它想要生效的能力列表,從伺服器在第一個 want 行中說它可以做什麼中選擇。
upload-request = want-list
*shallow-line
*1depth-request
[filter-request]
flush-pkt
want-list = first-want
*additional-want
shallow-line = PKT-LINE("shallow" SP obj-id)
depth-request = PKT-LINE("deepen" SP depth) /
PKT-LINE("deepen-since" SP timestamp) /
PKT-LINE("deepen-not" SP ref)
first-want = PKT-LINE("want" SP obj-id SP capability-list)
additional-want = PKT-LINE("want" SP obj-id)
depth = 1*DIGIT
filter-request = PKT-LINE("filter" SP filter-spec)
客戶端 MUST 將引用發現階段想要的所有 obj-id 作為 want 行傳送。客戶端在其請求正文中 MUST 至少傳送一個 want 命令。客戶端在 want 命令中 MUST NOT 提及未出現在透過 ref 發現獲得的響應中的 obj-id。
客戶端 MUST 將其僅擁有淺複製(意味著它沒有提交的父提交)的所有 obj-id 作為 shallow 行傳送,以便伺服器瞭解客戶端歷史的限制。
客戶端現在傳送其在此事務中想要的提交歷史的最大深度,即從歷史尖端開始想要的提交數量(如果有),作為 deepen 行。深度 0 與不進行深度請求相同。客戶端不希望接收超過此深度的任何提交,也不希望接收僅用於完成這些提交所需的物件。作為結果未接收到其父提交的提交被定義為淺層,並在伺服器中標記為如此。此資訊將在下一步返回給客戶端。
客戶端可以根據需要,使用幾種過濾技術中的一種,選擇性地請求 pack-objects 忽略 packfile 中的各種物件。這些用於部分克隆和部分獲取操作。不滿足 filter-spec 值(除非在 want 行中明確請求)的物件將被忽略。有關可能的 filter-spec 值,請參閱 rev-list。
一旦所有 want 和 shallow(以及可選的 'deepen')傳輸完畢,客戶端 MUST 傳送一個 flush-pkt,告知伺服器端它已完成傳送列表。
否則,如果客戶端傳送了正向深度請求,伺服器將確定哪些提交將是淺層而哪些不是,並將此資訊傳送給客戶端。如果客戶端沒有請求正向深度,則此步驟將被跳過。
shallow-update = *shallow-line
*unshallow-line
flush-pkt
shallow-line = PKT-LINE("shallow" SP obj-id)
unshallow-line = PKT-LINE("unshallow" SP obj-id)
如果客戶端請求了正向深度,伺服器將計算出深度不超過所需深度的提交集。提交集從客戶端的 wants 開始。
伺服器為每個提交寫入 shallow 行,其父提交將不會被髮送。伺服器為每個客戶端已指示為淺層但當前請求深度下不再是淺層的提交(即,其父提交現在將被髮送)寫入 unshallow 行。伺服器 MUST NOT 標記客戶端未指示為淺層的任何內容。
現在客戶端傳送它擁有的 obj-id 列表,使用 have 行,以便伺服器可以製作一個只包含客戶端所需物件的 packfile。在 multi_ack 模式下,標準的實現一次傳送多達 32 個,然後傳送一個 flush-pkt。標準的實現將跳到下一個並立即傳送下一個 32 個,以便始終有 32 個“在網路上傳輸中”的塊。
upload-haves = have-list
compute-end
have-list = *have-line
have-line = PKT-LINE("have" SP obj-id)
compute-end = flush-pkt / PKT-LINE("done")
如果伺服器讀取了 have 行,它將透過 ACK 客戶端聲稱它擁有但伺服器也擁有的任何 obj-id 來響應。伺服器根據客戶端選擇的 ack 模式以不同的方式 ACK obj-id。
在 multi_ack 模式下:
-
伺服器將對任何公共提交響應 ACK obj-id continue。
-
一旦伺服器找到了一個可接受的公共基提交併準備好製作 packfile,它將盲目地將所有 have obj-id ACK 回給客戶端。
-
然後伺服器將傳送一個 NAK,然後等待來自客戶端的另一個響應 - 要麼是 done,要麼是另一組 have 行。
在 multi_ack_detailed 模式下:
-
伺服器將區分 ACK,其中它會透過 ACK obj-id ready 行來指示它已準備好傳送資料,並用 ACK obj-id common 行來指示已識別的公共提交。
在沒有 multi_ack 或 multi_ack_detailed 的情況下:
-
upload-pack 在找到的第一個公共物件上傳送“ACK obj-id”。之後,它不會發出任何聲音,直到客戶端給出“done”。
-
如果尚未找到公共物件,upload-pack 在 flush-pkt 上傳送“NAK”。如果已找到,因此已傳送 ACK,則 flush-pkt 保持靜默。
在客戶端收到足夠的 ACK 響應,使其能夠確定伺服器擁有足夠的資訊來發送高效的 packfile(在標準的實現中,當它收到足夠的 ACK 以至於可以將 --date-order 佇列中剩餘的所有內容著色為與伺服器公共,或者 --date-order 佇列為空時,就會確定),或者客戶端決定放棄(在標準的實現中,當客戶端傳送 256 個 have 行但未收到任何一個被伺服器 ACK 時,就確定了——這意味著沒有共同點,伺服器應該只發送其所有物件),然後客戶端將傳送一個 done 命令。done 命令向伺服器發出訊號,表明客戶端已準備好接收其 packfile 資料。
但是,256 的限制 僅 在標準的客戶端實現中生效,前提是我們在此前一輪中至少收到了一個“ACK %s continue”。這有助於確保在我們完全放棄之前至少找到一個共同祖先。
一旦從客戶端讀取了 done 行,伺服器將傳送一個最終的 ACK obj-id 或傳送一個 NAK。obj-id 是確定的最後一個公共提交的物件名稱。伺服器只在 done 之後傳送 ACK,前提是至少有一個公共基並且啟用了 multi_ack 或 multi_ack_detailed。伺服器在 done 之後總是傳送 NAK,前提是未找到公共基。
代替 ACK 或 NAK,伺服器可能會發送錯誤訊息(例如,如果它不識別客戶端收到的 want 行中的物件)。
然後伺服器將開始傳送其 packfile 資料。
server-response = *ack_multi ack / nak
ack_multi = PKT-LINE("ACK" SP obj-id ack_status)
ack_status = "continue" / "common" / "ready"
ack = PKT-LINE("ACK" SP obj-id)
nak = PKT-LINE("NAK")
一個簡單的克隆可能看起來像這樣(沒有 have 行):
C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
side-band-64k ofs-delta\n
C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
C: 0000
C: 0009done\n
S: 0008NAK\n
S: [PACKFILE]
一個增量更新(fetch)響應可能看起來像這樣:
C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \
side-band-64k ofs-delta\n
C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
C: 0000
C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
C: [30 more have lines]
C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
C: 0000
S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
S: 0008NAK\n
C: 0009done\n
S: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
S: [PACKFILE]
Packfile 資料
現在客戶端和伺服器已經完成了關於需要傳送到客戶端的最小資料量的協商,伺服器將構造並以 packfile 格式傳送所需資料。
有關 packfile 本身外觀的更多資訊,請參閱 gitformat-pack[5]。
如果客戶端指定了 side-band 或 side-band-64k 功能,伺服器將以多路複用的方式傳送 packfile 資料。
每個資料包都以資料包行的長度開頭,表示後續資料的數量,後跟一個指定資料所在的 sideband 的單個位元組。
在 side-band 模式下,它最多傳送 999 個數據位元組加上 1 個控制碼,總共最多 1000 個位元組在一個 pkt-line 中。在 side-band-64k 模式下,它最多傳送 65519 個數據位元組加上 1 個控制碼,總共最多 65520 個位元組在一個 pkt-line 中。
sideband 位元組將是 1、2 或 3。Sideband 1 將包含 packfile 資料,sideband 2 將用於客戶端通常會列印到 stderr 的進度資訊,sideband 3 用於錯誤資訊。
如果沒有指定 side-band 功能,伺服器將不進行多路複用,直接流式傳輸整個 packfile。
向伺服器推送資料
向伺服器推送資料將呼叫伺服器上的 receive-pack 程序,該程序將允許客戶端告知它應該更新哪些引用,然後傳送伺服器完成這些新引用所需的所有資料。一旦接收並驗證了所有資料,伺服器將更新其引用以匹配客戶端指定的版本。
認證
協議本身不包含任何認證機制。這應由傳輸協議(如 SSH)在呼叫 receive-pack 程序之前處理。如果 receive-pack 透過 Git 傳輸協議配置,則可以向訪問該埠(9418)的任何人寫入,因為該傳輸協議未進行身份驗證。
引用發現
引用發現階段與獲取協議中的過程幾乎相同。伺服器上的每個引用物件 ID 和名稱都以 packet-line 格式傳送到客戶端,後跟一個 flush-pkt。唯一的實際區別在於能力列表不同 - 唯一可能的值是 report-status、report-status-v2、delete-refs、ofs-delta、atomic 和 push-options。
引用更新請求和 Packfile 傳輸
一旦客戶端知道伺服器上的引用版本,它就可以傳送引用更新請求列表。對於伺服器上它想要更新的每個引用,它傳送一行,列出伺服器上當前的 obj-id、客戶端想要將其更新到的 obj-id 以及引用的名稱。
此列表後跟一個 flush-pkt。
update-requests = *shallow ( command-list | push-cert )
shallow = PKT-LINE("shallow" SP obj-id)
command-list = PKT-LINE(command NUL capability-list)
*PKT-LINE(command)
flush-pkt
command = create / delete / update
create = zero-id SP new-id SP name
delete = old-id SP zero-id SP name
update = old-id SP new-id SP name
old-id = obj-id
new-id = obj-id
push-cert = PKT-LINE("push-cert" NUL capability-list LF)
PKT-LINE("certificate version 0.1" LF)
PKT-LINE("pusher" SP ident LF)
PKT-LINE("pushee" SP url LF)
PKT-LINE("nonce" SP nonce LF)
*PKT-LINE("push-option" SP push-option LF)
PKT-LINE(LF)
*PKT-LINE(command LF)
*PKT-LINE(gpg-signature-lines LF)
PKT-LINE("push-cert-end" LF)
push-option = 1*( VCHAR | SP )
如果伺服器已宣佈 push-options 功能,並且客戶端已在上述功能列表中指定了 push-options,則客戶端會發送其 push 選項,後跟一個 flush-pkt。
push-options = *PKT-LINE(push-option) flush-pkt
為了向後相容舊的 Git 伺服器,如果客戶端傳送推送證書和推送選項,它 MUST 將其推送選項同時嵌入到推送證書內和推送證書之後傳送。(請注意,證書內的推送選項前面有字首,而證書後的推送選項沒有。)這兩個列表 MUST 相同,除了字首。
之後,將傳送包含伺服器完成新引用所需的所有物件的 packfile。
packfile = "PACK" 28*(OCTET)
如果接收端不支援 delete-refs,傳送端 MUST NOT 請求 delete 命令。
如果接收端不支援 push-cert,傳送端 MUST NOT 傳送 push-cert 命令。當傳送 push-cert 命令時,command-list MUST NOT 被髮送;而是使用推送證書中記錄的命令。
如果使用的唯一命令是 delete,則 packfile MUST NOT 被髮送。
如果使用了 create 或 update 命令,則 packfile MUST 被髮送,即使伺服器已擁有所有必需的物件。在這種情況下,客戶端 MUST 傳送一個空的 packfile。唯一可能發生這種情況的情況是客戶端正在建立一個指向現有 obj-id 的新分支或標籤。
伺服器將接收 packfile,解包,然後驗證正在更新的每個引用(在請求處理過程中未發生更改,即 obj-id 仍然與 old-id 相同),並執行任何更新鉤子以確保更新是可接受的。如果所有這些都正常,伺服器將更新引用。
推送證書
推送證書以一組頭部行開頭。在頭部和空行之後,是協議命令,每行一個。請注意,推送證書 PKT-LINE 中的尾部 LF 不是 可選的;它必須存在。
當前,已定義以下頭部欄位:
GPG 簽名行是對推送證書內容(在簽名塊開始之前)的獨立簽名。獨立簽名用於證明命令是由推送者提供的,推送者必須是簽名者。
報告狀態
在接收發送者傳送的 pack 資料後,如果 report-status 或 report-status-v2 功能處於生效狀態,接收者會發送報告。它是一個簡短的列表,說明更新中發生了什麼。它首先列出 packfile 解包的狀態,為 unpack ok 或 unpack [error]。然後它會列出它嘗試更新的每個引用的狀態。每行是 ok [refname](如果更新成功),或 ng [refname] [error](如果更新失敗)。
report-status = unpack-status
1*(command-status)
flush-pkt
unpack-status = PKT-LINE("unpack" SP unpack-result)
unpack-result = "ok" / error-msg
command-status = command-ok / command-fail
command-ok = PKT-LINE("ok" SP refname)
command-fail = PKT-LINE("ng" SP refname SP error-msg)
error-msg = 1*(OCTET) ; where not "ok"
report-status-v2 功能透過新增新的選項行來擴充套件協議,以支援由 proc-receive 鉤子重寫引用的報告。proc-receive 鉤子可以處理一個偽引用的命令,該命令可能會建立或更新一個或多個引用,並且每個引用可能具有不同的名稱、不同的 new-oid 和不同的 old-oid。
report-status-v2 = unpack-status
1*(command-status-v2)
flush-pkt
unpack-status = PKT-LINE("unpack" SP unpack-result)
unpack-result = "ok" / error-msg
command-status-v2 = command-ok-v2 / command-fail
command-ok-v2 = command-ok
*option-line
command-ok = PKT-LINE("ok" SP refname)
command-fail = PKT-LINE("ng" SP refname SP error-msg)
error-msg = 1*(OCTET) ; where not "ok"
option-line = *1(option-refname)
*1(option-old-oid)
*1(option-new-oid)
*1(option-forced-update)
option-refname = PKT-LINE("option" SP "refname" SP refname)
option-old-oid = PKT-LINE("option" SP "old-oid" SP obj-id)
option-new-oid = PKT-LINE("option" SP "new-oid" SP obj-id)
option-force = PKT-LINE("option" SP "forced-update")
更新可能因多種原因而不成功。引用可能自最初發送引用發現階段以來已更改,意味著有人在此期間推送了。推送的引用可能是非快進引用,並且更新鉤子或配置被設定為不允許,等等。此外,某些引用可以被更新,而其他引用可能被拒絕。
一個典型的客戶端/伺服器通訊可能看起來像這樣:
S: 006274730d410fcb6603ace96f1dc55ea6196122532d refs/heads/local\0report-status delete-refs ofs-delta\n S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n S: 003d74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n S: 0000 C: 00677d1665144a3a975c05f1f43902ddaf084e784dbe 74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n C: 006874730d410fcb6603ace96f1dc55ea6196122532d 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n C: 0000 C: [PACKDATA] S: 000eunpack ok\n S: 0018ok refs/heads/debug\n S: 002ang refs/heads/master non-fast-forward\n