Git
Chapters ▾ 2nd Edition

10.6 Dahili Git Ögeleri - Transfer Protokolleri

Transfer Protokolleri

Git, iki repo arasında veri transferini iki ana şekilde yapabilir: "aptal" protokol ve "akıllı" protokol. Bu bölüm, bu iki ana protokolün nasıl çalıştığını kısaca ele alacaktır.

Aptal Protokol

Eğer bir reposunu HTTP üzerinden salt okunur olarak sunmak üzere kuruyorsanız, muhtemelen aptal protokol kullanılacaktır. Bu protokol taşıma sürecinde sunucu tarafında Git’e özgü herhangi bir kod gerektirmediği için "aptal" olarak adlandırılır; çekme işlemi, istemcinin sunucudaki Git reposunun düzenini üstlenebildiği bir dizi HTTP GET isteğidir.

Not

Aptal protokol bu günlerde oldukça nadiren kullanılmaktadır. Güvenliği sağlamak veya özel hale getirmek zor olduğu için çoğu Git ana bilgisayarı (hem bulut tabanlı hem de şirket içi) onu kullanmayı reddedecektir. Genel olarak, biraz ileride açıklayacağımız üzere, akıllı protokolün kullanılması tavsiye edilir.

Simplegit kütüphanesi için http-fetch sürecini takip edelim:

$ git clone http://server/simplegit-progit.git

Bu komutun yaptığı ilk şey info/refs dosyasını aşağı çekmektir. Bu dosya update-server-info komutu tarafından yazılmıştır, bu nedenle HTTP aktarımının düzgün çalışması için bunu bir post-receive (çekme sonrası) kancası olarak etkinleştirmeniz gerekir:

=> GET info/refs
ca82a6dff817ec66f44342007202690a93763949     refs/heads/master

Artık uzak referansların ve SHA-1’lerin bir listesine sahipsiniz. Sonra, HEAD referansının ne olduğuna bakarsınız, böylece işiniz bittiğinde neyi kontrol etmeniz gerektiğini bilirsiniz:

=> GET HEAD
ref: refs/heads/master

İşlemi tamamladığınızda master şubesine göz atmanız gerekiyor. Bu noktada yürüme sürecine başlamaya hazırsınız. Başlangıç ​​noktanız, info/refs dosyasında gördüğünüz ca82a6 katkı nesnesi olduğundan, şunu çekerek başlarsınız:

=> GET objects/ca/82a6dff817ec66f44342007202690a93763949
(179 bytes of binary data)

Bir nesneyi geri alırsınız; bu nesne sunucuda gevşek biçimdedir ve onu statik bir HTTP GET isteği üzerinden getirdiniz. Sıkıştırılmış zlib’i açabilir, başlığı (header) çıkarabilir ve katkı içeriğine bakabilirsiniz:

$ git cat-file -p ca82a6dff817ec66f44342007202690a93763949
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700

changed the version number

Daha sonra, almanız gereken iki nesne daha var: az önce aldığımız katkının işaret ettiği içerik ağacı olan cfda3b ve öncel katkısı olan 085bb3:

=> GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
(179 bytes of data)

Bu size bir sonraki katkı nesnenizi verir. Ağaç nesnesini alın:

=> GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf
(404 - Not Found)

Hata! Görünüşe göre ağaç nesnesi sunucuda gevşek formatta olmadığı için 404 yanıtı alıyorsunuz. Bunun birkaç nedeni olabilir: nesne, alternatif bir repoda veya bu repodaki bir paket dosyasında olabilir. Git önce listelenen alternatifleri kontrol eder:

=> GET objects/info/http-alternates
(empty file)

Bu, alternatif URL’lerin bir listesiyle birlikte gelirse, Git oradaki gevşek dosyaları ve paket dosyalarını kontrol eder; bu diskteki nesneleri paylaşmak için birbirinden çatalı olan projeler için güzel bir mekanizmadır. Ancak burada hiçbir alternatif listelenmediğinden nesnenizin bir paket dosyasında olması gerekir. Bu sunucuda hangi paket dosyalarının mevcut olduğunu görmek için, bunların bir listesini içeren (ayrıca update-server-info tarafından oluşturulan) objects/info/packs dosyasını almanız gerekir:

=> GET objects/info/packs
P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack

Sunucuda yalnızca bir paket dosyası olduğu için nesneniz açıkça oradadır, ancak emin olmak için dizin dosyasını kontrol edeceksiniz. Bu aynı zamanda sunucuda birden fazla paket dosyanız varsa kullanışlıdır, böylece ihtiyacınız olan nesneyi hangi paket dosyasının içerdiğini görebilirsiniz:

