13 Mart 2013 Çarşamba

Yeni Başlayanlar için Git ve Kullanımı


Git Nedir ? 

Yazılım dünyasına yeni adım atanlar projelerini versiyonlamayı "proje son , "proje en son" gibi klasör adlarıyla ya da tarihler ile yapmaya çalışırlar.Bu tarz isimlendirmeler belli bir süre sonra çok fazla yer kaplamaya ve çok dağınık bir hal almaya başlar. Bunun önüne geçmek  daha düzgün ve efektif çalışmak için birçok versiyonlama araçları geliştirmiştir.GIT bunların en yaygını ve kişisel görüşüm en kullanışlısıdır.
Eğer siz de java,c,c++,php, html ,css , python , perl vb dillerde projeler geliştiriyorsanız kesinlikle Git kullanmanızı tavsiye ederim.






GIT Mac Os X 'de kurulu gelmektedir.
Ubuntu da ise terminale sudo apt-get install git yazarak  kurabilirsiniz.
Windows üzerinde kuracak bir makinem olmadığından malesef kurulum hakkında bilgi veremeyeceğim.
Çok basit bir araştırma ile windows ve diğer işletim sistemlerine de kurulabileceğinize eminim. 

Git kurulumunu yaptıktan sonra hadi birkaç basit ayar ile git uygulamamızı özelleştirelim.

Git de temel olarak 3 config seviyesi bulunmaktadır.


System ile  sistemdeki bütün kullanıcılar aynı ayarlara sahip olur.
Global ile sadece mevcut kullanıcı tanımlanan ayarlara sahip olur.
Local ile ise  her repository ya da proje için ayrı ayrı ayarlara sahip olunabilir.

Bilgisayarımın tek kullanıcısı ben olduğumdan System seviyesini kullanmayı tercih ediyorum. Siz de bilgisayarınızın durumuna göre global ya da local'i seçebilirsiniz.

git config --system user.name "Anar Bayramov"
git config --system user.mail "rodrane@gmail.com"

yazarak ismimi ve emailimi tanımlıyorum.Bu arada belirteyim  --system parametresini girmeseydim ayarlarım default olarak repository seviyesinde kayıt edilecekti.

cat ~/.gitconfig yazarak  işlemlerin gerçekleşip gerçekleşmediğini  kontrol edebilirsiniz.

Daha sonra git config --system color.ui true yazarak git çıktılarımıza biraz renk katalım bu sayede çok sayıda dosyanın ve klasörün bulunduğu büyük projelerde karmaşık bir çıktı ekranıyla boğuşmak zorunda kalmayacağız. Renk komutları isteğe göre özelleştirilebilmektedir fakat bu yazımda bu konuya değinmeyi düşünmüyorum.
Daha ileride çok sık kullanacağımız komutlar için de  kısayollar oluşturmanın işimizi bir hayli kolaylaştıracağına inanıyorum.

Öncelikle git config --system alias.s status komutunu verelim böylece git status yazmak yerine kısaca git s yazarak aynı çıktıları alabileceğiz.Ama ben yazım boyunca git status komutunu kullanmaya devam edeceğim.

Bir diğer çok sık kullanılan komut olan git add bunun için de git config --system alias.a add komutunu verip git a komutuyla aynı işlemi gerçekleştirebileceğiz.git status komutunda olduğu gibi ben yazım boyunca git add komutunu kullanmaya devam edeceğim.
Bu arada belirtmek isterim bu kısayolların belirli bir standardı yok sizde istediğiniz bir kısayolu seçmekte özgürsünüz.
Ben mesela git config --system alias.t commit komutuyla git commit yerine git t kullanmayı tercih ediyorum. Siz git config --system alias.cm yazarak aynı kısayolu t yerine cm olarak seçebilirsiniz.

Aslına bakarsanız küçük bir araştırmayla uzun zamandır git kullanan kişilerin config dosyalarını bulabilirsiniz. Bu dosyalar öğrenmek ve kullanmak açısından güzel birer örnek olabilirler
Büyük ihtimal yazılan komutların ne olduğunu anlamayacaksınız ama emin olun yazım boyunca bir çoğunun üzerinden geçeceğiz.


Git ayarlarımızı da tamamladığımıza göre  projemiz için yeni bir klasör oluşturup terminalden bu klasöre ulaşalım.


git init komutu ile  git'i  oluşturduğumuz projemiz için tanımlayalım.Aksi halde git'in nimetlerinden faydalanamayacağız :) 


