Git
Chapters ▾ 2nd Edition

8.2 Git’i Özelleştirmek - Git Nitelikleri

Git Nitelikleri

Bu ayarlardan bazıları bir yol için de belirtilebilir, böylece Git bu ayarları yalnızca bir alt dizine veya dosyaların alt kümesine uygular. Bu yola özel ayarlara Git nitelikleri adı verilir ve dizinlerinizden birindeki (normalde proje kök dizini) bir ".gitattributes" dosyasında ya da eğer öznitelik dosyasının projenizde katkılanmasını istemiyorsanız ".git/info/attributes" dosyasında ayarlanır.

Nitelikleri kullanarak, projenizdeki tek tek dosyalar veya dizinler için ayrı birleştirme stratejileri belirlemek, Git’e metin olmayan dosyaların farkını nasıl ayıracağını söylemek veya ekleme veya çıkarma yapmadan önce Git’in içeriği filtrelemesini sağlamak gibi şeyler yapabilirsiniz. Bu bölümde Git proje dizinlerinizde ayarlayabileceğiniz bazı nitelikleri öğrenecek ve bu özelliğin pratikte kullanımına ilişkin birkaç örnek göreceksiniz.

İkilik (Binary) Dosyalar

Git özniteliklerini kullanarak yapabileceğiniz harika bir hile, Git’e hangi dosyaların ikilik olduğunu (aksi halde bunu kendisinin belirleyemeyeceği durumlarda) ve bu dosyaların nasıl işleneceği konusunda özel talimatlar verme yeteneğidir. Örneğin, bazı metin dosyaları makine tarafından oluşturulmuş olabilir ve farklanabilir (diff’i hesaplanabilir) olmayabilir, diğer yandan bazı ikili dosyalar ise farklanabilir olabilir. Git’e bunların hangisi olduğunu nasıl söyleyeceğinizi göreceksiniz.

İkilik Dosyaları Tanımlamak

Bazı dosyalar metin dosyalarına benzer ancak her amaç için ikilik veri olarak işlenmelidir. Örneğin, macOS’taki Xcode projeleri, IDE tarafından diske yazılan ve derleme ayarlarınızı vb. kaydeden bir JSON (düz metin JavaScript veri formatı) veri kümesi olan .pbxproj ile biten bir dosya içerir. Teknik olarak bir metin dosyası olmasına rağmen (çünkü tümü UTF-8’dir), aslında mini bir bir veritabanı olduğu için, bunu öyle işlemek istemezsiniz. İçeriği iki kişi değiştirdiğinde birleştiremezsiniz ve farkları bulmak genellikle yardımcı olmaz. Dosya bir makine tarafından tüketilmek üzere tasarlanmıştır. Temelde, onu ikilik bir dosya gibi işlemek istersiniz.

Git’e tüm pbxproj dosyalarını ikilik veri olarak işlemesini söylemek için .gitattributes dosyanıza aşağıdaki satırı ekleyin:

*.pbxproj binary

Artık Git, proje dosyalarınız üzerinde git show veya git diff komutunu çalıştırdığınızda bu dosyadaki değişiklikler için bir fark hesaplamaya veya yazdırmaya çalışmayacak; aynı zamanda CRLF sorunlarını çözmeye veya düzeltmeye de çalışmayacaktır.

İkilik Dosyaların Farkını (Diff) Bulma

Git öznitelikleri işlevselliğini kullanarak ikilik dosyaları etkin bir şekilde farklılaştırabilirsiniz. Bunu, Git’e ikili verinizi normal diff aracılığıyla karşılaştırılabilir bir metin biçimine nasıl dönüştüreceğini söyleyerek yaparsınız.

Öncelikle, bu tekniği insanlık tarihinde bilinen en sinir bozucu sorunlardan birini çözmek için kullanacaksınız: Microsoft Word belgelerini sürüm kontrolüne almak. İlginç şekilde, Word’ün en berbat metin düzenleyicisi olduğunu bilmesine rağmen, herkes halen onu kullanmaktadır. Word belgelerini sürüm kontrolüne almak istiyorsanız, onları bir Git reposuna koyabilir ve ara sıra katkı işleyebilirsiniz. Peki bu ne işe yarar? Normalde git diff komutunu çalıştırırsanız, yalnızca şunu görürsünüz:

