Git Başlangıç ve Orta Seviye

1. Başlangıç Seviye

Bu kısımda versiyon yönetiminin tarihçesine giriş yapılacak. Devamında Git versiyon yönetim aracı özelinde temel kullanım bilgileri verilecektir.

1.1 Versiyon Yönetimi

Geliştirmenin olduğu yerde versiyonlamaya ihtiyaç vardır. Her yeni gelişmede eski hallerinin tutulduğu bir yapı olmalıdır. Çünkü gelişim beraberinde sorunları da getirebilir. Her gelişim tek yönlü olmayabilir. Geçmişteki sorunsuz kısımların şimdiki haliyle kıyaslamak gerekebilir.

Versiyonlama ihtiyacının temelinde geçmişi kaybetmemek vardır. Versiyonlama ihtiyacı sadece yazılım için değil dijital olan herşey için geçerlidir. Örneğin bir mimar çizimlerini versiyonlamak ister.

Versiyonlamaya tekil çalışmanın yanında çok kişili çalışılan projelerde daha da fazla ihtiyaç duyulmaktadır. Ama sadece çok kişili çalışma için değil tek başına çalışılan projelerde de kullanılması gerekir. Projenin tarihçesini; kimin hangi işlemi yaptığını, hangi noktalara dokunduğunu, ne zaman yaptığını görmek istenir. Eğer bir problem varsa kimin ne zaman yaptığı veya sorunsuz halinin ne olduğu ile ilgili bilgiler kolaylıkla görülebilir.

Versiyonlama ihtiyacı geliştiriciler tarafından kabul görmüş ve çözüm arayışına çıkılmıştır. Versiyonlama önemlidir fakat nasıl yönetilmelidir? Örneğin farklı isimlerde dosyalamak da versiyonlama örneğidir. Ama bu yöntem versiyon yönetimini oldukça zorlaştırır. Versiyonlama için öncelikle uygun bir versiyon yönetim mimarisi geliştirilmelidir. Bu kapsamda geliştiriciler 3 farklı versiyon yönetim sistemi üzerinde çalışmışlardır.

1.1.1 Yerel Versiyon Yönetim Sistemleri (YVYS)

Bu yöntemde hedeflenen değişiklikleri küçük parçalar halinde takip edebilmektir. Küçük parçalara ayrılmış değişiklik geçmişini kolaylıkla takip edilebilir diye düşünülmüştür. Bu kapsamda değişiklik parçaları veritabanında tutulmuştur. Veritabanından okunarak takibi sağlanmıştır.

Yerel Versiyon Yönetim Sistemi

Bu yöntemin kullanıldığı versiyon yönetim aracına örnek olarak RCS verilebilir. Bu araç dosyadaki değişiklik yapılan parçaları kendine has formatta kaydeder. Daha sonra istenen zamandaki versiyon için o zamana kadarki tüm parçaları birleştirerek gösterir. Bu araçta çalışma performansnı yükseltmek için son versiyona ait parçaların birleştirilmiş hali hazır olarak tutulur.

1.1.2 Merkezi Versiyon Yönetim Sistemleri (MVYS)

Bu yöntemle hedeflenen YVYS’nin eksik yönlerini tamamlamaktır. YVYS’de çok kişili çalışılan projelerde versiyon takibi mümkün değildir. Çünkü versiyonlar kişilerin yerel bilgisayarlarında tutulmaktadır.

Merkezi Versiyon Yönetim Sistemi

Bu yöntemin versiyonlama mantığı YVYS ile aynıdır. Tek farkı versiyonlar yerel bilgisayarda değil internet üzerinden erişilebilir bir sunucu bilgisayarda tutulmaktadır. Sunucu veritabanında versiyonlar tutulur. Projede çalışan kişiler de sunucudan İlgili versiyonu çeker. Çalışması bittiğinde de sunucuya yeni versiyonu gönderir. Bu yöntemin kullanıldığı CVS, Subversion ve Perforce gibi araçlar vardır.

Bu yöntem YVYS’ye göre pek çok avantaja sahiptir. Tek bir noktadan tüm tarihçeye ulaşılabilir. Proje üzerindeki çalışmaların kontrolü uzaktan yapılabilir. Kim hangi değişikliği ne zaman yaptı görüntülenebilir. Kimin hangi çalışmayı yapacağına karar verilip kontrolü sağlanabilir.