git init işlemini tamamladıktan sonra dizin içerisinde yapılacak herhangi bir değişiklik kayıt altına alınmaya başlanacak. Nelerin değiştiğini git status komutu ile kontrol edebileceğiz.

Git tercihe göre istenilmeyen dosyalardaki değişiklikleri takip etmeyebilir.Bunun nasıl yapılacağını birazdan anlatacağım.

Şuan git status komutunu girdiğimizde hiç bir dosyanın takip edilmediği hakkında bir ileti görüyoruz. Bunun sebebi git'in kullanıcının takip edilmesini istediği dosyaları belirtmesini bekler. Takip edilmeyen dosyalardaki değişiklikler kayıt altına alınmaz.

git add dosyaadi ile istenilen bir dosya ya da dizin takip edilebilir Terminolojiye daha bir deyişle depolama alanına (stage area) kaydedilir.

Mesela klasörümüze index.php adında bir dosya ekledikten sonra git status komutunu verdiğimizde aşağıda new file yazısının çıktığını görürürüz bunun sebebi bu dosyanın daha önceki versiyonda bulunmuyor olması yani yeni yaratılmış olmasıdır.
Daha önce takip edilmiş ve üzerinde değişiklik yapılmış dosyalarda ise modified yazısı görebilirsiniz.


Tamam herşey güzel peki depolama alanına dosyaları hep böyle tek tek mi atacağız bunun daha kolayı yok mu ? 

Tabiki var.
Belirli bir klasörü atmak için  git add klasoradi , 
Aynı türdeki dosyaları atmak için ise  git add *.php gibi komutlar kullanılabilir.

Ben şahsen çalıştığım dizin içerisinde git add . komutunu kullanarak bulunduğum tüm değişikleri tek bir defada  depolama alanına eklemeyi daha pratik buluyorum.

Şimdi değişikliklerimizi tamamladık fakat henüz işleme koymadık . Yaptığımız bu değişiklikleri işleme koymak için git commit komutunu kullanmalıyız.

Ben Unix tabanlı bir işletim sistemi olan Mac Os X  kullandığım için öntanımlı olarak bende vim editörü açılıyor.Windows üzerinde ne oluyor gerçekten bir fikrim yok deneyen arkadaşlar beni de bilgilendirirse yazımın bu kısmını ona göre düzeltebilirim :) 


 # işaretini koymadan yazacağımız satırlar ile bu değişiklik dosyasında yaptıklarımızı açıklayabiliriz. Ben vim editörde a tuşuna basarak  insert mode'a geçiyor ve index.php yaratildi diye not düştükten sonra esc tuşuna basarak vim'de  command mode'a dönüp wq! komutu  ile dosyamı kaydediyorum.



Şuan git status yazdığımızda commit edilecek hiç birşeyin olmadığını görüyoruz.





Bir Git projesinde dosyaların ve dizinlerin depolama alanına nasıl ekleneceğinden bahsettim .Git'in istenilmeyen dosyaları takip etmeme gibi bir özelliğinin olduğunu da belirttim . Peki onlarca dosyanın olduğu bir klasörü depolama alanına tek tek eklemek yerine dizin ekleme özelliğini kullandığımızı farzedelim.Fakat içerisindeki bazı dosyaları depolama alanına eklemek istemiyoruz. İşte tam olarak  böyle durumlarda .gitignore dosyası imdadımıza yetişiyor.

Yukarıdaki sebebin yanı sıra takip edilmesini istemediğimiz dosyalar ve dizinler oluşturduğumuzda git status komutunu verince git'in bu dosyaları takip etmediği belirtiliyor.Bu çıktılar birkaç dosya için önemsiz gibi görünse de onlarca dosyanın eklendiği bir projede bu tarz eklemeler gerçekten can sıkıcı bir hal alabiliyor.Hele ki dizin altında git add . gibi bir komut girdiyseniz işlemleri tersine çevirmek tam bir işkence olabiliyor!

Ignore işlemini yapabilmek için ana dizinimizde .gitignore adında bir dosya oluşturmamız ve daha sonra dizin ya da dosya farkı gözetmeksizin her satırda takip etmek istemediğimiz dosyaları belirtmemiz gerekiyor.
Ben takip etmek istemediğim ignoredosyasi.tmp adında bir dosya oluşturuyorum.git status yazdığımda oluşturduğum dosyanın takip edilmeyenler arasında olduğunu görüyorum.



Şimdi .gitignore dosyamızı oluşturalım.






Bu dosya içerisinde kullanabileceğimiz birkaç farklı yöntemden bahsetmek istiyorum. 

İlk satır ile images klasöründeki .jpg dosyalarını ignore ediyoruz.
İkinci satır birinci satırdakine benzer fakat bu sefer tüm proje içerisindeki .gif dosyalarını ignore ediyoruz.
Üçüncü satır dizin ya da dosya tipinin ignore edilmiş olmasına bakılmaksızın banner.jpg dosyasını her zaman takip edilmeyenler arasında göster anlamına geliyor.Diğer bir deyişle  bu dosyanın hiç bir şekilde ignore  edilmesine izin verme. 
Dördüncü satır ise ignoredosyasi.tmp adlı dosyayı ignore ediyor.

Hadi git status komutumuzu tekrar yazıp sonuçlara bir daha bakalım.



Evet takip edilmesi istenen tek dosyanın artık .gitignore olduğunu görebiliyoruz.İsterseniz bu dosyanın kendisini de listeye ekleyerek ignore edebilirsiniz.Şahsen bu işlemi ben  önermiyorum.


Peki dosyamızı oluşturduk ve commit ettik. Şimdi tekrar bu dosya ile çalışıyoruz birşeyleri değiştirdik ya da ekledik ama ne yaptığımızı eski haliyle kontrol etmek istiyoruz işte tam bu noktada git'in diff komutunu kullanacağız.Ben daha önceden bir index.php dosyası oluşturup içerisine de tek satır bir kod yazmıştım.


Şimdi bu kodumun altına bir satır daha ekliyorum.


git diff index.php yazdığımda +echo "gitdiffdeneme" çıktısını alıyorum. Başındaki bu + işareti bu satırın eklendiğini belirtiyor.Tahmin edeceğiniz üzere - de silindiğini belirtir.Fakat bu şekilde sadece dosyanın ilk hali ile yapılan değişikliklerden sonraki hali arasındaki farkları kontrol edebiliyoruz.

Şuan kullanımda olan yani commit edilmiş index.php ile kontrol etmek istediğimzide ise HEAD adında özel bir parametre girmemiz gerekiyor.
Yani komutumuz git diff HEAD index.php şeklinde olacak. HEAD parametresini daha sonra başka işlemler için de kullanacacağız.

Birden fazla değişiklik yaptığınız bir dosyanın daha eski bir versiyonu ile kıyas yapmamız gereken durumlar olabilir bunun için öncelikle eski versiyonun hash kodunu öğrenmemiz gerekiyor.

Git gayet detaylı bir günlükleme sistemine sahip şuan için sadece git log --oneline komutunu vererek eski versiyonlarımızı ve hash kodlarını  görelim.


Normalde çok daha güzel isimler seçmeye özen gösteririm fakat şuan birden fazla versiyonumuz olsun diye gayet saçma isimler seçtim siz lütfen bu hatayı yapmayın :p 

Mesela index.php'nin yaratıldığı versiyon ile kıyas yapalım. Satırın başındaki hash kodunu alıyorum ve git diff 6ef422d index.php yazıyorum. 


Benim ilk yarattığım dosya ile mevcut dosyam arasında 2 satır farkın olduğunu görebilirsiniz.


Peki değişiklik yaptığımız bir dosyayı eski haline nasıl getirebiliriz?

Dosyalarda yaptığımzı her değişikliği uygulamaya koymak için commit ediyor ve bir de not düşüyorduk.Bunu yapmamızın sebebi ilerki bir zamanda bu dosyaya geri dönme ihtiyacı duyabilmemizdi.

Bir dosya üzerinde değişiklik yaptık fakat commit etmediysek ;
Basit bir şekilde git checkout -- dosyaadi komutuyla bu dosyadaki değişiklikleri geri alabiliyoruz.

Fakat dosya eğer commit edilmişse işlem biraz daha karmaşık bir hal alıyor bunun yegane sebebi bir dosyanın birden fazla defa commit edilmiş olma ihtimali ve kullanıcının bir önceki sürüme değil de çok daha önceki bir sürüme gitmek istiyor olmasıdır.

Daha önceden commit edilmiş dosyaları bulabilmek için daha önceden aşina olduğumuz git log --oneline index.php komutunu veriyoruz.



Bu sayede index.php adlı dosya üzerinde yaptığım commit işlemlerinin geçmişini görebilirsiniz.Daha önce belirttiğim gibi her commit işleminde yapılan değişiklikleri düzgün bir şekilde açıklayan yorumlar yazarım ama şimdi sadece deneme olduğundan birkaç versiyon ismini öylesine girdim.

Mesela ilk versiyona dönmek için git checkout 6ef422d -- index.php komutunuz yazalım.Dosyamıza açtığımızda ilk versiyona döndüğümüzü görebilirsiniz.


Şuana kadar bir dosyayı depolama alanına eklemeyi , commit etmeyi ve eski versiyonu geri getirmeyi gördük.
Git'in faydaları bunlarla sınırlı değil.

Git bize mevcut  projeye dokunmadan bir kopyasını alarak  ve üzerinde değişiklik/test yapma gibi bir olanak da sağlıyor. Bu işleme branch adı veriliyor.

git status yazdığımızda çıktı ekranında  On branch master satırını görebiliyoruz.Bu satır master branch üzerinde çalıştığımız anlamına geliyor.

İşte tam olarak bu  master branch özelliği sebebiyle Git  bize basit bir şekilde proje dizinimizi  kopyalayıp bu kopyalanan dizinde çalışmamızdan daha pratik bir çalışma ortamı sağlıyor.
Şöyle düşünün git kullanarak oluşturduğunuz bir branch üzerinde yapılan her türlü değişiklik orda kalacak hiç bir şekilde master branch'inizi etkilemeyecek fakat master branch üzerinde yaptığınız bir değişikliği diğer tüm branchler altında da otomatik olarak değiştirebileceksiniz.
Bu sayede eski usül çalışıp dizinlerini kopyalayan yazılımcılar tek tek bu eklemeleri  yapmak durumunda kalırken biz bu işlemi birkaç saniyede halletmiş olacağız.

git branch ilkbranch komutuyla ilk branchimizi oluşturalım. ilkbranch yerine istediğiniz bir ismi girebilirsiniz.Daha sonrasında git branch yazarak mevcut branchleri görebiliriz.


Şuanda master branchi kullandığımızdan yanında * işaretini görüyoruz.git checkout ilkbranch komutunu vererek ilkbranch'e geçiş yapalım.Artık burada yapacağımız herhangi bir değişiklik master branch'imizi etkilemeyecek daha önce belirttiğim gibi master branch'te commit ettiğimiz değişiklikler ise burada otomatik olarak görünecektir. Bu arada aklımdayken git branch -D branchadi komutuyla oluşturduğunuz bir branchi silebilirsiniz.

Peki herşey güzel bir şekilde tamamlandı ve şuan yarattığımız branch'teki değişiklikleri master branch'e aktarmak istiyoruz. Git bize oluşturduğumuz bir branch'i master ile birleştirebilme imkanı da sunuyor.
git merge branchadi yazarak herhangi bir branch'i master ile birleştirebiliriz.

Bir branch'i merge etmeden önce yaptığınız değişiklikleri git add ve git merge ile belirttiğinizden ve git checkout master komutuyla master branch'e geçiş yaptığınızdan emin olun. Aksi halde  "Already up-to-date"  uyarısıyla karşılacaksınız.

Projemize devam ederken bir takım arkadaşıyla birlikte çalışmak ya da birilerinden yardım almak için projemizi paylaşmak istiyoruz. Elbetteki dizini sıkıştırıp email ile atmak da güzel bir çözüm ama git için özellikle tasarlanmış github , bitbucket gibi siteleri kullanarak bu işlemi çok daha pratik bir hale dönüştürebiliriz.
Bu sitelerin emailden daha pratik olmasının sebebi projeyi git üzerinden sadece 2 satır komutla atabilmemiz.

Ama bu sitelerin pratik olmasının asıl sebebi yarattığımız projedeki tüm branchleri , versiyonları , .gitignore dosyasını olduğu gibi başka birine ulaştırabilmek yani sizin şuana sisteminizde yaptığınız tüm değişiklikleri bu kullanıcıya görebilme imkanı sunabilmek.Kısacası şuanki çalışma ortamınızı olduğu gibi bir başka kişiye aktarabilmek.

Peki bu işlemi Github ile bu işlemi nasıl yapacağız?
Github'a üye olduktan sonra create a repository seçeneğini seçerek yeni bir repo yaratmaya başlayalım.




Repomuza bir isim ve açıklama girdikten sonra create repository butonuna tılayarak repomuzu yaratıyoruz.

