Thursday, December 18, 2014

Svn Repolarda Git Kullanımı

Bu yazıda Subversion repolarda git ile nasıl çalışabileceğimizi anlatacağım. Çalıştığımız firmalarda Subversion kullanılıyor olabilir. Çoğu zaman aynı anda birden çok iş ile aynı anda uğraşmamız gerekiyor. Örneğin 1 ay sürecek bir işin normalde branch açılıp oradan ilerlenmesi, geliştirme bittiği zaman branchin trunk'a merge edilmesi gerekiyor. Ancak çoğu zaman bunu gerçekleştiremiyoruz. Yada ufak çaplı işler için branch açmıyoruz. Bu esnada acil işler geldiğinde kod tabanımız kirli olduğu için projeyi yeniden çekip, projeyi ayağa kaldırmak için yapılması gereken konfigurasyonlar varsa onları yapmak hayli yorucu ve şevk kırıcı oluyor. Halbuki git ile tek yapmamız gereken yeni bir branch oluşturup oradan çalışmak.


Git'in git-svn komutu sayesinde Subversion repolar ile çalışıp kendi bilgisayarımızda git kullanabiliyoruz.

git-svn kullanımını göstermek amacıyla bilgisayarımda Subversion server kurup bir proje oluşturuyorum. Proje hiyerarşisi aşağıdaki gibi
.
├── branches
│   └── feature
│       └── version.txt
├── tags
│   └── 1.0
│       └── version.txt
└── trunk
    └── version.txt

git svn clone komutu ile projeyi çekeceğim.
  • --stdlayout proje yapımın standart Subversion yapısında (trunk, branches, tags) olduğunu söylüyor.
  • --prefix=svn/ ise git'in önerdiği bir remote'ların başına "svn" eklediğimiz bir best practice.
  • Subversion proje yapınız standart değilse bunu -T [trunk ismi] -t [tag ismi] -b [branch ismi] parametreleri ile belirtebiliyoruz.
Oluşturduğum proje yapısı standart yapıda olduğundan aşağıdaki komutu çalıştırıyorum.

ugur@ugur-PC:~/dev/git-test$ git svn clone --stdlayout http://192.168.1.22/svn/test --prefix=svn/
Initialized empty Git repository in /home/ugur/dev/git-test/test/.git/
        A       version.txt
r1 = c2ebc7af6d5ce82fae91a9e5d7aad66a695694e5 (refs/remotes/svn/trunk)
Found possible branch point: http://192.168.1.22/svn/test/trunk => http://192.168.1.22/svn/test/tags/1.0, 1
Found branch parent: (refs/remotes/svn/tags/1.0) c2ebc7af6d5ce82fae91a9e5d7aad66a695694e5
Following parent with do_switch
Successfully followed parent
r2 = 8eceb98ea9fb9bb5b8e13ab7983aee86c1d15653 (refs/remotes/svn/tags/1.0)
Found possible branch point: http://192.168.1.22/svn/test/trunk => http://192.168.1.22/svn/test/branches/feature, 2
Found branch parent: (refs/remotes/svn/feature) c2ebc7af6d5ce82fae91a9e5d7aad66a695694e5
Following parent with do_switch
Successfully followed parent
r3 = f8d13d0c999d94f3816474ece614d4ee56309956 (refs/remotes/svn/feature)
        M       version.txt
r4 = 29351521159da33980d456d89916afeb4e8e3ec9 (refs/remotes/svn/feature)
        M       version.txt
r5 = e4ac1eac221012ac312ec766a0b104b9792ea4a0 (refs/remotes/svn/tags/1.0)
Checked out HEAD:
  http://192.168.1.22/svn/test/trunk r1


Görüldüğü üzere git-svn gidip projenin tüm versiyonlarını indirdi. Projemiz çok büyükse tüm versiyonları çekmek çok uzun sürebilir. Belirli bir revizyondan itibaren almak istiyorsanız -r100 gibi revizyon numarası belirterek o revizyondan itibaren çekmesini sağlayabilirsiniz.

git branch -a komutu ile remote'lar da dahil tüm branch'leri listeliyorum. Git tag ve branch'i de düzgün bir şekilde almış.

ugur@ugur-PC:~/dev/git-test/test$ git branch -a
* master
  remotes/svn/feature
  remotes/svn/tags/1.0
  remotes/svn/trunk

Şu anda master branch'deyim ve master branch'im trunk'a bakıyor. git svn info ile doğrulayalım.

ugur@ugur-PC:~/dev/git-test/test$ git svn info 
Path: .
URL: http://192.168.1.22/svn/test/trunk
Repository Root: http://192.168.1.22/svn/test
Repository UUID: 749e1b89-9750-43c6-a06e-47e3675be1a3
Revision: 1
Node Kind: directory
Schedule: normal
Last Changed Author: (no author)
Last Changed Rev: 1
Last Changed Date: 2014-12-18 20:36:39 +0200 (Prş, 18 Ara 2014)

svn:ignore ile takip etmediğimiz dosyaları git'e aktarmak için aşağıdaki komutu proje root klasöründe çalıştırıyoruz.

ugur@ugur-PC:~/dev/git-test/test$git svn show-ignore > .gitignore

Bu noktadan sonra normal bir şekilde git kullanabiliriz.

Git kullanırken Master'ı her zaman temiz tutup branchlerde çalışmak uygulanması gereken prensiplerden. bugfix isimli bir branch oluşturup bugfix branchine geçiyorum.

ugur@ugur-PC:~/dev/git-test/test$ git branch bugfix
ugur@ugur-PC:~/dev/git-test/test$ git checkout bugfix 
Switched to branch 'bugfix'

bugfix branchinden işlerimi yapıp comitliyorum.

ugur@ugur-PC:~/dev/git-test/test$ echo "dummy text" > dummy.txt
ugur@ugur-PC:~/dev/git-test/test$ git add dummy.txt
ugur@ugur-PC:~/dev/git-test/test$ git commit -m "added dummy text file"
[bugfix 702c482] added dummy text file
 1 file changed, 1 insertion(+)
 create mode 100644 dummy.txt

Şimdi master branchine geçip bugfix branchinde yaptığım değişiklikleri merge edeğim.

ugur@ugur-PC:~/dev/git-test/test$ git co master 
Switched to branch 'master'
ugur@ugur-PC:~/dev/git-test/test$ git merge master bugfix
Updating c2ebc7a..702c482
Fast-forward
 dummy.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 dummy.txt

Git kullanırken sık sık commit yapmak önerilir. Aynı zamanda sık sık update alıp çıkabilecek conflictleri ufak parçalar halinde çözüp komit yapılacak gün repo ile lokal kod arasında bir uçurum oluşup saatlerce conflict yapmak zorunda kalmıyoruz. Branch'de 100 komit ile bir işi bitirdim ancak bunların tamamının history'de görünmesini istemiyorum. Bu durumda git merge master bugfix --squash komutu ile tüm değişiklikleri master'a merge ettik ancak henüz komitlemedik. git commit -m "added x capabilities to project" komutu ile history'de görünecek tek komiti yapıyoruz.

Değişikliklerimi Subversion repoya göndermeden önce update alıyorum.

ugur@ugur-PC:~/dev/git-test/test$ git svn rebase
Current branch master is up to date.

Şimdi değişikliklerimi Subversion repoya gönderebilirim. Bu işlemi yaparken doğru yere komit yaptığımdan emin olmak için --dry-run parametresi ile önce bir önizleme yaptıktan sonra gerçekten komit yapmak daha sağlıklı.

ugur@ugur-PC:~/dev/git-test/test$ git svn dcommit --dry-run 
Committing to http://192.168.1.22/svn/test/trunk ...  
diff-tree 12609a045129e87aa7e50f2455c46dd70e529dc3~1 12609a045129e87aa7e50f2455c46dd70e529dc3

ugur@ugur-PC:~/dev/git-test/test$ git svn dcommit
Committing to http://192.168.1.22/svn/test/trunk ...
        A       dummy.txt
Committed r6
        A       dummy.txt
r6 = 911361691a5d90f7bd6e0da52768719e3bef3bcc (refs/remotes/svn/trunk)
No changes between 023baf48949871da63699b5642ab14de1bf86bf0 and refs/remotes/svn/trunk
Resetting to the latest refs/remotes/svn/trunk

İşim bittikten sonra branchimi silebilirim.

ugur@ugur-PC:~/dev/git-test/test$ git branch -D bugfix
Deleted branch bugfix (was 702c482).

Herhangi bir anda trunk yerine bir svn branch üzerinden çalışmanız gerekirse git HEAD'i o remote'a yönlendirerek bu işlemi yapabilirsiniz. feature branch'i üzerinde çalışmak için aşağıdaki komutu çalıştırmam yeterli.

ugur@ugur-PC:~/dev/git-test/test$ git br -a #branchlerimizi listeleyelim
  bugfix
* master
  remotes/svn/feature
  remotes/svn/tags/1.0
  remotes/svn/trunk
ugur@ugur-PC:~/dev/git-test/test$ git reset --hard remotes/svn/feature #feature branchine geçiyorum.
HEAD is now at 2935152 change branch version file
ugur@ugur-PC:~/dev/git-test/test$ git svn info #feature branchine olduğumu doğruluyorum.
Path: .
URL: http://192.168.1.22/svn/test/branches/feature
Repository Root: http://192.168.1.22/svn/test
Repository UUID: 749e1b89-9750-43c6-a06e-47e3675be1a3
Revision: 4
Node Kind: directory
Schedule: normal
Last Changed Author: (no author)
Last Changed Rev: 4
Last Changed Date: 2014-12-18 20:38:29 +0200 (Prş, 18 Ara 2014)

Daha sonrada Subversion'a yeni bir branch eklenirse bunu nasıl git ile takip edebiliriz. Projeme foo isimli yeni bir branch ekledim.
aşağıdaki komut ile yeni eklenen branchi'de çekiyorum.
ugur@ugur-PC:~/dev/git-test/test$ git svn fetch --all
        A       version.txt
        A       dummy.txt
r8 = a19516f6027a38337224f543f612cc32b9663b07 (refs/remotes/svn/foo)
ugur@ugur-PC:~/dev/git-test/test$ git br -a
* master
  remotes/svn/feature
  remotes/svn/foo
  remotes/svn/tags/1.0
  remotes/svn/trunk

Daha fazla bilgi ve komutların detayları için git-svn dökümanına bakabilirsiniz.

Tuesday, December 2, 2014

Spring Boot ile Spring'e hızlı bir giriş

Merhaba,

Askerlik ve sonrasında iş temposu derken uzun zamandır birşeyler yazamadım. Bundan sonra daha tekrar öğrendiklerimi paylaşmayı düşünüyorum.

Spring, Spring Web MVC öğrenme sürecinde evde birşeyler denerken her defasında yeni bir spring projesi oluşturmak ve ayağa kaldırmak fazlasıyla zamanımı alıyordu. Bu durumu aşmak için Spring, Spring Web MVC, Hibernate ve basit bir önyüzden oluşan bir proje hazırlayıp bu proje üzerinde denemelerimi yapmaya başladım. http://spring.io adresinde gezerken Spring-Boot projesi ile karşılaştım. Spring-Boot projesi Spring konfigurasyonları ile uğraşmadan direk Spring ile geliştirme yapabilmemize imkan veren araçlar sunuyor.
Spring-Boot ile hızlıca bir proje oluşturup, RestController yazıp spring-boot içerisinde gelen tomcat'i çalıştırıp controller'ımızı test edelim.

Öncelikle bir maven projesi açarak başlıyoruz. pom.xml içerisine aşağıdaki dependency'leri ekliyoruz.


  org.springframework.boot
  spring-boot-starter-parent
  1.1.9.RELEASE
 
 
  
   org.springframework.boot
   spring-boot-starter-web
  
 

Şimdi bir Controller yazıyoruz.

package org.guneriu.hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * @EnableAutoConfiguration anotasyonu ile Spring proje için gerekli ayarları yapıyor.
 * spring-boot-starter-web dependency eklediğimiz için web projesi ayağa kaldırıyor.
 *
 */
@EnableAutoConfiguration
@RestController
public class HelloController {
 
 @RequestMapping("/")
 public String index() {
  return "Hello World";
 }
 
 @RequestMapping("/hello/{name}")
 public String greetings(@PathVariable String name) {
  return "Hello " + name;
 }

 public static void main(String[] args) throws Exception {
        SpringApplication.run(HelloController.class, args);
    }
 
}


HelloController sınıfını java uygulaması olarak çalıştırıyoruz. Konsol çıktısı uygulamamızın 8080 portunda çalıştığını söylüyor.





Spring-Boot'u çalıştırmanın başka yolları da var. Bu yazıda sadece "spring-boot-starter-web" starter pom kullandım. Her anlamda ihtiyacınızı karşılayacak starter pom'ları kullanabilirsiniz. Daha fazla bilgi için Spring-Boot Dökümanı'na göz atabilirsiniz.