Yar Yaban Ellere `Git` miş.

Share Button

Bir sabah IT den sorumlu devlet bakanınız “ya allah” diyip GIT`e geçmeye karar vermiş ve siz hayatınızda böyle birşey duymamışsanız vah halinize. Commit mi edeyim push mu edeyim ne pull u noluyor lan derken iki satır kodu yayına alamaz sinirinizden klavyeyi yersiniz. Konuyla ilgili Türkçe kaynak kıtlığı olayın vehametini birkaç kat daha arttırır.

Bugün sizlerle GIT de yapabileceğiniz günlük işlerle ilgili olarak küçük ipuçları paylaşmaya çalışacağım.

GIT reposundaki bir projeye nasıl dahil olurum?

GIT , SVN den farklı olarak dağıtık bir yapıya sahipdir. Merkezi bir reponun olması zorunlu değildir. Üyeler değişiklikleri kendi aralarında paylaşabildikleri gibi merkez olarak belirlenen ortak bir makineye (Git jargonunda bu makineye origin deniliyor.) de gönderebilirler. Günümüzde bu işler için genelde GITHub ve BitBucket gibi servislerden yararlanılıyor. Özetle projeye dahil olmak yerine merkez reponun kopyasını bilgisayarınıza alıyorsunuz. Bu işlemi gerçekleştirmek için aşağıdaki komutu kullanabilirsiniz.

git clone <repo adı>

Örnek:

$ git clone git@github.com:ibrahimgunduz34/mytest.git

Sonuç:

Cloning into 'mytest'...
remote: Counting objects: 29, done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 29 (delta 3), reused 24 (delta 1)
Receiving objects: 100% (29/29), done.
Resolving deltas: 100% (3/3), done.

Hangi dosyaların değiştiğini nasıl anlayabilirim ?

SVN’de olduğu gibi GIT ‘de de status komutunu kullanarak değişen/eklenen dosyalarınızın listesini görebilirsiniz.
Örnek:

$ git status

Şayet herhangibir ekleme veya değişiklik yapmadıysanız aşağıdaki gibi bir sonuç görebilirsiniz:
Sonuç:

# On branch master
nothing to commit (working directory clean)

Şayet birşeyler değiştirdiyseniz veya eklediyseniz;
Sonuç:

# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   test1.php
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	NEW.txt
no changes added to commit (use "git add" and/or "git commit -a")

Yukarıda gördüğünüz üzere ilk örnekde herhangibir değişiklik yokken ikinci örnekde test1.php isimli dosyada değişiklik olduğunu, NEW.txt isimli dosyanın eklendiğini ve untracked (takip edilmeyen: buradan bu dosyanın henüz projeye dahil edilmediğini anlıyoruz.) durumda olduğunu anlıyoruz.

Yaptığım değişiklikleri merkez repoya nasıl gönderirim ?

GIT in SVN e göre majör farklarından biri de değişikliklerin merkez repoya gönderilmesi konusudur.

SVN`de değişiklikleri merkez repoya göndermek için commit etmeniz yeterlidir. Yalnızca yeni dosya eklediğiniz durumlarda add komutu ile dosyayı projeye dahil etmeniz ve sonrasında commit işlemini gerçekleştirmeniz gerekir.

