Git Repository İşlemleri ve Komutlar

Git ve ardından öne çıkan git platformları ile git kullanım sürecine geçtik.

AA

Bu yazıda, öncelikle örnek iki durum üzerinden işlemler gerçekleştireceğiz. Ardından, örnek işlemlerde yer alan komutların detaylarına değinmeye çalışacağım. İlk örneğimiz bir projeyi nasıl git directory’e aktaracağımız üzerine olacak, bir diğer örnekte de git directory’deki (repository) bir projeyi bilgisayarımıza nasıl indirebileceğimize bakacağız.

Git Konfigürasyonu

Öncelikle, bu örnek işlemler ve komut uygulamaları için sistemimizde git‘in kurulu olduğunu varsayıyorum. Dolayısıyla, bir sonraki adımımız konfigürasyon düzenlemesi olacak. Öncelikle halihazırda bir tanımlama olup olmadığını kontrol edelim.

git config --list

Komutu uyguladığımızda eğer bir tanımlama yapılmamışsa boş bir geri dönüş alırız. O halde kullanıcı tanımımızı yapalım.

git config --global user.name "John Doe"
git config --global user.email johndoe@example.com

Şimdi git config --list kodunu uyguladığımızda user.name ve user.email tanımlarını alırız. Bu tanımlama ~/.gitconfig içerisinde yer almaktadır. cat ~/.gitconfig komutu ile dosya içeriğine göz atabilirsiniz.

Bir Git Yazılım Havuzu (Repository) Oluşturmak

Projemiz için newproject adında bir klasör oluşturarak başlayalım.

mkdir newproject
cd newproject

Proje içeriğimiz şu şekilde olabilir.

.
├── dist
│   ├── bundle.js
│   ├── css
│   ├── img
│   ├── js
│   └── view
├── package-lock.json
├── package.json
├── src
│   ├── css
│   ├── img
│   ├── index.js
│   ├── js
│   │   ├── bar.js
│   │   └── foo.js
│   └── layout
├── webpack.config.js
└── yarn.lock

10 directories, 8 files

Şimdi, klasörü git’e işlemek için git init kullanmamız gerekir. init boş bir Git repo’su oluşturur (initialize) veya mevcut olanı yeniden yapılandırır (reinitialize). Komutun uygulanmasının ardından gerekli yazılım havuzu dosyalarını içeren .git adında bir alt klasör oluşturulur.

git init

Ancak, bu aşamada projedeki hiçbir şey sürüm kontrolüne girmiş değildir. Detaylar için git-init1 kaynakçasına göz atabilirsiniz. Artık var olan dosyalarınızı sürüm kontrolüne alabiliriz. Bu işlem sürüm kontrolüne almak istediğimiz dosyaları belirleyip kayıt altına aldığınız birkaç git komutuyla gerçekleştirilebilir.

Tüm dosyaları işleme almak için git add . komutunu kullanabiliriz. Ancak, node_modules gibi bir klasörü işleme almak istemeyebiliriz. Neticede, repo’yu indiren bir kullanıcı yarn veya npm ile package.json içeriğini işleme alabilir. Bu durumda dosya isimlerini spesifik olarak işleme almamız veya .gitignore dosyası oluşturup işleme alınmasını istemediğimiz dosyaları tanımlamamız daha uygun olacaktır.

Adım adım bu konulara değinelim. İlk olarak src klasörünün içeriğini ve ardından webpack.config.js dosyasını ele alalım.