$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 88839c4..4afcb7c 100644
Binary files a/chapter1.docx and b/chapter1.docx differ

İki sürümü doğrudan karşılaştıramazsınız, bunun için onları kontrol etmeniz ve manuel olarak taramanız gerekir, değil mi? Git özniteliklerini kullanarak bunu kolayca yapabilirsiniz. .gitattributes dosyanıza aşağıdaki satırı ekleyin:

*.docx diff=word

Bu komut Git’e, eğer değişiklik içeren dosyaların değişimini görmek isterseniz, bu örüntüyle eşleşen herhangi bir dosyayla karşılaştığınızda, Git’in ``word`` filtresini kullanması gerektiğini söyler. Peki ``word`` filtresi nedir? Önce onu yapılandırmanız gerekir. Burada, Git’in Word belgelerini okunabilir metin dosyalarına dönüştürmek için docx2txt programını kullanmasını yapılandırıyoruz, böylece bunların farkını doğru şekilde karşılaştırabilirsiniz.

Bunun için öncelikle, docx2txt 'yi kurmanız gerekecek; onu https://sourceforge.net/projects/docx2txt adresinden indirebilirsiniz. INSTALL dosyasındaki yönergeleri izleyerek, onu shell’inizin bulabileceği bir yere koyun. Sonraki adımda, çıktıyı Git’in beklediği formata dönüştüren bir sargı betiği yazacaksınız. Dizininizde docx2txt adında bir dosya oluşturun ve şu içeriği ekleyin:

#!/bin/bash
docx2txt.pl "$1" -

Dosyanın chmod a+x ile yürütülebilir olması gerektiğini unutmayın. Son olarak, bu betiği kullanması için Git’i yapılandırabilirsiniz:

$ git config diff.word.textconv docx2txt

Artık Git, iki poz arasındaki farkı bulmaya çalışırken, dosyalardan herhangi birinin .docx uzantısıyla bittiğini görürse; bu dosyaları docx2txt programı olarak tanımlanan ``word`` filtresinden geçirmesi gerektiğini bilir. Böylece, ilgili dosyaların farkını bulmadan önce, onları metin tabanlı sürümlere dönüştürür.

İşte bir örnek: Bu kitabın 1. bölümü Word biçimine dönüştürüldü ve bir Git reposuna katkılandı. Ardından, yeni bir paragraf daha eklendi. İşte git diff komutunun şu anda gösterdiği sonuç:

$ git diff
diff --git a/chapter1.docx b/chapter1.docx
index 0b013ca..ba25db5 100644
--- a/chapter1.docx
+++ b/chapter1.docx
@@ -2,6 +2,7 @@
 This chapter will be about getting started with Git. We will begin at the beginning by explaining some background on version control tools, then move on to how to get Git running on your system and finally how to get it setup to start working with. At the end of this chapter you should understand why Git is around, why you should use it and you should be all setup to do so.
 1.1. About Version Control
 What is "version control", and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. For the examples in this book you will use software source code as the files being version controlled, though in reality you can do this with nearly any type of file on a computer.
+Testing: 1, 2, 3.
 If you are a graphic or web designer and want to keep every version of an image or layout (which you would most certainly want to), a Version Control System (VCS) is a very wise thing to use. It allows you to revert files back to a previous state, revert the entire project back to a previous state, compare changes over time, see who last modified something that might be causing a problem, who introduced an issue and when, and more. Using a VCS also generally means that if you screw things up or lose files, you can easily recover. In addition, you get all this for very little overhead.
 1.1.1. Local Version Control Systems
 Many people's version-control method of choice is to copy files into another directory (perhaps a time-stamped directory, if they're clever). This approach is very common because it is so simple, but it is also incredibly error prone. It is easy to forget which directory you're in and accidentally write to the wrong file or copy over files you don't mean to.

Git bize eklediğimiz "Testing: 1, 2, 3." dizesini doğru bir şekilde bildiriyor. Belki mükemmel değil - biçim (font, büyüklük, vs) değişikliklerini göremezsiniz - ama kesinlikle işe yarıyor.