YVYS ve MVYS ciddi dezanvajlara da sahiptir. Versiyonlar her iki yöntemde de sadece 1 noktada tutulmaktadır. MVYS için sunucuda olabilecek kesintilerde versiyonlama çalışması da durur. Sunucuda olası bir disk arızasında veri kaybıyla beraber tüm versiyonlar yok olur. Sadece yerelde kişilerin çalıştığı versiyona ait proje dosyaları kalır. Aynı şekilde YVYS için de bu durumlar geçerlidir.

1.1.3 Dağıtık Versiyon Yönetim Sistemleri (DVYS)

Bu yöntemle hedeflenen YVYS ve MVYS’nin eksik yönlerini tamamlamaktır. YVYS’de çok kişili çalışılan projelerde versiyon takibi mümkün değildir. MVYS ise sunucuda yaşanacak problem veya erişim sorunlarında versiyonlama durur. Ayrıca her iki yöntemde de projede versiyon kaybı hatta proje kaybı söz konusudur.

Dağıtık Versiyon Yönetim Sistemi

Bu yöntemin versiyonlama mantığı YVYS ile aynıdır. YVYS ve MVYS’den farkı versiyonlar hem yerelde hem sunucuda tutulmaktadır. Yerelde başlatılan bir proje YVYS gibi yerel veritabanında tutulur. Yereldeki bu projenin sunucu ile bağlantısı kurulur ve MVYS gibi yereldeki versiyonlama sunucuya aktarılır. Bu noktada proje kritik ayrım versiyonların tüm tarihçesi olduğu gibi yerelde ve sunucuda bulunur. Bu yöntemin kullanıldığı Git, Mercurial, Bazaar ya da Darcs gibi araçlar vardır.

Sunucu ile yerel senkron çalışmak zorunda değildir. Örneğin çevrimiçin olunamadığı durumlarda yerelde sunucudan bağımsız yani çevrimdışı olarak çalışılabilir. Çok kişili projelerde sunucudaki versiyon başka kullanılar tarafından ilerletilebilir. Çevrimiçi olunduğu anda sunucuya yereldeki proje versiyonu gönderilmeden önce sunucudaki güncel versiyon çekilir. Tarih bazlı sıralamayla değişiklikler versiyonlanır. Bu şekilde yerel versiyon veritabanı sunucudaki versiyon veritabanı ile eşitlenir. Bu noktada yereldeki versiyon veritabanı ile sunucudaki versiyon veri tabanı birleştirilir. Son adım olarak da yereldeki versiyon sunucuya gönderilir. Başka biri de benzer işlemi yaparak çalışmaya devam eder.

Bu yöntem YVYS ve MVYS’e göre pek çok avantaja sahiptir. Proje versiyonlarının kaybolma riski düzenli senktonize edildiği taktirde yoktur. YVYS gibi sadece yerelinde çalışabilir, MVYS gibi yerelindeki çalışmayı sunucuya gönderebilirsin. Projenin bir örneği bulunduğu sürece yerelindeki veritabanı arızası veya sunucudaki veritabanı arızası projedeki versiyonların kaybolmasına sebep olmaz. Sunucuda problem olursa herhangi birindeki örnek proje sunucuya gönderilerek çalışmaya devam edilebilir. Herhangi birinin yerelinde bir problem yaşanırsa da sunucudan projenin bütün halini çekip kaldığı yerden devam edebilir.

Bu yöntemin diğer yöntemlerde olduğu gibi çalışmayı etkileyen bir dezavantajı yoktur. Bu yöntem günümüzde kabul görmüş ve yaygın olarak kullanılan yöntemdir. Projeye ait tüm kaynaklar yok olmadığı sürece proje kaybolmaz.

Bu yazıda Git versiyon yönetim aracı ile ilgili bilgiler verilecektir.

1.2 Git’e Giriş

2005 yılında Linus Torvalds başta olmak üzere Linux çekirdeğini geliştiren topluluk tarafından geliştirilmiştir.

Git’in bazı hedefleri şunlardır:

  • Hız
  • Minimal tasarım
  • Lineer olmayan geliştirme için güçlü destek (binlerce paralel dal desteği)
  • Tamamen dağıtık olması
  • Devasa projeleri Linux kerneli verimliliğinde destekleyebilmesi (hız ve veri büyüklüğü açısından)

Git diğer dağıtık versiyon yönetim araçlarına göre farklı mimaride geliştirilmiştir. Diğer mimarilerde dosyanın değişiklik parçası saklanır. Başka bir deyişle delta temelli versiyonlar tanımlanır (delta-based).

Delta-Based

Git’te ise dosyanın anlık görüntüsü alınır (snapshot). Yani diğerlerinin yaptığı gibi sadece değişiklik parçasını versiyonlamaz. Dosyanın o anki halinin görüntüsünü çeker ve o şekilde saklar. Eğer anlık görünümü alınan dosya değişmediyse yeni bir görüntü oluşturmaz bir önceki görüntünün referansını saklar. Başka bir deyişle anlık görünümler ile versiyon tanımlanır (stream of snapshots).

Stream of Snapshots

Dosyanın versiyon döngüsü 3 durumdan oluşmaktadır. Modified(Değişiklik), Staged(İşaretli), and Committed(Kaydedilmiş).

  • Modified: dosyayı değiştirdiğinizi ama henüz veritabanına kaydetmediğinizi gösterir.
  • Staged: değiştirilmiş bir dosyayı bir sonraki anlık görünümünde kaydedilecek şekilde işaretlediğinizi gösterir. Bu dosyalara Index ismi verilir.
  • Committed: dosyanın güvenli bir şekilde yerel veritabanınızda saklandığını gösterir.

Bu kapsamda proje 3 ana bölüme ayrılabilir.

Proje Bölümleri


Proje Bölümleri Alt

Commit’lenmiş yani kaydedilmiş dosyalar ile versiyon ağacı ortaya çıkar. Versiyon ağacında hangi versiyonun aktif olduğunu yani kullanıldığını işaret eden HEAD isminde bir işaretçi(pointer) vardır.

HEAD

1.3 Kurulum

https://git-scm.com/downloads resmi adresinden kurulum yapabilirsiniz.

1.4 Konfigürasyon

Kurulum sonrası yapılması gereken ilk şey temel konfigürasyonların ayarlanmasıdır. Burada kullanıcı bilgilerimizi tanımlamamız gerekir. Bu bilgiler commit işleminde kimlik bilgisi olarak kullanılır. Tüm yaratılan commit’lerde değişmez bir şekilde kaydedilir.

1
2
git config --global user.name "Levent Sencer Şahin"
git config --global user.email l.sencer.sahin@gmail.com

1.5 Komutlar

1.5.1 init

Bu komut projenizde git’i oluşturur. Git ile versiyonlamaya başlamaya karar verdiğinizde bu komutu proje dizininde çalıştırmalısınız. Bu komut proje dizininde .git adında bir dizin oluşturur. Bu dizin git’in iskeletidir. Git herşeyi bu dizin altında tutar.

Proje Dizini içine git:

1
git init

1.5.2 add

Bu komut dosyaları takibe almak için kullanılır. İlk defa git entegre edildiyse hiçbir versiyonlama yoktur ve projedeki tüm dosyalar takip edilmeyi bekler. Sonraki aşamalarda değişiklik olan dosyaların takibe alınması için kullanılır. Tek tek takip edilmesi istenen dosyalar tam dosya yolu belirtilecek şekilde yazılabilir veya tüm dosyaların takip edilmesi isteniyorsa .(nokta) işareti kullanılabilir.

1
git add <dosyanın_tam_yolu|.> # Tüm dosyaları takibe almak için .(nokta) işareti kullanılır
1
2
git add README.md
git add LICENSE

1.5.3 commit

Bu komut takibe alınan dosyaların yerel veritabanına kaydedilmesi için kullanılır. Komit işleminde mesaj yazılması beklenir. Bunun için 2 farklı yöntem izlenebilir.

  1. Daha detaylı mesaj yazmak için editörden açmak.
    1
    git commit # Editör açılır. Editörde yazılan mesaj kaydedilip editör kapatıldığında commit tamamlanmış olur.
  2. Pratik mesaj yazmak.
    1
    git commit -m "Initial Project"

Buraya kadar 3 komuttan bahsettim. Bu 3 komut git ile yerelde çalışmak için başlangıç seviyesinde yeterlidir. Sunucuya gönderme işleminden önce internetten erişilebilir bir git projesini nasıl yerele çekip üzerinde çalışılabileceğinden bahsedeceğim.

1.5.4 clone

Bu komut bir git projesini tüm versiyonlarıyla beraber neredeyse tüm verileri olduğu gibi yerelinize kopyalar.

Örneğin libgit2 projesini yerele kopyalamak için:

1
git clone https://github.com/libgit2/libgit2

Kopyalama işleminden sonra add ve commit komutları ile kopyalanan proje içinde versiyon yönetimi yapılabilir.

1.5.5 status

Bu komut dosyaların dumunu listeler. Bir dosyanın 4 farklı durumu olabilir. Untracked(Takipsiz), Unmodified(Değişmemiş), Modified(Değişmiş) ve Staged(İşaretli).

  • Untracked: Takip edilmeyen dosya durumudur. Örneğin bu durumdaki dosyalar yeni eklenmiş dosyalar olabilir.
  • Unmodified: Takip edilen ve commit edilmiş dosyalarda değişiklik olmama durumudur. Örneği add ile işaretlenmiş ve commit ile kaydedilmiş ve sonrasında hiçbir değişikliğe uğramamış dosyalar.
  • Modified: Takip edilen ve commit edilmiş dosyalarda değişiklik olma durumudur. Örneği add ile işaretlenmiş ve commit ile kaydedilmiş ve sonrasında değişikliğe uğramış dosyalar.
  • Staged: Takip edilen veya edilmeyen dosyaların işaretlenme durumudur. Örneğin add komutu ile bu dosyalar işaretlenir. Commit işleminden sonra da takip edilir duruma geçerler.

Dosya Durum Döngüsü

1
git status

1.5.6 log

Bu komut commit tarihçesini gösterir.

1
git log

Bu noktaya kadar sadece yerelde çalıştık. Bu noktadan sonra sunucu ile çalışma kısmından bahsedeceğim.

1.5.7 remote

Bu komut yerelde çalışılan projenin sunucu bağlantısı kurmak için kullanılır. Sunucunun kısa adını ve url bilgisini girerek bağlantı kurulur. Kısa ad olarak gelenek haline gelmiş “origin” ismi kullanılabilir.

1
git remote add <kısa_ad> <url>
1
git remote add origin https://git.yesilirmakedas.com/levent.sahin/hello-world

Sunucu bağlantısını görüntülemek için:

1
git remote -v

1.5.8 pull

Bu komut yerelde olmayan sunucudaki tüm versiyonları çeker ve yereldeki versiyonlarla birleştirir. Varsayılan olarak gelenek haline gelmiş “master” dalı kullanılır.

1
git pull <kısa_ad> <dal>
1
git pull origin master

1.5.9 push

Bu komut sunucuda olmayan yereldeki tüm versiyonları sunucuya göndermek için kullanılır. Eğer sunucuda yereldeki değişiklik sonucu oluşan versiyondan başka bir versiyon varsa öncelikle pull yapılması gerekir.

1
2
git push <kısa_ad> <dal>
git push -u <kısa_ad> <dal> # -u parametresi varsayılan kısa ad ve dalı ayarlamak için eklenebilir.
1
2
3
git push origin master
# veya
git push -u origin master # eğer bu şekilde çalıştırılırsa bir sonraki push ve pull işleminde <kısa_ad> ve <dal> eklenmesine gerek kalmaz. --> git push (yeterli)

2. Orta Seviye

Bu kısımda Git versiyon yönetim aracı ile ilgili temel bilgilerin üzerine sık kullanılan veya kullanılma ihtiyacı duyulabilecek konulardan bahsedilecek.

2.1 .gitignore

Versiyonlamaya dahil olmasını istemediğini dosya ve dizinleri .gitignore dosyasına yazabilirsiniz. Bu dosyada tam yol(full path) veya göreceli yol(relative path) veya joker karakter(wildcard) ile tanımlama yapabilirsiniz. Her satırda 1 tanımlama olacak şekilde yazılır. Hariç tutmak istediğin tanımın başına !(ünlem) işareti koyabilirsin.

Tanım Kuralları:

  • #(hashtag) karakteri ile başlayan satırlar yok sayılır. Yorum satırı olarak değerlendirilir.
  • Standart glob deseninde(pattern) çalışır. Yinelemeli(Recursive) olarak tanımlama uygulanır. Yinelemeyi önlemek için başına /(eğik çizgi) karakteri ile başlatın. Dizini belirtmek için sonuna /(eğik çizgi) karakteri ekleyin.
  • Hariç tutmak için başına !(ünlem) işareti atabilirsiniz. !(ünlem) işareti değili/olumsuzu anlamına gelir.

Örnek:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ignore all .a files
*.a

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in any directory named build
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf

2.2 Dallar(Branch)

Git, paralel çalışmaya izin verir. Bu kapsamda farklı çalışmalar farklı birçok dal(brach) ile yapılabilir. Git’in çalışma yapısı depolama mimarisi ise bu dallanmaya oldukça elverişlidir. Herhangi bir performans sorunu yaratmaz.

dal bilgi

Yeni dal oluştururken mevcut daldaki HEAD referans alınır.

Dal Oluştur:

1
git checkout -b <dal_adı>

Öncesi:

dal ekle öncesi

1
git checkout -b iss53

Sonra

dal ekle sonrası

Dal oluşturduktan sonra checkout komutuyla ilgili dalı seçip çalışmaya başlayabiliriz. Çalışmaya başlayıp commit attığımızda aktif dalda commit tarihçesi ilerler.

1
2
3
git checkout iss53
git add file.txt
git commit -m "file.txt"

dal seç

Tekrar master dalına checkout komutuyla dönüp yeni bir dal yaratıp o dalda da farklı bir çalışma yürütebiliriz.

1
2
3
4
git checkout master
git checkout -b hotfix
git add index.txt
git commit -m "index.txt"

dal oluştur seç

2.3 Komutlar

2.3.1 diff

Bu komut kaydedilmiş son versiyon ile mevcuttaki değişiklikler arasındaki farkları listeler. Tüm değişiklikler de görüntülenebilir sadece 1 dosya özelinde de bu işlem yapılabilir.

1
git diff [dosya]

2.3.2 rm

Bu komut silme işlemi yapar. Fakat standart silmeden farklıdır. Git tarafından takip edilen bir dosyayı sildiğinizde bunu değişiklik olarak kabul eder ve işaretleyip bu değişikliği kaybetmenizi ister. Git’in rm komutu ile sildiğinizde ise Git bunu otomatik yapar. Yani dosyayı hem fiziksel olarak siler hem de işaretler. Aynı zamanda bu dosyanın takibini de kaldırır.

Örnek:

1
git rm <dosya>

2.3.3 mv

Git dosyaların isimleri ile ilgili meta bilgileri tutmaz, isim değişikliğini takip etmez. Bu komut bir dosyayı yeniden adlandırmak için kullanılır. Bunu taşıma işlemi yaparak sağlar. Fakat standart taşımadan farklıdır. Git tarafından takip edilen bir dosyayı taşıdığınızda yani ismini değiştirdiğinizde eski isimdeki dosyanın silindiğini ve yeni isimdeki dosyanın takip edilmeyen yeni bir dosya olduğunu söyler. Bu işlemi devam ettirdiğinizde eski isimdeki silme operasyonunun ve yeni isimdeki dosyayı işaretlemeniz gerekir. İşaretleme sonrası eski isim tarihçeye silindi olarak geçer ve yepyeni bir dosya takip edilmeye başlandı olarak geçer. Bu doğru bir yaklaşım değildir. Bu yanlış kullanımın önüne geçmek için Git’in mv komutu ile isim değişikliği yapılmalıdır. Git mv komutu ile dosya ismini değiştirdiğinizde Git bunun bir isim değişikliği olduğunu anlar ve eski isimden yeni isme geçiş olduğunu belirtecek şekilde “renamed” durumunda işaretler.

Örnek:

1
git mv <eski_dosya> <yeni_dosya>

2.3.4 checkout