=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx
(4k of binary data)

Artık paket dosyası dizinine sahip olduğunuza göre, nesnenizin burada olup olmadığını görebilirsiniz; çünkü dizin, paket dosyasında bulunan nesnelerin SHA-1’lerini ve bu nesnelerin uzaklıklarını listeler. Nesneniz orada, o yüzden devam edin ve paket dosyasının tamamını alın:

=> GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack
(13k of binary data)

Ağaç nesneniz var, böylece katkılarınızı yürütmeye devam edersiniz. Bunların hepsi aynı zamanda yeni indirdiğiniz paket dosyasının içindedir, dolayısıyla sunucunuza başka istekte bulunmanıza gerek yoktur. Git başlangıçta indirdiğiniz HEAD referansının işaret ettiği master dalının çalışan bir kopyasını kontrol eder.

Akıllı Protokol

Aptal protokol basit ama biraz verimsizdir ve istemciden sunucuya veri yazılmasını sağlayamaz. Akıllı protokol, veri aktarmanın daha yaygın bir yöntemidir ancak uzak uçta Git konusunda akıllı olan bir işlem gerektirir; yerel verileri okuyabilir, istemcinin neye sahip olduğunu ve neye ihtiyaç duyduğunu anlayabilir ve bunun için özel bir paket dosyası oluşturabilir. Veri aktarımı için iki süreç kümesi vardır: veri yüklemek için bir çift ve veri indirmek için bir çift.

Veri Yüklemek

Git uzak bir sürece veri yüklemek için send-pack ve receive-pack süreçlerini kullanır. send-pack süreci istemcide çalışır ve uzak tarafta bir receive-pack sürecine bağlanır.

SSH

Örneğin, bir projede git push origin master komutunu çalıştırdığınızı ve origin 'in SSH protokolünü kullanan bir URL olarak tanımlandığını varsayalım. Git, sunucunuza bir SSH bağlantısı üzerinden başlatılan send-pack sürecini çalıştırır. Uzak sunucuda bir komut çalıştırmaya çalışır ve bunun için bir SSH çağrısı yapar. Örnek olarak şöyle bir şey olabilir:

$ ssh -x git@server "git-receive-pack 'simplegit-progit.git'"
00a5ca82a6dff817ec66f4437202690a93763949 refs/heads/master□report-status \
	delete-refs side-band-64k quiet ofs-delta \
	agent=git/2:2.1.1+github-607-gfba4028 delete-refs
0000

git-receive-pack komutu şu anda sahip olduğu her referans için bir satır ile hemen yanıt verir (burada sadece master dalı ve onun SHA-1’ı). İlk satır aynı zamanda sunucunun yeteneklerinin bir listesini de içerir (burada report-status, delete-refs ve istemci tanımlayıcısı da dahil, başkaları ).

Her satır geri kalan kısmın ne kadar uzun olduğunu belirten 4 karakterlik bir onaltılık değerle başlar. İlk satır 00a5 ile başlar, bu da geri kalan kısmın 165 bayt olduğunu belirtir. Bir sonraki satır 0000’dir, bu da sunucunun referans listelemesinin bittiğini belirtir.

Artık sunucunun durumunu bildiğine göre, send-pack süreci sunucunun sahip olmadığı hangi katkıların olduğunu belirler. send-pack süreci bu bilgiyi, bu itişin güncelleyeceği her referans için receive-pack sürecine bildirir. Örneğin, master dalını güncelliyor ve experiment dalı ekliyorsanız, send-pack 'in yanıtı şöyle görünebilir:

0076ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 \
	refs/heads/master report-status
006c0000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d \
	refs/heads/experiment
0000

Git, güncellediğiniz her referans için satırın uzunluğunu, eski SHA-1’i, yeni SHA-1’i ve güncellenmekte olan referansı içeren bir satır gönderir. İlk satır aynı zamanda istemcinin yeteneklerine de sahiptir. Tüm sıfırların SHA-1 değeri, daha önce hiçbir şeyin olmadığı anlamına gelir; çünkü deneme referansı ekliyorsunuz. Bir referansı siliyorsanız tam tersini görürsünüz: tüm sıfırlar sağ tarafta.

Daha sonra istemci, sunucunun henüz sahip olmadığı tüm nesnelerin bir paket dosyasını gönderir. Son olarak sunucu bir başarı (veya başarısızlık) göstergesiyle yanıt verir:

000eunpack ok
HTTP(S)

Bu işlem çoğunlukla HTTP üzerinden aynıdır, ancak el sıkışma biraz farklıdır. Bağlantı şu istekle başlatılır:

=> GET http://server/simplegit-progit.git/info/refs?service=git-receive-pack
001f# service=git-receive-pack
00ab6c5f0e45abd7832bf23074a333f739977c9e8188 refs/heads/master□report-status \
	delete-refs side-band-64k quiet ofs-delta \
	agent=git/2:2.1.1~vmg-bitmaps-bugaloo-608-g116744e
0000

Bu, ilk istemci-sunucu değişiminin sonudur. İstemci daha sonra send-pack 'in sağladığı verilerle bu sefer bir POST olan başka bir istekte bulunur.

=> POST http://server/simplegit-progit.git/git-receive-pack

POST isteği, yük olarak send-pack çıktısını ve paket dosyasını içerir. Sunucu daha sonra başarılı veya başarısız olduğunu HTTP yanıtı ile belirtir.

Veri İndirme

Veri indirdiğinizde, fetch-pack ve upload-pack süreçleri devreye girer. İstemci, indirilecek verileri belirlemek için uzak tarafta upload-pack sürecine bağlanan bir fetch-pack süreci başlatır.

SSH

Eğer SSH üzerinden indirme yapıyorsanız, fetch-pack şu şekilde çalışır:

$ ssh -x git@server "git-upload-pack 'simplegit-progit.git'"

fetch-pack bağlandıktan sonra, upload-pack şuna benzer bir şey gönderir:

00dfca82a6dff817ec66f44342007202690a93763949 HEAD□multi_ack thin-pack \
	side-band side-band-64k ofs-delta shallow no-progress include-tag \
	multi_ack_detailed symref=HEAD:refs/heads/master \
	agent=git/2:2.1.1+github-607-gfba4028
003fe2409a098dc3e53539a9028a94b6224db9d6a6b6 refs/heads/master
0000

Bu receive-pack'in yanıtına çok benzer, ancak yetenekler farklıdır. Ayrıca bu bir kopya ise, HEAD’e ne işaret ettiğini (symref=HEAD:refs/heads/master) geri gönderir, böylece istemci neyi klonlayacağını bilir.

Bu noktada fetch-pack süreci sahip olduğu nesnelere bakar ve ihtiyaç duyduğu nesneleri want ve ardından istediği SHA-1 ile göndererek yanıt verir. Zaten sahip olduğu tüm nesneleri have ve ardından SHA-1 ile gönderir. Bu liste sonuna, ihtiyaç duyduğu veri paket dosyasını göndermeye başlamak için upload-pack sürecini başlatmak için done yazılır:

003cwant ca82a6dff817ec66f44342007202690a93763949 ofs-delta
0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
0009done
0000
HTTP(S)

İndirme işlemi için anlaşma (handshake) iki HTTP isteği alır. İlk olarak, aptal protokolde kullanılan aynı uç noktaya bir GET isteği gönderilir:

=> GET $GIT_URL/info/refs?service=git-upload-pack
001e# service=git-upload-pack
00e7ca82a6dff817ec66f44342007202690a93763949 HEAD□multi_ack thin-pack \
	side-band side-band-64k ofs-delta shallow no-progress include-tag \
	multi_ack_detailed no-done symref=HEAD:refs/heads/master \
	agent=git/2:2.1.1+github-607-gfba4028
003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master
0000

Bu işlem bir SSH bağlantısı üzerinden git-upload-pack 'i çağırmaya çok benzer, ancak ikinci değişim ayrı bir istek olarak gerçekleştirilir:

=> POST $GIT_URL/git-upload-pack HTTP/1.0
0032want 0a53e9ddeaddad63ad106860237bbf53411d11a7
0032have 441b40d833fdfa93eb2908e52742248faf0ee993
0000

Yine yukarıdakiyle aynı formattadır. Bu isteğe yanıt, başarı veya başarısızlığı gösterir ve paket dosyasını içerir.

Özet Olarak Protokoller

Bu bölüm aktarım protokollerine çok temel bir genel bakış içerir. Protokol multi_ack veya side-band yetenekleri gibi birçok başka özellik içerir, ancak bunlar bu kitabın kapsamı dışındadır. Size istemci ile sunucu arasındaki genel gidiş-geliş hakkında bir fikir vermeye çalıştık; bundan daha fazla bilgiye ihtiyacınız varsa muhtemelen Git kaynak koduna bakmak isteyeceksiniz.

scroll-to-top