Bu yazıda işe yeni başlayan, bir takımla ilk defa çalışanlar için Git komutlarını bir developer gözünden, örneklendirerek anlatmaya çalışacağım.
Git bilmiyorsanız ve bir takım ile ilk kez çalışmaya başlamışsanız, hele küçük ölçekli bir takım ise “kodluyoruz işte, ne olur şu git’le uğraşmasak?” diye düşünebilirsiniz. Eğer böyle bir durumda iseniz ve farklı git komutları arasında hangisi ne işe yarıyor diye düşünüyorsanız, bu yazıda bazı temel git komutlarını açıklamaya çalışacağım.
Umuyorum ki bu yazıyı okuduktan sonra git ile ilgili çok daha iyi bir yoruma sahip olacaksınız. Hemen başlayalım.
Git nedir?
Git, bir “version control” (ya da “source control”) yönetim aracıdır.
Git kullanmaya nasıl başlanır?
Bunun birden fazla yolu vardır. Bir sonraki yazımızda bu farklı senaryolardan bahsediyor olacağız. Bu yazıda basit git komutları üzerine konuşuyor ve şimdilik, bir takıma sonradan dahil olduğumuzu, birinin bize “git’ten kodları çek” dediğini varsayıyor olacağız.
Lügatçe
Repository (kısaca “repo”): git ile takip edilen bir codebase anlamına gelir.
Remote: git kullanmanın bir amacı da, kodları herkesin 7/24 ulaşabileceği bir yerde tutmaktır. Bu hizmeti sağlayan markaları duymuşsunuzdur: GitLab, Github, Bitbucket ve dahası. Remote, kaynak kodlarımızın bulunduğu bu sunuculara denir. “Remote repo” da denir.
Buradan anlaşılacağı üzere, git ile Github aynı şey değillerdir.
Local: Kodlarımızı yazdığınız ortam; remote ile uzaktan iletişim kurduğumuz, genelde iş bilgisayarımızdır. “Local repo” da denir.
Commit: Commit mekanizmasını elimizdeki bir fotoğraf makinesi gibi düşünebiliriz.
Bir iş yapıyoruz ve yarın, çalışmamızın bugünkü halini hatırlamak, gerekirse karşılaştırmak isteyebiliriz. Elimizdeki fotoğraf makinesi ile bugün çalışmamızın fotoğrafını çekip, notlar alıp ve bir yığın olarak derleyip, ilerleyen bir zamanda buna dönerek önceki çalışmalarımıza müracaat edebiliriz.
Git’teki commit mekanizması da aynen bu işi yapmaktadır. En temel mekanizmalardan biridir. Yazının geri kalanında bu fotoğraf çekme örneğine değiniyor olacağız.
Not: Ben, çalışma ortamı olarak Linux tabanlı bir işletim sistemi kullanıyor olacağım. Kullandığım shell bash, editör ise Vim editör olacaktır. Sizlerin de bunlara aşina olduğunuzu varsayıyor olacağım.
Temel git komutları
git init
Boş bir git projesi başlatmak için kullanılır. Bunu genelde projeyi başlatacak kişi isek kullanıyor oluruz; ancak diğer senaryolarda da kullanmak için bir engel yoktur.
Bu komutu çalıştırdıktan sonra çalıştırdığımız dizinde “.git” adında bir directory oluşur. Başında nokta olduğu için bu gizli klasör olur; görmememiz mümkündür.
git clone
Bir remote’tan kaynak kodlarını local’imize indirmemizi sağlar. Github arayüzündeki “download as .zip” yerine tercih etmemiz gereken yöntemdir.
Bu kodu çalıştırdığımız zaman, çalıştırdığımız dizinde remote’un path’ine sahip bir dizin oluşur. Örneğin, klonlamaya çalıştığımız projenin adı MyApp ve path’i github.com/username/my-app ise, bulunduğumuz dizinde my-app adında bir klasör oluşacaktır ve kodlar onun içindedir. Yani klon yaptıktan sonra dizin değiştirmemiz gerekir. my-app dizinine girdikten sonra çalışmaya burada devam edebiliriz.
git status
Muhtemelen en sık başvurmamız gereken komuttur. Ne yaptığımızı biliyor dahi olsak git status
komutunu çalıştırıp çıktıyı okumamız faydalı olabilir.
Burada çıktıyı okumayı vurguladım. Çünkü git komutlarının çıktıları belki de gördüğüm en yol gösterici çıktılardır. Komutları sadece ezbere çalıştırmayıp, çıktıları okumaya zaman ayırmamız kısa zamanda ne yaptığımızı daha çok anlamanıza yardımcı olacaktır.
Bir repo’yu klonlayıp bu komutu ilk çalıştırdığımızda muhtemelen aşağıdaki gibi bir çıktı görüyor olacağız:
On branch main
Your branch is up to date with ‘origin/main’.nothing to commit, working tree clean
Kısaca meali: “main adlı branch’tesin. Ve bu branch, origin adlı remote’taki main branch’i ile aynı noktada.”
“Commit edilecek bir şey yok, çalışma dizini (working tree ya da working directory) temiz durumda.”
Önümüze bir anda farklı terimler çıktı. Ama bu yüzden çıktıyı görmezden gelmemeliyiz. Kısaca açıklayalım:
“On branch main”: Git’te “branching” mevzusu bu yazı için uzun gelebilir, onu farklı bir yazıya saklayıp burada sadece adını kullanıyor olacağım.
Git kullanılan bir repo oluşturulduğu zaman, ilk branch otomatik olarak main adını alır. Bu mesaj, şu anda main branch’inde olduğumuzu söylemektedir ve genelde bir repo’yu klonladığımız zaman karşılaşacağınız branch ismidir.
Not: 2020 yazına kadar yeni oluşturulan repo’larda ilk branch otomatik olarak masteradını alırdı. Ancak bu isim main olarak değiştirildi. Daha fazla bilgi için bakınız.
“Your branch is up to date with ‘origin/main’.”: Bir proje, birden fazla remote’la ilişkilendirilebilir. Bu yüzden remote’lara bir isim verilir. Branch konusunda pratikte ilk branch’in main (ya da master) olarak adlandırılması gibi, remote’larda da ana remote genelde “origin”olarak adlandırılır. Buradaki mesaj, localimizdeki main branch’i ile origin’deki main branchinin tamamen aynı commit history’sine sahip olduğunu belirtiyor. “Commit history” kavramına birazdan değiniyor olacağız.
“nothing to commit, working tree clean”: Bu mesaj, çalışma dizininizde commit etmeye dair hiçbir şey bulunmadığını, projedeki dosyaların, commit edilmiş hali ile tamamen aynı olduğunu belirtir.
Yani fotoğraf çekme örneğine dönersek, dün çalışmanızın fotoğrafını çekip kaydettiyseniz (commit ettiyseniz) ve sonra en ufak bir değişiklik dahi yapmadıysanız (“working tree clean”), fotoğrafı çekilecek bir değişiklik yok (“nothing to commit”) demektir.
git diff
Projeyi klonladık, inceledik. Sıra geldi bir şeyler katmaya. Kodlarımızı yazdık, test ettik. Bu değişikliklerin hayata geçmesini istiyoruz.
Kodlarımızı yazdıktan sonra bir göz gezdirmekten zarar gelmez. Git de bunun için var. git diff
komutunu çalıştırdığımız zaman commit edilen andaki kodlar ile local’inizde yaptığınız değişikliklerin “farkı” gösterilir:
diff --git a/README.md b/README.md
index f184856..a6b7f1c 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,4 @@
Git üzerine bir yazı.
+
+Bu satır son commit'te yoktu!
+
Burada hangi dosya ve hangi commitler arası farka baktığımızı, hangi satırlar arasında olduğumuzu ve hangi satırların eklenip silindiğini görebiliriz. Kullandığımız ortama göre değişebilir olsa da alt-üst satırlara j ve k tuşlarını kullanarak inip çıkabiliriz. Kapatmak için de q tuşuna basabiliriz.
Fotoğraf örneğine dönecek olursak, dün çalışmamızın fotoğrafını çekip, bir zarfa koyup, etiketleyip, bir zarf yığınının üzerine koymuştuk (commit). Bugün çalışmamızda bir şeyler değiştirdik ve son çektiğimiz fotoğraftaki hali ile karşılaştırmak istiyoruz. git diff
komutu bu fonksiyonelliği sağlıyor.
git add
Bu komut, genellikle bir commit yapmadan önce kullanacağımız bir komuttur. Kullanımı git add <dosya_adı>
şeklindedir. Burada bir değil birden fazla dosya adını ard arda yazabiliriz. Bu şekilde git’e “bu dosyaların şimdiki hallerini, sıradaki commitimde kullanacağım” demiş oluyoruz. Git de belirttiğiniz dosyaların mevcut hallerini “index”e ekliyor. Bundan sıradaki yazımızda bahsediyor olacağız.
Önemli bir nokta: bu komutu çalıştırdıktan sonra örneğin README.md dosyasında yeniden bir değişiklik yaparsak ve bu değişikliğin sıradaki commit’te yer almasını istersek, add
komutunu yeniden çalıştırmalıyız.
Fotoğraf örneğine bakacak olursak şunu diyebiliriz: git add
komutu ile çalışmamızın fotoğrafını çekiyoruz, ancak henüz buna bir etiket verip diğer fotoğrafların yanına eklememiş oluyoruz (commit etmiyoruz). Fotoğraf henüz askıda duruyor.
git commit
Şimdi geldik en civcivli bölüme. (G.O.R.A. — 2004)
Aslında belki de en basit git komutlarından biridir, çünkü asıl cefayı zaten bu aşamaya gelene kadar çekmişizdir.
Oldukça basit, amacı net bir işlemdir: git add
komutu ile bir sonraki commitimizde kullanacağımızı vaadettiğiniz değişiklikleri paketleyip anlamlandırmamızı sağlar. Kullanımı: git commit
şeklindedir.
Burada yeni başlayanlar için önemli bir nokta, bu kod direkt çalıştırıldığı zaman, çalıştığınız ortama bağlı olarak bir “text editor” açılır ve bir commit mesajı girmeniz istenir. Bu editör çalışılan ortama göre değişebilir. Ben şahsen Linux ortamında çalışıyorum ve bu iş için Vim editörünü kullanıyorum. Kullanılan text editörün nasıl değiştirileceğine buradan bakabilirsiniz.
Eğer bir editör açılmadan commit mesajını girmek istersek komutu bu şekilde kullanabiliriz: git commit -m “Commit mesajı”
.
Fotoğraf örneğine dönecek olursak, çalışmamızın fotoğrafını git add
komutu ile çekmiştik. git commit
komutunu kullanarak buna bir etiket vermiş, bir zarfa koymuş ve önceden çektiğimiz fotoğrafların bulunduğu zarf yığınının (“commit history”) en üstüne koymuş oluyoruz.
git push
Bu komut kullanılarak yaptığımız commitleri bir remote’a “pushlayabiliriz”. Kullanımı git push <remote_adı> <branch_adı>
şeklindedir. Son örneğimizden devam edecek olursak git push origin main
diyebiliriz.
remote_adı, hangi remote’a pushlayacağımızı belirtir. Tek remote’umuz varsa adı genelde “origin” olur. branch_adı ise hangi branch’e pushlayacağımızı belirtir. Bu, genelde local’imizde olan branch adı ile aynı olur.
Fotoğraf çalışmasına dönecek olursak bu komut, oluşturduğumuz yeni zarfların birer kopyalarını iş arkadaşlarımızın da erişiminin bulunduğu bir yere postalamak olarak düşünebiliriz. Eğer her şey yolunda giderse, örneğin önceki zarflar (commit history) da aynı ise bu işlem sorunsuz bir şekilde gerçekleşir ve iş arkadaşlarımız, çalışmanızın bir kopyasını (yeni gelen zarfları) kendilerine alabilirler.
git pull
Çalışma arkadaşımızın git push
yaptığını düşünürsek, onun çalışmalarını kendi localimize almak istediğimizde git pull
komutunu kullanırız. Direkt kullanılırsa, o an içinde bulunduğumuz branch’in remote’ta ilişkili olduğu branch’teki yeni komutları, localimize ekler ve merge eder. Bu konuya sıradaki yazıda değiniyor olacağız.
Önemli bir nokta: eğer biz localimizde ve çalışma arkadaşımız remote’ta bir dosyanın aynı satırlarını değiştirdiysek, git pull
komutu çalışmayacaktır. Çünkü git, yaptığımız çalışmaları kaybetmemizi istemez. Bu durumda üç seçeneğimiz olur. Bunlara sıradaki yazımızda değiniyor olacağız.
git fetch
Bu komut, localimizin, remote’ta yapılan herhangi bir güncellemeden “haberdar olmasını” sağlar. git pull
‘a çok benzer, ancak yeni bir commit varsa dahi working directory’deki kodlarımızı güncellemez (merge yapmaz).
Fotoğraf örneğinde, arkadaşlarımız, kullanılan ortak alana (remote) yeni zarflar (commitler) gönderdiğinde (push) bizim bundan otomatik olarak haberimiz olmaz. Bu yüzden merkezi arayıp “yeni zarf geldi mi?” diye sormamız gerekir. git fetch
komutu bu işi yapmaktadır.
Not: git pull
, git fetch
ve git merge
komutlarının ard arda kullanılması ile aynı işi yapar.
Sırada ne var?
Bu yazıda en temel git komutlarının basit kullanımlarını görüp “fotoğraf çekme” senaryosu ile betimlemeye çalıştım.
Bir sonraki yazımızda bu komutları kullanarak ve biraz da konfigüre ederek bazı gerçek hayat senaryolarını taklit etmeye çalışacağız. Ayrıca bazı best-practice’lere değiniyor olacağız.
Kullanacağımız yeni komutlardan bazıları branch
, checkout
, stash
ve merge
komutları olacaktır.
Naçizane tavsiyelerim
- Yazımın başında da belirttiğim üzere, git komutlarının çıktılarını tamamen okumak ve merak ettiğimiz yerleri Google’lamak çok büyük fayda sağlayacaktır.
- Bu yazıda komutların en saf hallerini kullandık. Ancak git komutları çok farklı parametreler ve “flaglerle” kullanılabilir. Bu yüzden merak ettiğimiz bir şey varsa bunu Google’lamaktan çekinmemeliyiz. Örneğin
git diff
komutu direkt çalıştırıldığında tüm dosyaların farkı görünür. Ancak sadece bir dosyanın farkına bakmayı istemek çok olası bir durumdur, bu yüzden muhtemelen daha önce birilerinin aklına gelmiştir. Bu yüzden kısa bir Google sorgusu çok işe yarayabilir.