git add src/* webpack.config.js

Bu yöntemin, düzenleme yapılan temel bazı dosyaları işleme almak için oldukça pratik olsa da birden fazla dosya ve klasörle çalıştığımızda biraz can sıkıcı olabilmekte. Yukarıdaki komut yerine şu şekilde de bir yol izleyebiliriz.

git add -u
git reset -- src/index.js node_modules

Bu durumda özellikle belirttiğimiz dosya ve klasörler dışındaki tüm içeriğimiz index‘e eklenecektir.

.gitignore ise git add . gibi genel ifadelerde görmezden gelinmesini istediğimiz dosyaları tanımlamamızı sağlayan bir konfigürasyon dosyasıdır ve bizi tek tek işlemler yapma zorunluluğunda kurtarır. Örnek olarak, node_modules için bir .gitignore dosyası oluşturalım.

touch .gitignore
echo node_modules/ >> .gitignore

Bu işlemin ardından git add . komutunu kullandığımızda .gitignore içeriğine bakılır ve burada belirtilen dosya veya dizinler işlem dışında tutulur. github/gitignore altında oluşturulmuş pek çok .gitignore örneğini görüntüleyebilirsiniz.

Geldik bir sonraki adıma. Artık dosyalarımızı kayıt altına alabiliriz.

git commit

Bu komutu uyguladığımızda bir commit mesajının da iletilmesinin hoş olacağı uyarısını alırız.

git commit -m 'projenin ilk hali'

Elbette mesaj tanımı bir zorunluluk değil, ancak projenin geliştirilmesi sürecinde yapılan değişikliklere dair bir açıklama düşmek faydalı olacaktır.

git commit -a --allow-empty-message -m ''

Yukarıdaki komut ile commit işlemini mesaj tanımlamadan (boş mesaj ile) gerçekleştirebiliriz. Her defasında bu tanımı yapmak istemiyorsak, ilgili tanımı --global ile config‘e alias.nccommit olarak işleyebiliriz.

git config --global alias.nccommit 'm-message -commit -a --allow-empty ""'

İşlemlerimiz bu kadar!

Bir Yazılım Havuzunu (Repository) Klonlamak

Bir projemizi nasıl yazılım havuzu olarak kayıt edebileceğimizi öğrendiğimize göre, bir sonraki aşamada var olan bir repository’i -örneğin, projeye katkıda bulunmak amacıyla- nasıl edinebileceğimize (klonlamak) bakabiliriz. Bu amaçla kullanacağımız komut git clone. Diğer versiyon kontrol sistemlerine aşina iseniz checkout yerine neden clone kullanıldığını merak ediyor olabilirsiniz. Git SCM yazısında da belirttiğim üzere, Git sunucuda bulunan her dosyanın proje tarihçesinde bulunan her sürümü de dahil neredeyse tüm veriyi kopyalar. Bu nedenle clone komutu kullanılmaktadır. Hatta, bu sayede sunucuda bir sorun yaşanması durumunda (dosya silme, donanım hatası, erişim kısıtlaması vb.) klonlanan herhangi bir kayıt üzerinden sunucudaki zamana geri dönülebilir.

Git Clone Repository

git clone repo URL‘i birlikte kullanılır.

git clone [repository-url]

Örneğin, GitLab‘de barındırdığım webpack-test isimli repo’yu indirelim. Bu işlemi 3 şekilde gerçekleştirebiliriz.

# git
git clone git://gitlab.com/ceaksan/webpack-test.git
# https
git clone https://gitlab.com/ceaksan/webpack-test.git
# ssh
git clone git@gitlab.com:ceaksan/webpack-test.git

SSH bağlantısı için bağlantı gerçekleştireceğiniz sunucunun key’inizi tanıyor olması gerekmektedir. Diğer seçenekler için ekstra bir ayar ya da gereksinim söz konusu değildir.

Yukarıdaki komutlardan uygun olanın kullanılmasının ardından proje adıyla (webpack-test) bir klasör oluşturulur. Ardından, .git alt dizini oluşturulur. Repo’ya ait tüm verinin indirilmesinin ardından son sürümün bir kopyası seçilir (checkout) ve üzerine çalışılabilir olarak sunulur. İndirme işlemini elbette proje adıyla gerçekleştirmek zorunda değiliz. Farklı bir isimle (örneğin, newproject) projeyi yapılandırmak istersek şu komut işimizi görecektir.

git clone git://gitlab.com/ceaksan/webpack-test.git newproject

Artık üzerinde çalışılabilir dosyaları edindiğimize göre git show ile hızlı bir kontrol işlemi gerçekleştirebiliriz. Bu komut ile projeye / repoya dair tüm detayları görüntüleyebiliriz. Bu aşamada edindiğimiz tüm dosyalar izlenen (tracked) ve değişmemiş dosyalardır.

Değişikliklerin İşlenmesi

Bundan sonraki süreçte, dosyalar üzerinde çalışmaya başladığımızda unutmamamız gereken konu, klasörümüzdeki dosyaların iki halden birinde bulunacağıdır; izlenenler (tracked) ve izlenmeyenler (untracked).

İzlenen dosyalar, bir önceki bellek kopyasında bulunan dosyalardır. Bu dosyalar değişmemiş, değişmiş ya da hazırlanmış olabilirler. Bu dosyaların haricindeki her şey —çalışma klasörünüzde olup bir önceki bellek kopyasında ya da hazırlama alanında bulunmayanlar— izlenmeyen dosyalardır.

Git Dosya Aşamaları

Bir dosyaya müdahale ettiğimizde artık o dosya git için değişmiş olarak nitelendirilir. Bu aşamadan sonra, değişikliğe uğrayan dosyaları önce hazırlayıp sonra bütün hazırlanmış değişiklikleri kaydetmeliyiz. Bu süreç çalışma sürecinin tamamında döngüsel olarak tekrarlanır.

Dosyaların Durumlarının Kontrol Edilmesi

Hangi dosyanın hangi konumda bulunduğunu git status komutu ile görüntüleriz. Örnek olarak src/templates/index.html dosyasında bir işlem gerçekleştirdim ve git status komutunu çalıştırdım. Aldığım karşılık şu oldu:

On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

 modified:   src/templates/index.html

no changes added to commit (use "git add" and/or "git commit -a")

Eğer herhangi bir değişiklik söz konusu olmasaydı nothing to commit, working directory clean mesajı dönecekti.

Ek olarak, dizin içerisinde bir README dosyası olmadığını gördüm. O halde proje ile ilgili bazı detayların yer alacağı bir README dosyası oluşturalım ve ardından yine git status ile durum kontrolü gerçekleştirelim.

touch README
echo '# It is a New Project' >> README

Bu işlemin ardından git status bana şu dönüşü sağlar.

On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

 modified:   src/templates/index.html

Untracked files:
  (use "git add ..." to include in what will be committed)

 README

no changes added to commit (use "git add" and/or "git commit -a")

İletilen açıklamalardan da anlaşıldığı üzere src/templates/index.html modified, README ise untracked olarak nitelendirilmekte. O halde README dosyasını da git add README ile bir üst aşamaya geçirmem gerekiyor. Ardından, git status komutunu tekrar uyguladığımda README dosyası new file olarak nitelendirilecek ve izlenmeye başlanacaktır. README dosyasını açıp bir düzenleme yaptığınızda artık dosyanın modified olarak belirtildiğini görebilirsiniz.

Peki, dosyalardaki bu değişiklikleri görüntülemek istersek diff komutunu kullanabiliriz.

git diff

Komutun uygulanmasının ardından dosyalardaki değişiklikler bize ön tanımlı metin editörü üzerinden satır numaralarıyla birlikte sunulur. Unutmadan ekleyeyim, git diff bize son kayıttan beri yapılan bütün değişiklikler yerine sadece kayda hazırlanmamış değişiklikleri gösterir. Eğer sadece kayda hazırladığımız değişiklikleri görüntülemek istersek git diff --cached komutunu kullanmamız gerekir.

Artık yaptığımız değişikliklerin kayıt edilmesini (commit) sağlayabiliriz.

git commit -m "New comment"

Komutun uygulanmasının ardından, yaptığımız işlemleri özetleyen şu dönüşü alırız.

[master aa88c360] New comment
 1 file changed, 1 insertion(+)
 create mode 100644 README

Hazırlık alanını atlamak istersek git commit -a -m '' ile işlemimizi sürdürebiliriz.

Peki, bir dosyayı silmek / taşımak istediğimizde ne yapmalıyız? Bu gibi durumlarda rm (silme) ve mv (taşıma veya isim değiştirme) komutlarını kullanmamız işlemlerin daha kolay takip edilmesini sağlayacaktır. Doğrudan klasör içerisinde gerçekleştireceğimiz işlemler sonucunda sorun yaşamak istemiyorsak rm kullanımını bir alışkanlık haline getirmemiz uygun olacaktır. Örnek olarak README dosyasını silelim.

git rm README

Komutun uygulanmasının ardından, README dosyası bir sonraki kayıtta artık izlenmeyecektir. Ancak, bazı durumlarda dosyayı değiştirmiş ve çoktan indekse eklemiş olabiliyoruz. Bu gibi durumlarda ortadan kaldırma işlemini -f seçeneğini kullanarak zorlamamız gerekir. Diğer yandan, bir dosyayı çalışma klasörünüzde tutup, kayda hazırlık alanından silmek de isteyebiliriz. Bu durumda git rm --cached [dosya-adi] komutundan faydalanabiliriz. Taşıma işlemleri veya dosya ismi değişikliklerinde de benzer kurallar söz konusudur. Değişen tek şey rm yerine mv komutundan faydalanacak olmamızdır.

git mv README readme.txt

Komutun uygulanmasının ardınan readme.txt dosyası renamed olarak nitelendirilecektir.

mv komutu yerine şu şekilde de ilerleyebilirdik.

git rm README.txt
git add README

Tüm bu değişikliklerin ardından yine işlemleri commit ile kayıt altına almamız gerekir. Peki, ya gerçekleştirilen bir kaydı geri almak istersek? Bu gibi durumlarda (örneğin bir dosyayı kayda işlememişsek) --amend seçeneğini kullanırız.

git commit --amend

Bu komutu uyguladığımızda hazırlık alanındaki değişiklikler alınır ve kaydı değiştirmek için kullanılır.

Kayda alınmış bir dosyayı hazırlık alanından kaldırmak istediğimizde ise git reset komutunu kullanırız. Bu komutu yazının ilk bölümünde src/index.js ve node_modules gibi dosya ve klasörlerin kayıt altına alınmasını engellemek için kullanmıştık. Şimdide bu işlemi readme.txt için gerçekleştirelim.

git reset HEAD readme.txt

Son olarak, değişmiş bir durumdaki bir dosyayı değişmemiş duruma nasıl getirebileceğimize bakalım. Örneğin, bir dosyada çeşitli düzenlemeler yaptınız ve kayıt altına alacaksınız. git status ile durum kontrolü yaptığınızda işlem yaptığınız dosyanın haricinde de düzenlenmiş dosyaların beklediğini gördünüz. Ancak, yapılan değişikliklerden emin değilsiniz. diff ile değişiklikleri görüntülediniz ve değişikliklerin geri alınmasına karar verdiniz. Bu gibi durumlarda kullanacağımız komutumuz git checkout -- [dosya-adi] olacaktır.

git checkout -- readme.txt

Şimdi bir sonraki başlığımıza geçebiliriz. Bilgisayarımızda yeni oluşturduğumuz ve/veya klonladığımız bir projeyi nasıl uzak uçbirime (GitHub, GitLab vb.) ileteceğiz?

Uzaktaki Repository’lerle Çalışmak

Uzaktaki yazılım havuzları (repository), projenizin İnternet’te ya da başka bir ağda barındırılan sürümleridir. Bu projeler ya salt okunur ya da okunur/yazılır durumdadır. Ortak çalıştığımız okunur/yazılır durumdaki projelerde değişiklik yapabilir, veri çekip (pull) onlara veri itebiliriz (push). Yukarıdaki örnekte GitLab’de barındırdığım webpack-test çalışmasını kullanmıştık. Yine bu çalışma üzerinden devam edelim. Ön bilgi olarak, çalışmanın iki adet dalı (branch) var; master ve cea. Master ön tanımlı dalın adıdır ve değiştirilmediği / silinmediği sürece bu ad ile erişilebilir. Genellikle master branch üzerinden pek işlem gerçekleştirilmez ve yeni bir branch ile işlemler yürütülür.

O halde, ilk olarak indirdiğimiz webpack-test (eğer isim değiştirmediysek) çalışmasının hangi uzak sunucularla ilişkilendirildiğine bakalım.

git remote

Komutun uygulanmasının ardından origin dönüşünü alırız; origin bir uzak uçbirimin belirlenmiş kısa adıdır. -v seçeneği ile origin olarak ifade edilen uzak uçbirimin URL‘ini de görüntüleyebiliriz.

git remote -v

Bu durumda şu dönüşü alırız.

origin git@gitlab.com:ceaksan/webpack-test.git (fetch)
origin git@gitlab.com:ceaksan/webpack-test.git (push)

Elbette projede birden fazla uçbirim olabilir. Yani, farklı kullanıcılar proje üzerine çalışıyor olabilir. Bu durumda yukarıdaki dönüş diğer uçbirimleri de içerecektir. Ek olarak, bizde bu kullanıcıların herhangi birinden kolaylıkla çekme işlemi (pull) yapabiliriz.

Uzaktaki bir repositery’i git remote add [kisa-ad] [repositery-url] ile farklı bir isimle de ekleyebiliriz.

git remote add ceaksan https://gitlab.com/ceaksan/webpack-test.git

Bu durumda, git remote -v komutunu kullandığımızda şu dönüş alınır.

wt https://gitlab.com/ceaksan/webpack-test.git (fetch)
wt https://gitlab.com/ceaksan/webpack-test.git (push)
origin git@gitlab.com:ceaksan/webpack-test.git (fetch)
origin git@gitlab.com:ceaksan/webpack-test.git (push)

Fark ettiyseniz uçbirimler remote işleminde kullandığımız protokoller (https, ssl, git) ile listelenmekte.

Yukarıdaki isimlendirmenin ardından artık komutlarda belirttiğimiz ismi (örnekte wt) kullanmaya başlayabiliriz. O halde, git fetch wt ile yazılım havuzunda bulunan ancak bizde bulunmayan bütün bilgileri (yeni dal vb.) edinebiliriz.

From https://gitlab.com/ceaksan/webpack-test
 * [new branch]        cea        -> wt/cea
 * [new branch]        master     -> wt/master

Görüldüğü üzere yeni branch ve remote bağlantı bilgileri bize iletildi. Bu bilgiler ışığında, cea dalına wt/cea ile erişebileceğimi, bu dal ile birleştirme (merge) işlemi yapabileceğimi ve bu dallardan birini yeral dal olarak seçip içeriğine erişebileceğimi gördüm.

git fetch wt ile tüm bilgileri edinmenin yanı sıra, projede uzak repository’deki bütün dallara da referans oluşur. Bu sayede kolaylıkla proje içeriğini inceleyebilir ve/veya merge işlemi gerçekleştirebiliriz. Tekrar belirtmekte fayda var; fetch sadece bilgi getirir herhangi bir merge (birleştirme) işlemi gerçekleştirilmez. Bu işlem ayrıca uygulanır. Şayet, uzaktaki bir dalı izlemek üzere ayarladığımız bir dalımız varsa git pull ile tek seferde bu dalın ilişkili olduğu uzak daldan güncel veriyi edinebilir ve değişiklikleri mevcut dalımızla birleştirebiliriz.

Artık projemiz paylaşıma hazır. Paylaşma işlemi için yaptığımız değişiklikleri git push [uzak-sunucu-adi] [dal-adi] ile uzak uçbirime push etmeliyiz. Push işlemini farklı uçbirim adları üzerinden gerçekleştirebiliriz.

# origin için
git push origin master
# wt için
git push wt master

Klonlama (git clone) aşamasında genellikle isimlendirmeler ön tanımlı oldukları şekilde ele alınır. Belirli bir uzak uçbirim ile ilgili bilgi almak için git remote show [ucbirim-adi] komutunu kullanabiliriz.

git remote show wt

Yukarıdaki komutu uyguladığımızda şu dönüşü alırız.

* remote wt
  Fetch URL: https://gitlab.com/ceaksan/webpack-test.git
  Push  URL: https://gitlab.com/ceaksan/webpack-test.git
  HEAD branch: master
  Remote branches:
    cea    tracked
    master tracked
  Local ref configured for 'git push':
    master pushes to master (up to date)

Yeni bir proje olarak (uzak uçbirim’de henüz böyle bir proje yok ise) tanımlamak için:

git push -u https://[uzak-ucbirim]/[yeni-proje-adi].git master

Son olarak, bir uzak uç birimin adını git remote rename [ucbirim-adi] ile değiştirebilir, bir uçbirimi git remote remove [ucbirim-adi] veya git remote rm [ucbirim-adi] ile silebiliriz.

Son Olarak

Şimdilik git işlemleri ve bu işlemler içerisinde kullanacağımız komutlara dair anlatacaklarım bu kadar. Etiketleme, dallar ve komutlarla ilgili detaylara örnek durumlar üzerinden değinmenin daha doğru ve anlaşılır olacağını düşünüyorum. Ancak, öncesinde ilgili konulara dair detaylı anlatımlara ulaşmak isterseniz aşağıdaki ileri okumalar ve kaynakça bölümlerine göz atabilirsiniz.

İleri Okumalar

  1. Git 101
  2. Git Versiyon Kontrol Sistemi
  3. Git – Versiyon ve Sürüm Kontrol Sistemi
  4. Git Eğitimi
  5. git – basit rehber
  6. Git Komutları ve Kullanımı
  7. Git: Delete a branch (local or remote)
  8. Pro Git: Git’in Temelleri
  9. Start a new git repository
  10. Creating a Project