Dal(branch), versiyon(commit), etiket(tag) gibi kayıtlı bölümler arasında seçim yapmak için kullanılır. Commit seviyesinde HEAD’i değiştirir. Aynı zamanda işaretlenmemiş değişikliklerin son versiyonlanmış haline geri dönmesi için de kullanılır. Yani değişikliği işaretlememek istediğinizde checkout ile kaldırabilirsiniz.

Dal Geçişi:

1
git checkout <dal>

master dalında:

1
git checkout master

master Dal

testing dalında:

1
git checkout testing

testing Dal

Versiyon Geçişi:

1
git checkout <commit>

Versiyon

Değişikliği Geri Al:

1
git checkout -- <dosya|.> # .(nokta) işareti tüm değişiklikleri geri alır.

2.3.5 reset

Versiyonları veya dosyalardaki değişiklikleri geri almak için kullanılır. Geri alma işlemi Git’in 3 ana çalışma bölgesi için ayrı ayrı uygulabilir. Bu ayrım –soft, –mixed ve –hard parametreleriyle yapılır. Varsayılan olarak parametre belirtilmezse –mixed uygulanır.

reset 3 bölge

reset –soft

Commit seviyesinde HEAD’i değiştirir. Bu anlamda checkout ile benzer işlemi yapar. (HEAD, aktif commit işaretçisi)

1
git reset --soft <commit|dosya>

Öncesi Commit:

reset soft öncesi commit

1
git reset --soft 9e5e6a4

Sonrası Commit:

reset soft sonrası commit

Öncesi Dosya:

reset soft öncesi dosya

1
git reset --soft file-a.txt

Sonrası Dosya:

reset soft sonrası dosya

Bu işlemden sonra işlemi geri almak için git commit komutu çalıştırılabilir.

reset soft sonrası dosya commit

reset –mixed veya reset

Index seviyesinde değişiklik yapar. Hem HEAD’i hem Index’i değiştirir. (Index, stage bölümünde işaretlenmiş hali)

1
2
3
git reset --mixed <commit|dosya>
# veya
git reset <commit|dosya>

Öncesi Commit:

reset mixed öncesi commit

1
2
3
git reset --mixed 9e5e6a4
# veya
git reset 9e5e6a4

Sonrası Commit:

reset mixed sonrası commit

Öncesi Dosya:

reset mixed öncesi dosya

1
2
3
git reset --mixed file.txt
# veya
git reset file.txt

Sonrası Dosya:

reset mixed sonrası dosya

Bu işlemden sonra işlemi geri almak için git add komutu çalıştırılabilir.

reset soft sonrası dosya add

reset –hard

Proje genelinde değişiklik yapar. Hem çalışma dizinini (working directory) hem HEAD’i hem de Index’i değiştirir. Bu işlemi diğerlerine göre tehlikelidir. Çünkü yapılan değişiklik geri alınamaz. Kalıcı olarak siler.

1
git reset --hard <commit|dosya>

Öncesi:

reset hard öncesi

1
git reset --hard 9e5e6a4

Sonrası:

reset hard sonrası

2.3.6 checkout vs reset

git checkout b:

checkout vs

git reset b:

reset vs


checkout vs reset

2.3.7 merge

2 veya daha fazla versiyonu birleştirmek için kullanılır. Örneğin farklı dallar ile çalıştıktan sonra birleştirme işlemi için bu komut kullanılır.

1
git merge <dal|commit>

Örneğin master ile iss53 dalını master dalında birleştirelim.

Öncesi:

merge öncesi

1
2
git checkout master
git merge iss53

Sonrası:

merge sonrası

2.4 SSH(Secure Shell) Protokolü

Bir bilgisayardan diğeri güvenli yoldan oturum açma yöntemidir. Bilgisayarlar arası bağlantı güvenli bağlantı kurulur.

Projede yaptığınız çalışmaları sunucuya gönderirken bu protokolün kullanılması hız katar. Varsayılan olarak HTTPS protokolü üzerinden aktarım yapılır. Bu protokolde ise her transferde kimlik doğrulaması yapmanız gerekir. SSH protokolü ile çalıştığınızda ise git web client uygulamasındaki tarife göre ayarlama yaptıktan sonra transfer işlemini transfer anında kimlik doğrulamasına ihtiyaç olmadan yapabilirsiniz.

ssh şema1


ssh şema2