GIT`de ise eklenen veya değişen her dosyanın bir sonraki commit ile gönderilebilmesi için görüntülerinin add komutu ile alınarak index ismli geçici bir alanda saklanması gerekmektedir. Aksi halde yapılan değişiklikler commit edilemez.

Kullanım:

git add <dosya1> <dosya2> <dosya-n>

Örnek:
Git add komutunu aşağıdaki gibi her dosya için tek tek çağıraiblirsiniz

$ git add test1.php
$ git add NEW.txt

veya dosya isimlerini peş peşe yazarak kullanabilirsiniz

$ git add test1.php NEW.txt

ya da (.) işaretini kullanarak eklenen ve değişen tüm dosyaların görüntüsünü index e alabilirsiniz.

$ git add .

Şimdi git status komutunu çalştırarak durumdaki değişikliği görelim.

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   NEW.txt
#	modified:   test1.php
#

Status komutunu anlatırken ikinci örneğin en altında gördüğünüz no changes added to commit (use “git add” and/or “git commit -a”) ibaresi, değişikliklerimizi index e eklediğimizden dolayı artık yok.Bu durum eklenen veya değişen tüm dosyaların başarıyla indeks e eklendiğini gösteriyor. Artık dosyalarımızı commit etmeye hazırız.
Örnek:

$ git commit -m "Filanca konuda değişiklik yaptım."

Sonuç:

[master 51655a4] Filanca konuda değişiklik yaptım.
 1 file changed, 1 insertion(+)
 create mode 100644 NEW.txt

Değişen veya eklenen tüm dosyaları commit komutuna -a parametresini vererek bir kerede hem indekse eklenip hem de repoya gönderilebilmesi mümkündür. Ancak kontrolünüz dışında repoya birşey gönderilmemesi açısından add komutu ile dosya listesi göndermek her zaman için daha doğru bir yaklaşımdır. Zira kimse .tmp .swp .bak uzantılı dosyalarla reposunu çöp haline getirmek istemez. :)

Bitti mi ? Bitmed… Yazının başnda hatırlayacak olursanız GIT tarafında her kullanıcının proje reposunun bir klonuna sahip olduğundan bahsetmiştik. Commit komutunu çalıştırdığınızda indekse aldığınız tüm değişiklikler işte bu yerel repo ya gönderilecektir. Yerel reponuzun origin e göre ne kadar eski veya yeni olduğunu görmek için status komutunu çalıştırmalısınız.

$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#
nothing to commit (working directory clean)

Gördüğünüz üzere az önce yerel repoya yaptığımız commit nedeniyle origindeki repodan 1 commit ilerideyiz. Diğer kullanıcıları bu değişiklikten mahrum etmemek ve origin i güncellemek için push komutunu kullanıyoruz.
Kullanım:

$ git push <repo adı veya url> <branch adı>

repo adı veya url: Bu parametre ile değişikliklerin gönderileceği repo tanımlanır. Boş bırakılması durumunda değişiklikler, projenin kopyalandığı kaynağa (origin) gönderilir.
branch adı: Değişikliklerin gerçekleştirildiği branch ın adıdır. Boş bırakılması durumunda varsayılan olarak master branch ı gönderilir.

Örnek:

git push origin

Sonuç:

Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 389 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)
To git@github.com:ibrahimgunduz34/mytest.git
   39b5963..109014a  master -> master

Merkez repodaki değişiklikleri nasıl alabilirim ?

SVN kullanırken merkezdeki değişiklikleri yerel e alabilmek için update komutunu kullanırken GIT tarafında bu işlemi gerçekleştirmek için pull komutunu kullanmamız gerekir.
Kullanım:

git pull <repo adı veya url> <branch adı>

repo adı veya url: Bu parametre ile değişikliklerin alınacağı repo tanımlanır. Boş bırakılması durumunda değişiklikler, projenin kopyalandığı kaynaktan (origin) alınır.
branch adı: Değişikliklerin alınacağı branch ın adıdır. Boş bırakılması durumunda origin repoda değişen tüm branchlar alınır.

Örnek:

$ git pull origin
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:ibrahimgunduz34/mytest
   d89fbf9..486cfa0  master     -> origin/master
Updating d89fbf9..486cfa0
Fast-forward
 NEW.txt |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

@berkerpeksag dan sonra gelen edit:
GIT in güzel özelliklerinden biri de pull ile kullanılan –rebase parametresidir (Bir de git rebase var ki tadından yenmez. Ayrıca söz edeceğim.) git pull –rebase, çalıştığınız branchda yaptığınız değişiklikleri originden alacağınız değişikliklerin üzerine uygular. Bu ne demek ? Örneğin bir patch çıkmayı planlıyorsunuzdur ancak siz bu işi yapana kadar yayına giren başka işler vardır. Doğal olarak sizin öncelikle güncellemeleri kendi lokalinize almanız gerekir. Peki ya sizin yaptığınız güncellemeler ne olacak ? :( Git pull –rebase origin de ilgili branch daki değişiklikleri aldıktan sonra sizin yaptığınız değişiklikleri aynen HEAD e uygulayacaktır. Tabi önce kendi yaptığınız değişiklikleri yerel reponuzdaki branch a commit etmiş olmanız gerekiyor.
Kullanım:

git pull --rebase <repo adı veya url> <branch adı>

Örnek:

git pull --rebase origin master

Teşekkürler Berker :)

Nasıl yeni bir branch oluştururum ?

Bunu SVN le karşılaştırmak bile istemiyorum. Zira SVN kullandığım günler aklıma geliyor da fena sövüyorum… Neyse… SVN de branch oluşturmak için copy ile referans branch ınızın bir kopyasını oluştururken GIT tarafında bulunduğunuz branch dan branch oluşturmak için branch komutu ile birlikte oluşturmak istediğiniz branch ın adını yazmanız yeterlidir. Branch komutu, branch adı belirtilmeden kullanıldığında reponuzdaki branchları listeler ve bulunduğunuz branch ı (*) işareti ile gösterir.

Kullanım:

git branch <branch adı>

Örnek:

$ git branch akbank_uyarlamasi

Nasıl branchlar arasında geçiş yapabilirim ?

SVN de bu işlemi gerçekleştirmek için switch komutu kullanılırken GIT tarafında checkout komutu kullanılır. GIT in güzel özelliklerinden birisinin de branchlar arasındaki geçiş hızı olduğunu söylemeden geçemeyeceğim. SVN kullanıcısıysanız, projenizdeki dosya sayısı hatırı sayılırsa ve geçiş yaptığınız branchlar arasında değişiklik sayısı birkaç committen fazlaysa o switch toprakta biterken GIT tarafında bu işlem komutu yazıp elinizi enter dan kaldırmanız ile sonlanır.
Kullanım:

git checkout <branch adı>

Örnek:

$ git checkout akbank_uyarlamasi

Checkout komutundan bahsetmişken küçük bir ipucu vermekte yarar var. Checkout komutu ile birlikte -b parametresini kullanarak aynı anda hem branch yaratıp hem de yarattığınız branch a geçiş yapabilirsiniz.
Örnek:

$ git checkout -b yeni_branch

Commit etmediğim bir değişikliği nasıl geri alabilirim ?

Yaptığınız bir değişikliği henüz commit etmemiş ve indeks e de almamışsanız checkout komutunu kullanarak dosyayı revert edebilirsiniz.
Örnek:

$ git checkout NEW.txt

Eğer dosyayı indekse eklediyseniz öncelikle reset sonra checkout komutlarını çalıştırmanız gerekiyor.

$ git reset NEW.txt
Unstaged changes after reset:
M	NEW.txt
$ git checkout NEW.txt

Commit ettiğim bir değişikliği nasıl geri alabilirim. ?

Commit ettiğiniz dosyayı daha önceki sürümlerden birine almak istiyorsanız dosyayı ilgili commite checkout etmeli ve tekrardan commit etmelisiniz.
Kullanım:

git checkout <geri dönülecek commit id> <dosya adı>
git commit -m <commit mesajı>

Örnek:

$ git checkout 3a6576743bea41635296e1721de89b5e1e6770ab NEW.txt
$ git commit -m "Filanca işe geri döndük."
[master 7ae70a1] Filanca işe geri döndük.
 1 file changed, 3 deletions(-)

Belirli bir sürüme komple dönmeyi planlıyorsanız:

git reset <geri donulecek commit_id>

Örnek:

git reset 3a6576743bea41635296e1721de89b5e1e6770ab

Bu işlemi gerçekleştirdikten sonra dosyalarınız indexlenmemiş belirtilen commit id deki durumlarına geri dönecektir. Gerçekleşen değişikliği (geri dönüşden kaynaklanan değişiklik) indekse ekleyerek commit etmeniz gerekmektedir.

git reset 3a6576743bea41635296e1721de89b5e1e6770ab
git add .
git commit -m "Filanca sürüme geri dönüldü."
git push origin

Tabi bu işin legal yolu. Dilerseniz reset –hard <commitid> yapabilirsiniz. Böylece hem belirttiğiniz commit id li işe geri döner hem de bu commit id den sonraki işlerin logdan silinmesini sağlarsınız. Ancak bu işlemi gerçekleştirdiğinizde GIT, push ile normal yoldan reponuzu merkeze senkronlamanıza izin vermeyeceğinden push –force kullanmanız gerekecektir. Kalabalık bir ekiple çalışıyorsanız bu yöntem başkalarının yaptığı değişiklikleri ezmenize neden olacağından gerekmedikçe kullanmamanızı öneriririm.

Sürüm geçmişi günlüğüne nasıl ulaşırım ?

Geçmiş günlüğüne SVN de olduğu gibi log komutu ile ulaşabilirsiniz.

$ git log

Son 5 commit i görüntülemek için:

$ git log -5

Bir branch da yaptığım değişiklikleri başka bir branch ile nasıl birleştirebilirim ?

GIT’de bir branch içinde yaptığımız güncellemeleri başka bir branch ile birleştirmek için merge komutu kullanılır. merge komutu bulunduğunuz branch ile merge komutuna parametre olarak gönderdiğiniz branch yada branchlarda varolan değişiklikleri birleştirir.

Örneğin yeni_branch branchındaki değişiklikleri master isimli branch`da birleştirmek istiyorsak

