You are currently viewing Sunucu Üzerinde Git ile Çalışmak

Sunucu Üzerinde Git ile Çalışmak

Önceki yazımızda git ile projelerinizi nasıl geçmişleri ile beraber takip edebileceğimizi öğrenmiştik. Eğer okumadıysanız şu linkteki yazımızı okumayı ihmal etmeyin. Bu videomuz ise bir sunucuda bulunduracağımız bir ortak repository (remote repository) ile nasıl çalışacağımızı öğreneceğiz. Sunucularda bulunduracağımız repositorylerde doğrudan bir düzenleme yapılmaz. Bundan ötürü bu repository’lerde çalışma ağacı (working tree) bulunmaz. Bu tip repository’lere bare repository adı verilmektedir. Bare repository’ler yalnızca ./git dosyalarını içerirler. Ortak bir kabul olarak da bu dizin isimleri .git şeklinde biter. Bare repository oluşturmak için git init komutu –bare parametresi ile birlikte kullanılır. gelin hep birlikte bir örnek yapalım.

Ortak Repository Oluşturma (git init –bare)

Bu şekilde bir bare repository oluşturmuş olduk. Tipik olarak bu repository’ler sunucularda bulunmaktadır. Fakat bu örneğimiz için ortak olan repository de aynı makinede bulunacaktır. Yazımızın devamında bu repository’i nasıl bir sunucu üzerinden kullanabiliriz inceleyeceğiz. Şimdi ekibimizde bulunan iki geliştiricimiz için bu ortak repository’i klonlayalım. Bunun için git clone komutu kullanılır.

Klonlama (git clone)

Bu şekilde iki geliştiricimiz Umut ve Elif, kendi yerel (local) klonları üzerinde çalışabilirler. Öncelikle Umut’un klonuna giderek git remote komutunu çağıralım.

git remote komutu bizlere yerel repo’nun bağlı olduğu uzak repo’lar hakkında bilgi vermektedir. Başka bir repodan klonlanmış olduğundan dolayı burada origin isimli uzak repo’nun bizim için eklendiğini ve bu repo’nun fetch ve push işlemleri için kullanılacağını görüyoruz. -v parametresi daha detaylı bilgi almak için verilebilmektedir.

Öncelikle Umut, C dilinde bir “Hello, World” uygulaması yazmış olsun ve bunu ortak olan sunucuya koysun. Bunun için geçen yazımızda bahsettiğimiz yerel repo’da commit işlemi yapıldıktan sonra git push komutu ile bu değişiklikler uzaktaki repo’ya gönderilir.

Bazı dosyaları görmezden gelme (.gitignore)

Projemizi derledik. Commit’imize eklemek istediğimiz kod dosyamızı ekledikten sonra git status komutunu çalıştırdığımızda main.exe isimli dosyanın takip edilmeyen dosyalar arasında gösterildiğini görüyoruz. Fakat bu bilinçli olarak istediğimiz bir durum. Çünkü çalıştırılabilen dosyalar projenin bir parçası değil, bir sonucudur. Ayrıca bu çalıştırılabilir dosyalar kullanıcının veya geliştiricinin kullandığı donanıma ve sistem özelliklerine göre değişecektir. Ayrıca projemiz içerisinde yalnızca çalışma ortamına veya geliştiriciye özel hassas bilgiler içeren dosyalar da bulunabilir. Bu dosyaların git tarafından takip edilmemesi gerektiğini açıkça belirtmek için .gitignore dosyası oluşturulur. Bu özel isimli dosyanın içine ihmal edilmesi gereken dosyalar listelenir. Doğrudan dosya ve dizin adı yazılabildiği gibi şablonlar (pattern) oluşturmak için özel karakterler vardır. Detaylı bilgilere şu linkten ulaşabilirsiniz. Bu yazımızda en çok kullanılanları açıklayacağız.

  • Dizinleri ayırmak için ‘/’ karakteri kullanılır. Eğer başında veya ortasında ‘/’ karakteri içeren bir dizin var ise bu, .gitignore dizinin bulunduğu dizinden itibaren bulunan dizinleri ve dosyaları ifade eder.
  • Eğer ifadenin sonunda ‘/’ karakteri var ise bu ifade yalnızca dizinler için geçerli olur. Eğer yoksa bu ifade hem dizinler hem de dosyalar için geçerlidir.
  • * karakteri tüm uzunluklardaki ‘/’ hariç tüm karakteri ifade eder. Örneğin *.exe ifadesi .exe ile biten bütün dosyaları ifade etmektedir.
  • ‘!’ karakteri bu şablona uymayan bütün ifadeleri kapsar. İfadenin tersini alır da diyebiliriz.
  • ‘**’ ifadesi mevcut dizin ve bu dizinin bütün alt dizinleri anlamına gelir. Örneğin “**/foo/bar” ifadesi nerede olursa olsun tüm “foo” dizini altındaki “bar” dosya ve dizinlerini kapsar.