Bu şekilde çözebileceğiniz başka ilginç bir sorun da resim dosyalarını farklılaştırmaktır. Bunu yapmanın yollarından biri, resim dosyalarını EXIF bilgilerini (çoğu resim formatında kaydedilmekte olan metaveriler) çıkaran bir filtreden geçirmektir. exiftool programını indirip kurarsanız, onu resimlerinizi metaveri içeren metin biçiminde dönüştürmek için kullanabilirsiniz. Böylece fark en azından yapılan herhangi bir değişikliğin metinleştirilmiş halini gösterir. .gitattributes dosyanıza şu satırı ekleyin:

*.png diff=exif

Git’i bu aracı kullanması için yapılandırın:

$ git config diff.exif.textconv exiftool

Projede bir resmi değiştirirseniz ve git diff komutunu çalıştırırsanız, şuna benzer bir şey görürsünüz:

diff --git a/image.png b/image.png
index 88839c4..4afcb7c 100644
--- a/image.png
+++ b/image.png
@@ -1,12 +1,12 @@
 ExifTool Version Number         : 7.74
-File Size                       : 70 kB
-File Modification Date/Time     : 2009:04:21 07:02:45-07:00
+File Size                       : 94 kB
+File Modification Date/Time     : 2009:04:21 07:02:43-07:00
 File Type                       : PNG
 MIME Type                       : image/png
-Image Width                     : 1058
-Image Height                    : 889
+Image Width                     : 1056
+Image Height                    : 827
 Bit Depth                       : 8
 Color Type                      : RGB with Alpha

Dosya boyutu ve görüntü boyutlarının her ikisinin de değiştiğini kolayca görebilirsiniz.

Anahtar Kelime Genişletmesi

SVN veya CVS tarzı anahtar kelime genişletmesi, bu sistemlere alışkın olan geliştiriciler tarafından sıkça istenir. Git’teki temel sorun şudur ki, Git öncelikle dosyanın özetini çıkardığı için, bir dosya katkılandıktan sonra, katkı hakkında bilgi içeren bir dosyayı değiştiremezsiniz. Ancak, bir dosya katkılanırken içine metin ekleyebilir ve katkı işlenmeden önce tekrar kaldırabilirsiniz. Git öznitelikleri size bunu yapmanın iki yolunu sunar.

İlk olarak, bir dosyadaki $Id$ alanına otomatik olarak bir blokun SHA-1 özeti enjekte edebilirsiniz. Bu özniteliği bir dosyaya veya dosya kümesine ayarlarsanız, bir sonraki sefer o dala geçtiğinizde, Git bu alanı blokun SHA-1’i ile değiştirir. Önemli olan, bu özetin katkının SHA-1’i değil, bloğun kendi SHA-1’i olduğunu bilmenizdir. Şimdi .gitattributes dosyanıza şu satırı ekleyin:

*.txt ident

Bir test dosyasına bir $Id$ referansı ekleyin:

$ echo '$Id$' > test.txt

Bir sonraki sefer bu dosyayı çıkardığınızda, Git blokun SHA-1 özetini enjekte eder:

$ rm test.txt
$ git checkout -- test.txt
$ cat test.txt
$Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $

Ancak, bu sonuç sınırlı bir kullanıma sahiptir. Eğer CVS veya Subversion’da anahtar kelime yerine başka bir şey koyduysanız (mesela bir tarih damgası ekleyebilirsiniz); SHA-1 rasgele üretilen bir karma olduğu için, bir SHA-1’in diğerinden daha eski veya daha yeni olup olmadığını sadece bakarak anlayamazsınız.

Dosya işleme/çıkarma işlemlerinde yerine koyma yapmak için kendi filtrelerinizi yazabilirsiniz. Bunlara clean (temizleme, arındırma) ve smudge (lekeleme, bulaştırma) filtreleri denir. .gitattributes dosyasında, belirli dizinlere bir filtre belirleyebilir ve dosyaları çıkarmadan hemen önce ("smudge", bkz. ``smudge`` filtresi checkout işleminde çalışıyor.) veya izleme alınmadan hemen önce ("clean", bkz. ``clean`` filtresi stage işleminde çalışıyor.) çalışacak betikler kurabilirsiniz. Bu filtreler çeşitli eğlenceli işlemleri gerçekleştirmek üzere ayarlanabilir.