//master branch ına geçiyoruz.
$ git checkout master
Switched to branch 'master'

//yeni_branch isimli branchdaki değişiklikleri master ile birleştiriyoruz.
$ git merge yeni_branch
Updating 3a65767..2e8dfa8
Fast-forward
 NEW.txt |    1 +
 1 file changed, 1 insertion(+)

GIT, branchlardaki değişiklikleri birleştirmek için bize cherry-pick isimli farklı bir alternatif daha sunuyor. Cherry-pick, bir branchdaki commitleri başka bir branch a kopyalayabilmemizi sağlar. Böylelikle sürüm hazırlarken yayına almak istediğimiz işle ilişkisi olmayan commitlerin sürüme girmesinin önüne geçmiş oluyoruz.
Kullanım:

git cherry-pick <commit id>

Örneğin master da İlk Commit. ve İkinci Commit olarak iki tane commit imiz olsun ve yeni_is diye isimli bir branchımız ve bu branchda da Üçüncü commit, Dördüncü commit ve Beşinci commit isimli commitlerimiz olsun. Yeni bir sürüm çıkacağımızı ve bu sürüme yalnızca Üçüncü commit ve Beşinci commit commitlerinin gireceğini varsayalım.

Mevcut Durum:

$ git log master
commit 3a6576743bea41635296e1721de89b5e1e6770ab
Author: İbrahim Gündüz <ibrahimgunduz34@gmail.com>
Date:   Sat Nov 3 23:40:15 2012 +0200

    İkinci commit.