Bu noktada değinmek istediğim bir konu var.
Ücretsiz github üyeliklerinde malesef gizli proje yaratamıyoruz.Yani yaratacağınız projeler herkese açık bir şekilde olacak.Bitbucket bize gizli proje yaratma imkanı sunuyor.
Ben daha popüler olması ve  uygulamalarımda kullanabileceğim başka geliştiriciler tarafından yazılmış olan kod parçacıklarını github'da daha rahat bulabildiğimden  github'u tercih ediyorum.


Eğer bu repoyu yeni bir proje için yarattıysak yukarıdaki 5 komutu komutları girmemizi istiyor.
Mevcut bir projeyi yüklemek için ise sadece 2 komut girmemiz gerekiyor.
İlk komut projenin yayınlanacağı yerin tanımlıyor ikinci komut ise bu dosyaları oraya yükle anlamına geliyor.

Aslına bakarsanız ikinci komutu sistemdeki projede yapılan değişiliklerin github'a yüklemesini istediğimiz her an kullanmak durumunda kalacağız.Bu işlemi bir bakıma uzak bir bağlantıya yapılan commit komutu gibi düşünebilirsiniz.

Bu komutları iki komutu ardına girdiğimizde github'a üye olurken seçtiğimiz kullanıcı adı ve şifre sorulacak bunları da yazınca projemiz otomatik olarak github'a yüklenecektir.
Push işlemini ssh denilen özel bir protokol ile de gerçekleştirebiliriz.Bu kadar detaya girip kafanızı karıştırmayı çok uygun görmüyorum.Merak eden arkadaşlar araştırabilirler.

Bu arada her bir commit işlemini tek tek github reponuza yüklemek gibi bir imkanımız da var ama ben bu işlemi de çok gereksiz buluyorum.



Evet yüklememizin gerçekleştiğini repo adresinize giderek görebiliriz.


Github'a yükleme yapabildiğimiz gibi github'dan da istenilen projeleri , kütüphaneleri bilgisayarımıza indirebiliriz.
Mesela örnek olarak şuan oluşturduğumuz proje içerisine web tasarımcılar tarafından çok sık kullanılan jquery kütüphanesini indirmek için
git clone https://github.com/jquery/jquery.git komutunu verelim.



Evet jquery kütüphanesinin projemize indirildiğini görebilirsiniz.
git status komutunu vererek untracked files kısmı altında jquery klasörümüzü de görebilirsiniz.

Github üzerinden yapılan push , clone ve daha bir sürü işlem için terminal ekranına alternatif olarak  Github for Mac , Github for Windows gibi uygulamalar da geliştirmiş .Bu uygulamaları  http://mac.github.com , http://windows.github.com adreslerinden inceleyebilir ve indirebilirsiniz.


Git tam bir unix tabanlı işletim sistemi gibi neredeyse herşeyin log'unu tutuyor ve bu logları istenilen şekillerde kullanıcılara sunma imkanı sağlıyor. Şu ana kadar sadece git log --oneline komutunu birkaç defa kullandık ama emin olun git log bundan çok daha fazlası...

Mesela
git log  --since="1 day ago" bir gün öncesinden itibaren olan logları ekrana yazdırabilirsiniz. (1 yerine istediğiniz gün sayısını ve day yerine week , month , year  ya da 2013-03-18 gibi spesifik bir yazarak özelleştirebilirsiniz)

git log --until="4 days ago" ile 4 gün öncesine kadar olan logları ekrana yazdırabilirsiniz..

git log  --since="1 day ago"  --until="4 days ago" şeklinde komutlarla spesifik bir süreyi seçip ekrana yazdırabilirsiniz.

git log --oneline ile ekrana yazdırdığınız versiyonlar arasında spesifik bir kısmı seçmek için

git log ilkhashkodu..ikincihashkodu komutunu verebilir çıktıları sadece isim ve commit mesajı olarak görmek için sonuna --oneline parametresini yazabilirsiniz.

Bu işlemi index.php dosyasına yapmak için git log ilkhashkodu..ikincihashkodu --oneline index.php gibi özel komutlar yazabilirsiniz.
Bu arada iki noktadan sonra ikinci bir hashkodu yazmazsanız son commit'e kadar olan günlükleri ekrana yazdırırsınız.

git log --grep="index.php" yazarak  commit mesajları içerisinde index.php geçenleri ekrana yazdırabilirsiniz.




Umarım bu yazımda git öğrenmek isteyen programcı arkadaşlara yardımcı olabilmişimdir

aklınıza takılan herhangi bir soru için rodrane@gmail.com adresine mail atmaktan çekinmeyin.

Hoşçakalın

Hiç yorum yok:

Yorum Gönder