Örneğimize dönecek olursak “main” isimli dosyanın versiyon kontrol sistemine dahil olmamasını istiyoruz. Bunun için .gitignore dosyamızı oluşturalım. Burada dosyamızda tek satır ekleyerek “main” isimli dosya ve dizinlerin ihmal edilmesini sağlıyoruz.

Tekrar git statue komutunu çalıştırdığımızda artık main isimli dosyanın takip edilmeyen dosyalar kısmında görüntülenmediğini görüyoruz. .gitignore dosyamızı da ekleyerek commit işlemimizi yapalım.

Bu değişikliği yerel repo’muzda yaptık fakat henüz ortak repo’muza göndermedik bunun içinse git push komutunu kullanalım. Burada main isimli dalımızı (branch), origin isimli uzak repo’muza gönderiyoruz.

Bu sırada Elif isimli geliştiricimiz de aynı proje üstünde çalışıyor olsun fakat ufak bir farkla. Her geliştiricinin bir yoğurt yiğişi vardır sonuçta.

Elif aynı değişikliği yapıp origin‘e push etmeye çalıştığında yukarıdaki hatayı alıyor. Hata mesajında uzak repo’da olan bir değişiklikten Elif’in yerel repo’sunun haberi olmadığını söylüyor. Bunun giderilmesi için push yapılmadan önce git pull komutunun çalıştırılması öneriliyor. O zaman gelin bu komutu çalıştıralım.

git pull komutunu çalıştırdığımızda uzak ve yerel dalların birbirinden ayrıldığını ve bunu nasıl çözümlemek istediğimizi belirtmemiz isteniyor. Bunun için iki ana opsiyonumuz var: merge veya rebase. –rebase parametresi ile rebase operasyonu, –no-rebase ile de merge operasyonu ile bu ayrılığı giderebiliriz. Öncelikle rebase operasyonunun nasıl sonuç vereceğine bakalım.

Rebase operasyonunun başladığını fakat bir çakışma olduğunu, bu çakışma çözüldükten sonra git rebase –continue komutu ile devam edebileceğimizi görüyoruz. Gelin çalışma ağacımızda main.c dosyasının durumuna bakalım.

Burada çakışmanın olduğu kısmı, görebiliyoruz. Burada dosyayı en son olmasını istediğimiz haline getirip dosyayı kaydederek git rebase –continue komutunu çalıştırabiliriz.

Böylece rebase işlemimizi gerçekleştirmiş olduk. Gelin git log komutu ile commit geçmişimize bakalım.

git log çıktısına baktığımızda Elif’in yaptığı commit’in ilk commit olarak değil, Umut’un commit’inin üzerine yapılmış olduğunu görüyoruz. İşte rebase komutu tam olarak bu işlemi yapmaktadır. Bir commit’i, bir başka commit’in sonrasına taşımaktadır. Bu işlemin commit geçmiş’ini, yani kronolojik sıralamasını değiştirdiğini belirtelim.

Peki eğer diğer opsiyonumuz olan merge operasyonu ile nasıl bir sonuç alırdık gelin birlikte görelim.