commit dd879a82049e3f80d8ea07b150b3b29e45f3bb37
Author: İbrahim Gündüz <ibrahimgunduz34@gmail.com>
Date:   Sat Nov 3 23:21:59 2012 +0200

    İlk commit.

$ git log yeni_branch
commit b6d44d862c6f8b93f0468218eaf060fd1ce95989
Author: İbrahim Gündüz <ibrahimgunduz34@gmail.com>
Date:   Sun Nov 4 00:00:04 2012 +0200

    Beşinci commit.

commit 5e79f8c1b28d5a52bb658efbc59b854746880b11
Author: İbrahim Gündüz <ibrahimgunduz34@gmail.com>
Date:   Sat Nov 3 23:59:54 2012 +0200

    Dördüncü commit.

commit 2e8dfa800eb9941c3853946ed8359091f3da3f0f
Author: İbrahim Gündüz <ibrahimgunduz34@gmail.com>
Date:   Sat Nov 3 23:40:48 2012 +0200

    Üçüncü commit.

commit 3a6576743bea41635296e1721de89b5e1e6770ab
Author: İbrahim Gündüz <ibrahimgunduz34@gmail.com>
Date:   Sat Nov 3 23:40:15 2012 +0200

    İkinci commit.

commit dd879a82049e3f80d8ea07b150b3b29e45f3bb37
Author: İbrahim Gündüz <ibrahimgunduz34@gmail.com>
Date:   Sat Nov 3 23:21:59 2012 +0200

    İlk commit.

3. ve 5. commit leri master a alalım.

$ git checkout master
Switched to branch 'master'

$ git cherry-pick 2e8dfa800eb9941c3853946ed8359091f3da3f0f b6d44d862c6f8b93f0468218eaf060fd1ce95989

[master e2b3fa3] Üçüncü commit.
 1 file changed, 1 insertion(+)
error: could not apply b6d44d8... Beşinci commit.
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

Oh.. Yea… Bir taşla iki kuş. cherry-pick anlatalım derken conflict olduk. Hadi hayırlısı. Gelin şimdi conflict i resolve edelim.

Öncelikle hangi dosya veya dosyaların conflict olduğunu öğrenelim.

$ git status
# On branch master
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#	both modified:      NEW.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

Bakalım dosyaya ne olmuş.

ASDF
QWER
<<<<<<< HEAD
=======
qwer
QWER
>>>>>>> b6d44d8... Beşinci commit.                                      

Conflict in oluştuğu bölgede master ın HEAD inde birşey yokken Beşinci coommit commitinde yeni 2 satır eklenmiş. Kabuülümüzdür diyoruz ve dosyayı aşağıdaki şekilde güncelleyip kaydediyoruz.