``smudge`` filtresi checkout işleminde çalışıyor.
Görsel 143. ``smudge`` filtresi checkout işleminde çalışıyor.
``clean`` filtresi stage işleminde çalışıyor.
Görsel 144. ``clean`` filtresi stage işleminde çalışıyor.

Bu özelliğin orijinal katkı mesajı, tüm C kaynak kodlarınızı katkılamadan önce indent programından geçirmenin basit bir örneğini verir. .gitattributes dosyanızdaki filtre özniteliğini *.c dosyalarını ``indent`` filtresi ile süzmek üzere ayarlayarak bunu kurabilirsiniz:

*.c filter=indent

Ardından, Git’e ``indent`` filtresinin "smudge" ve "clean" işlemlerinde ne yapacağını söyleyin:

$ git config --global filter.indent.clean indent
$ git config --global filter.indent.smudge cat

Bu durumda, *.c ile eşleşen dosyaları katkıladığınızda, Git önce onları izleme almadan önce indent programından geçirecek ve sonra onları diske geri çıkarmadan önce de cat programından geçirecektir. cat programı aslında hiçbir şey yapmaz: aldığı veriyi aynı şekilde verir. Bu kombinasyon, katkı işlemeden önce tüm C kaynak kodu dosyalarını indent ile filtreler.

Başka bir ilginç örnek, $Date$ anahtar kelime genişlemesidir, RCS stili. Bunu düzgün yapmak için, bir dosya adını alıp, bu projenin son katkı tarihini bulan ve tarihi dosyaya yerleştiren küçük bir betik gerekmektedir. İşte bunu yapan küçük bir Ruby betiği:

#! /usr/bin/env ruby
data = STDIN.read
last_date = `git log --pretty=format:"%ad" -1`
puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')

Betik, yalnızca git log komutundan en son katkı tarihini alır, bunu stdin’de gördüğü herhangi bir $Date$ dizesine yerleştirip, sonuçları yazdırır - bu işlemi isteğiniz dilde kolayca yapabilirsiniz. Bu dosyayı expand_date adıyla adlandırıp, dizininize ekleyebilirsiniz. Şimdi, Git’te (dater olarak adlandıracağınız) bir filtre kurmanız gerekiyor ve çıkışta dosyaları bulaştırmak (smudge) için expand_date filtresini kullanmasını söyleyin. Bunu katkıda temizlemek (clean) için bir Perl ifadesi kullanılacaktır:

$ git config filter.dater.smudge expand_date
$ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'

Bu Perl kodcuğu, $Date$ dizesinde gördüğü her şeyi ayıklar ve başlangıç durumuna geri döner. Artık filtre hazır olduğuna göre, yeni filtreyi devreye sokan ve $Date$ anahtarını içeren bir dosya oluşturarak test edebilirsiniz:

date*.txt filter=dater
$ echo '# $Date$' > date_test.txt

Bu değişiklikleri yapıp ve dosyayı kontrol ederseniz, anahtar kelime doğru şekilde değiştirilmiş olacaktır:

$ git add date_test.txt .gitattributes
$ git commit -m "Testing date expansion in Git"
$ rm date_test.txt
$ git checkout date_test.txt
$ cat date_test.txt
# $Date: Tue Apr 21 07:26:52 2009 -0700$

Bu tekniğin özelleştirilmiş uygulamalar için ne kadar güçlü olabileceğini görebilirsiniz. Ancak dikkatli olmanız gerekir: çünkü .gitattributes dosyası projeye dahil edilir ve projeyle birlikte dolaşır, ancak sürücü (bu durumda dater) dahil edilmez; bu yüzden her yerde çalışmayabilir. Bu filtreleri tasarlarken şunu hedefleyin: bunlar başarısız olurken bile bunu zarif bir şekilde yapmalı ve projenin düzgün çalışmasını engellememesi gerekir.

Repoyu Dışa Aktarma

Git öznitelik verileri, proje arşivini dışa aktarırken bazı ilginç işlemler yapmanıza olanak tanır.

export-ignore

Arşiv oluşturulurken belirli dosyaların veya dizinlerin dışa aktarılmamasını söyleyebilirsiniz. Projenizin arşiv dosyasına dahil etmek istemediğiniz ancak projenizde kontrol edilmesini istediğiniz bir alt dizin veya dosya varsa, bu dosyaları export-ignore özniteliği aracılığıyla belirleyebilirsiniz.

Örneğin, bir test/ alt dizininde bazı test dosyalarınız var ve bu dosyaların projenizin arşiv tar dosyasına dahil edilmesi mantıklı değilse, aşağıdaki satırı Git öznitelik dosyanıza ekleyebilirsiniz:

test/ export-ignore

Artık projenizin bir arşiv tar dosyasını oluşturmak için git archive komutunu çalıştırdığınızda, bu dizin arşivde yer almayacak.

export-subst

Dağıtım için dosyaları dışa aktarırken, export-subst özniteliğiyle işaretlenmiş dosyaların belirli bölümlerine git log 'un biçimlendirme ve anahtar-kaynak genişletme işlemi uygulayabilirsiniz.

Projenize bir LAST_COMMIT adlı bir dosya eklemek ve git archive çalıştığında son taahhüt hakkında otomatik olarak meta verileri enjekte etmek isterseniz, .gitattributes ve LAST_COMMIT dosyalarınızı örneğin aşağıdaki gibi ayarlayabilirsiniz:

LAST_COMMIT export-subst
$ echo 'Last commit date: $Format:%cd by %aN$' > LAST_COMMIT
$ git add LAST_COMMIT .gitattributes
$ git commit -am 'adding LAST_COMMIT file for archives'

git archive komutunu çalıştırdığınızda, arşivlenmiş dosyanın içeriği şöyle görünecektir:

$ git archive HEAD | tar xCf ../deployment-testing -
$ cat ../deployment-testing/LAST_COMMIT
Last commit date: Tue Apr 21 08:38:48 2009 -0700 by Scott Chacon

Dönüşümler, örneğin katkı mesajını ve herhangi bir git notes içerebilir veya git log basit kelime sarmalama yapabilir:

$ echo '$Format:Last commit: %h by %aN at %cd%n%+w(76,6,9)%B$' > LAST_COMMIT
$ git commit -am 'export-subst uses git log'\''s custom formatter

git archive uses git log'\''s `pretty=format:` processor
directly, and strips the surrounding `$Format:` and `$`
markup from the output.
'
$ git archive @ | tar xfO - LAST_COMMIT
Last commit: 312ccc8 by Jim Hill at Fri May 8 09:14:04 2015 -0700
       export-subst uses git log's custom formatter

         git archive uses git log's `pretty=format:` processor directly, and
         strips the surrounding `$Format:` and `$` markup from the output.

Oluşan arşiv, dağıtım çalışması için uygun olsa da, herhangi bir dışa aktarılmış arşiv gibi, daha fazla geliştirme çalışmasına uygun değildir.

Birleştirme Stratejileri

Projedeki belirli dosyalar için farklı birleştirme stratejileri kullanmasını söylemek için de Git özniteliklerini kullanabilirsiniz. Çok kullanışlı bir seçenek, belirli dosyaların çakışmaları olduğunda Git’in bu dosyaları birleştirmeye çalışmamasını, bunun yerine çakışma olduğunda sizin kodunuzu başkasınınkinin üzerine yazmasını istemektir.

Bu, bir projedeki bir dalın ayrıştığı veya özelleştiği, ancak bu dalı geri birleştirmek istediğinizde belirli dosyaları yok saymak istediğiniz durumlarda faydalıdır. Örneğin, iki dalda farklı olan database.xml adında bir veritabanı ayar dosyanız varsa ve veritabanı dosyasını bozmadan diğer daldan birleştirmek istiyorsanız, şöyle bir öznitelik kurabilirsiniz:

database.xml merge=ours

Ve ardından bir ours birleştirme stratejisi tanımlayın:

$ git config --global merge.ours.driver true

Diğer dalı birleştirirseniz, database.xml dosyasında birleştirme çakışmaları yerine şunu görürsünüz:

$ git merge topic
Auto-merging database.xml
Merge made by recursive.

Bu durumda, database.xml dosyası, ilk başta sahip olduğunuz sürümde kalır.

scroll-to-top