Git pull komutunu –no-rebase komutu ile çalıştırdığımızda merge operasyonu başlamış oluyor. Fakat hata mesajından görebileceğimiz üzere benzer biçimde main.c dosyamızda bir çakışma durumu oluştu ve bunu çözmemizi, ve sonucu commit etmemizi istiyor. main.c dosyamıza bakalım.

main.c dosyamızın benzer biçimde olduğunu gördük. Dosyamızı kaydedip commit ettiğimizde şöyle bir git log çıktısı ile karşı karşıya kalıyoruz.

Burada commit geçmişimizin doğrusal bir şekilde ilerlemediğini, bir dallanma olduğunu görüyoruz. Ayrıca merge işlemi esnasında merge commit denilen yenidir Committee de oluştu. Burada commit geçmişimde bakarak iki geliştiricinin aynı zamanlarda paralel olarak çalışmış olduklarını görmekteyiz. Hatırlayacak olursak rebase yaptığımızda Elif’in yaptığı değişiklik sanki Umut’tan sonra yapılmış gibi görünüyordu. İşte rebase ve merge arasındaki temel fark budur.

Rebase ise daha temiz lineer bir commit geçmişi elde edilir, ayrıca merge commitleri oluşmaz. Böylece commit’ler içerisinde bir şeyler aramak kolaylaşır. Fakat rebase işlemi commit geçmişini değiştirdiğinden hangi değişikliğin ne zaman yapılmış olduğu ile ilgili yanılgılar oluşabilir. Merge kullanıldığında daha karmaşık bir yapı oluşur ve kesişim noktalarında merge commt’ler bulunur fakat kronolojik sıra korunur.

Git ile uzak sunucuda çalışmak

Yukarıda yaptığımız örneklerde ortak repo olarak aynı bilgisayarda bulunan bir dizini kullandık. Günlük hayatta farklı geliştiriciler farklı makineler kullandığından bu ortak repo’ların herkesin erişimin bulunduğu sunucularda barındırılması gerekmektedir. Bunun için 3 temel protokol bulunur.

  • Paylaşımlı klasör: Tıpkı aynı bilgisayardaki bir başka dizini kullandığımız gibi herkesin erişiminin bulunduğu paylaşımlı bir klasör de kullanılabilir. Fakat bu çözüm aynı yerel ağda bulunmayı ya da VPN kullanımını gerektirdiğinden çok tercih edilmemektedir.
  • HTTP: Git repo’ları uzak bir sunucudan internet bağlantısı ile HTTP protokolü ile sağlanabilmektedir. Kurulumu SSH protokolüne göre daha kolaydır. Doğrudan kullanıcı adı ve şifre ile kimlik kontrolü yapılabilmektedir (authentication). Yaygın olarak kullanılmaktadır. GitHub, HTTP desteğini bırakmış durumdadır.
  • SSH: SSH protokolü uzak bilgisayarlara terminal veya dosya sistemi üzerinden bağlanmaya yarayan bir protokoldür. Güvenlik için SSH key denen özel ve genel anahtarlar kullanır. Bu anahtarlar istemci (client) tarafından oluşturulur. Sunucu ile yalnızca genel anahtar paylaşılır. Kullanıcı bağlantıyı özel anahtar ile açar, sunucu ise genel anahtar kullanıcının kimliğini doğrular. GitHub güncel olarak yalnızca SSH protokolünü kullanmaktadır.

Bu yazımızda git versiyon kontrol sisteminin bir sunucu ve ortak repo üzerinde nasıl kullanıldığını, çakışmalar olması halinde nasıl çözümlenebileceğini, marge ve rebase stratejileri arasında ne gibi farklar bulunduğunu ve git’i nasıl uzak bir sunucu makine üzerinden kullanabileceğimizi inceledik. Bir sonraki yazımızda git’in derinliklerine ineceğiz ve arkaplanda nasıl çalıştığını inceleyeceğiz. Şimdilik görüşmek üzere.

Bir yanıt yazın