ASDF
QWER
qwer
QWER

ve… değişen dosyamızın görüntüsünü indekse alıp yola devam ediyoruz.

$ git add NEW.txt
$ git cherry-pick --continue
[master f238560] Beşinci commit.
 1 file changed, 2 insertions(+)

Aklıma geldikçe paylaşmaya devam edeceğim. Kısa vadede günü kurtarmanızı sağlayacağını umuyorum.

Share Button

About İbrahim Gündüz

1983 yılında İstanbul’da doğdu. İlkokul yıllarında cobol ve basic le olan tanışması, yazılıma olan ilgisini arttırdı 2005 yılında. Uludağ Üniversitesi Teknik Bilimler Meslek Yüksek Okulu Elektronik bölümünden mezun olan Gündüz, çeşitli alanlarda faaliyet gösteren kurumlarda yazılım geliştirici olarak görev almıştır. Mesleki ilgi alanları, ölçeklenebilir sistemler, uygulama entegrasyonları ve ödeme sistemleridir. Halen Markafoni back end geliştirici olarak çalışmaktadır.

7 Comments

  • Kasım 3, 2012 - 11:39 pm | Permalink

    Eline sağlık İbo dayı. İki tane önerim var:

    1) `git clone`’u açıklarken git@github.com:ibrahimgunduz34/mytest.git ve git://github.com/ibrahimgunduz34/mytest.git farkından bahsetsen güzel olur.
    2) `git pull`’da da hangi durumlarda –rebase ile kullanmak gerektiğini eklenebilir.

    Son olarak, master’a “forced push” yapmayalım, yapanları teşhir edip dövelim.

  • Kasım 4, 2012 - 12:11 am | Permalink

    Clone konusuyla ilgili git, http, https, ftp, ssh ve rsync protokollerini destekliyormuş. Bunu ben de yeni öğrendim, akabinde de bir kere daha hayran kaldım:)
    protokol://host:port/repo.git şeklinde bir syntax ile kullanılabiliyormuş. Fakat github ve benzeri servislerde bu olay bir şekilde rewrite edilmiş. port yerine username geliyor. Biraz okudum ama orası kafamda çok oturmadı, o konuda bir açıkcası bir yorumum yok. :)

    Aslında rebase komutundan ayrıca bahsetmiştim ama hep SVN le kıyaslayarak gidiyorum, kafa karışıklığına neden olmasın diye kaldırdım. Ama pull –rebase olarak anlatılabilir. Hemen güncelleyeceğim.

    Çoook teşekkür ederim Berker. Ayrıca kahrolsun master a force push yapanlar.

    • Eylül 9, 2013 - 8:15 am | Permalink

      Port ile kullanıcı adı nasıl değişmiş kısmına ufak bi açıklama yapayım. Eğer port değiştirilmemişse host:user olarak alıyor, fakatki port değişirse host:port/user/repo.git tarzı oluyor. Yani orada aslında port yoksa default[protokol portu: 22/80/21] alıyor. Bi rewrite olayı mevcut değil.

      Yazı yeterince detaylı olmuş. Yeni geçiş yapanlar için aydınlatıcı.

      Saygılar.

  • Eylül 3, 2013 - 4:14 pm | Permalink

    Bir TFS kullanıcı olarak hızlı bir GIT dersi oldu benim için. Farkları anlamamda çok faydası oldu. Eline sağlık. Çok teşekkürler.

  • Pingback: Git Versiyon Kontrol Sistemi, Getirdiği Yenilikler, Avantajları ve Dezatanvajları |

  • Nisan 3, 2014 - 3:22 am | Permalink

    Benden de ufacık bir katkı olsun, aylardır kullandığım bir komut var, git log’u okunabilir kılıyor.

    git config –global alias.lg “log –color –graph –pretty=format:’%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)%Creset’ –abbrev-commit”

    bunu bir kere çalıştırdıktan sonra terminal’de “git lg” yazarak ibretlik, hatta ibreti geçtim, çoğoş bir görüntü elde edilebiliyor. Bir de JetBrain ürünlerinde (PyCharm, PhpStorm, IntellijIDEA…) Git entegrasyonu efsanevi. Yalanım yok, bir de hunk’lara ayırma olsa başka birşey istemem…

  • Nisan 3, 2014 - 7:56 am | Permalink

    En son 1 sene önce güncellediğim mini proje: http://vigo.github.io/git-tips/

    Türkçe git ipuçları

  • Bir Cevap Yazın

    E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir