Git
Chapters ▾ 2nd Edition

8.2 Prilagoditev Gita - Atributi Git

Atributi Git

Nekatere od teh nastavitev lahko določimo tudi za določeno pot, tako da Git uporablja te nastavitve le za poddirektorij ali podmnožico datotek. Te nastavitve, specifične za pot, se imenujejo atributi Git in jih nastavimo v datoteki .gitattributes v enem od vaših direktorijev (običajno v korenski mapi vašega projekta) ali v datoteki .git/info/attributes, če ne želite, da se datoteka z atributi dodaja v vaš projekt.

Z uporabo atributov lahko npr. določimo različne strategije združevanja za posamezne datoteke ali direktorije v svojem projektu, povemo Gitu, kako primerjati datoteke, ki niso besedilne, ali pa omogočimo filtriranje vsebine, preden jo shranimo, ali pridobimo iz Gita. V tem razdelku se boste naučili o nekaterih atributih, ki jih lahko nastavite na vaših poteh v vašem projektu Git, in videli boste nekaj primerov uporabe te lastnosti v praksi.

Binarne datoteke

Eden izmed trikov, za katerega lahko uporabite atribute Git, je naročiti Gitu, katere datoteke so binarne (v primerih, ko morda ne more ugotoviti sam) in mu dati posebnih navodil o tem, kako s takimi datotekami ravnati. Na primer, nekatere besedilne datoteke so lahko strojno generirane in jih ni mogoče razlikovati, medtem ko je mogoče nekatere binarne datoteke razlikovati. Pokazali vam bomo, kako Gitu naročiti, katera vrsta datoteke je katera.

Prepoznavanje binarnih datotek

Nekatere datoteke so videti kot besedilne datoteke, vendar v resnici predstavljajo binarne podatke. Na primer, projekti Xcode na macOS vsebujejo datoteko, ki se konča s .pbxproj, kar je v bistvu nabor podatkov JSON (besedilni format podatkov JavaScript) zapisanih na disk s strani IDE, ki beleži vaše nastavitve gradnje in podobno. Čeprav je tehnično gledano besedilna datoteka (ker je vse UTF-8), je ne želite tako obravnavati, saj gre v resnici za lahko podatkovno bazo — vsebine ni mogoče združiti, če jo spremenita dva človeka, in razlike sprememb običajno niso uporabne. Datoteka je namenjena strojnemu branju. V bistvu jo želite obravnavati kot binarno datoteko.

Da povežete Git, da obravnava vse datoteke pbxproj kot binarne podatke, dodajte naslednjo vrstico v vašo datoteko .gitattributes:

*.pbxproj binary

Zdaj Git ne bo poskušal pretvoriti ali popraviti težav CRLF; prav tako ne bo poskušal izračunati ali izpisati razlike za spremembe v tej datoteki, ko zaženete git show ali git diff v vašem projektu.

Prikazovanje razlik binarnih datotek

Funkcionalnost atributov Git lahko uporabite tudi za primerjavo binarnih datotek. To dosežete tako, da Gitu poveste, kako pretvoriti vaše binarne podatke v besedilno obliko, ki se lahko primerja preko normalne razlike sprememb.

Najprej boste to tehniko uporabili za reševanje enega najbolj nadležnih problemov, ki jih pozna človeštvo: nadzor različic dokumentov Microsoft Word. Če želite nadzorovati različice dokumentov Word, jih lahko postavite v repozitorij Git in jih občasno potrdite; ampak čemu je to uporabno? Če zaženete git diff na takšni datoteki, vidite nekaj takega:

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

Ni mogoče neposredno primerjati dveh različic, razen če ju izvlečete in ročno pregledate, kajne? Izkazalo se je, da lahko to storite precej dobro z uporabo atributov Git. V datoteko .gitattributes vstavite naslednjo vrstico:

*.docx diff=word

To sporoči Gitu, da se katera koli datoteka, ki ustreza tej zbirki znakov (.docx), pri prikazu razlike sprememb diff uporabi filter »word«. Kaj je filter »word«? Treba ga je nastaviti. V tem primeru boste nastavili Git, da uporabi program docx2txt za pretvorbo datotek Word v berljive besedilne datoteke, ki jih bo nato pravilno primerjal.

Najprej morate namestiti docx2txt; prenesete ga lahko s spletnega mesta https://sourceforge.net/projects/docx2txt. Sledite navodilom v datoteki INSTALL, da ga namestite na mesto, ki ga bo vaša lupina lahko našla. Nato boste napisali ovojni skript, ki bo pretvoril izhod v format, ki ga Git pričakuje. Ustvarite datoteko z imenom docx2txt, ki se nahaja v vaši poti, in dodajte naslednjo vsebino:

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

Ne pozabite uporabiti ukaza chmod a+x, da datoteki dodelite izvajalne pravice. Nazadnje lahko nastavite Git, da uporabi ta skript:

$ git config diff.word.textconv docx2txt

Zdaj Git ve, da mora, če poskuša narediti razliko med dvema posnetkoma in se datoteke končajo z .docx, te datoteke pognati skozi filter »word«, ki je določen kot program docx2txt. To učinkovito ustvari lepe besedilne različice vaših Wordovih datotek pred poskusom razlikovanja.

Tu je primer: Prvo poglavje te knjige je bilo pretvorjeno v format Word in je bilo potrjeno v repozitorij Git. Nato je bil dodan nov odstavek. Če zaženete git diff, vidite nekaj takega:

$ 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 nam uspešno in jedrnato sporoča, da smo dodali niz »Testing: 1, 2, 3.«, kar je pravilno. Ni popolno — spremembe oblikovanja tukaj ne bi bile prikazane — vendar zagotovo deluje.

Druga zanimiva težava, ki jo lahko rešite s tem načinom, se nanaša na razlike v slikovnih datotekah. En način za to je, da slikovne datoteke poganjamo skozi filter, ki iz njih izvleče informacije EXIF — metapodatke, ki so zapisani pri večini formatov slik. Če prenesete in namestite program exiftool, ga lahko uporabite za pretvorbo slik v besedilo o metapodatkih, tako da vam vsaj diff prikaže besedilno predstavitev vseh sprememb. V datoteko .gitattributes vstavite naslednjo vrstico:

*.png diff=exif

Nastavite Git, da uporabi to orodje:

$ git config diff.exif.textconv exiftool

Če zamenjate sliko v svojem projektu in poženete git diff, boste videli nekaj takega:

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

Enostavno lahko vidite, da so se velikost datoteke in dimenzije slike spremenile.

Razširitev ključnih besed

Stil razširjanja ključnih besed SVN ali CVS pogosto zahtevajo razvijalci, ki so navajeni teh sistemov. Glavni problem pri tem v Gitu je, da datoteke z informacijami o potrditvi ne morete spreminjati po tem, ko ste jih že potrdili, ker Git najprej preveri kontrolne vsote datoteke. Vendar pa lahko v datoteko vstavite besedilo, ko jo izpišete, in ga pred dodajanjem k potrditvi spet odstranite. Atributi Git vam ponujajo dva načina za to.

Najprej lahko samodejno vstavite kontrolno vsoto SHA-1 bloba v polje $Id$ v datoteki. Če to lastnost nastavite na datoteko ali sklop datotek, bo Git naslednjič, ko izvlečete tisto vejo, to polje nadomestil s SHA-1 bloba. Pomembno je opozoriti, da to ni SHA-1 potrditve, ampak SHA-1 samega bloba. V datoteko .gitattributes vnesite naslednjo vrstico:

*.txt ident

Testni datoteki dodajte referenco $Id$:

$ echo '$Id$' > test.txt

Naslednjič, ko boste izvlekli to datoteko, bo Git injiciral SHA-1 bloba:

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

Vendar pa je ta rezultat omejenega pomena. Če ste uporabljali zamenjavo ključnih besed v CVS ali Subversion, lahko vključite datumski žig — SHA-1 ni v veliko pomoč, ker je dokaj naključen in ga ni mogoče razlikovati po starosti le z gledanjem nanj.

Izkaže se, da lahko napišete lastna filtra za zamenjave v datotekah ob potrditvi/izvleku. Ta se imenujeta filtra »clean« in »smudge«. V datoteki .gitattributes lahko nastavite filter za določene poti in nato nastavite skripte, ki bodo obdelali datoteke, tik preden jih izvlečete (za »smudge« poglejte sliko Filter »smudge« se požene pri izvleku) in tik preden jih shranite (za »clean« poglejte sliko Filter »clean« se požene, ko so datoteke v področju priprave). Te filtre lahko nastavite, da naredijo vse vrste zabavnih stvari.

Filter »smudge« se požene pri izvleku
Slika 169. Filter »smudge« se požene pri izvleku
Filter »clean« se požene, ko so datoteke v področju priprave
Slika 170. Filter »clean« se požene, ko so datoteke v področju priprave

Izvirno sporočilo potrditve za to funkcionalnost podaja preprost primer, kako poganjati vse svoje izvorne datoteke C skozi program indent pred potrditvijo. Nastavite lahko atribute filtra v datoteki .gitattributes za filtriranje datotek \*.c s filtrom »indent«:

*.c filter=indent

Nato povejte Gitu, kaj filter »indent« naredi pri razmazovanju (angl. smudge) in čiščenju (angl. clean):

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

V tem primeru, ko shranite datoteke, ki se prilegajo *.c, bo Git te datoteke pred področjem priprave poslal skozi program indent in nato skozi program cat, preden jih znova izvleče nazaj na disk. Program cat v bistvu ne naredi ničesar: izpiše enake podatke, kot jih prejme. Ta kombinacija učinkovito filtrira vse izvorne datoteke C skozi indent pred potrjevanjem.

Še en zanimiv primer je vstavljanje ključne besede $Date$ v slogu RCS. Za pravilno izvedbo tega potrebujete majhen skript, ki vzame ime datoteke, ugotovi datum zadnje opravljene potrditve za ta projekt in vstavi datum v datoteko. Tu je kratek skript Ruby, ki to opravi:

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

Vse, kar skript naredi, je, da iz ukaza git log prebere zadnji datum potrditve in ga vstavi v vse nize $Date$ na stdin, nato pa izpiše rezultate — to bi moralo biti enostavno storiti v katerem koli jeziku, v katerem se najbolje počutite. Datoteko lahko poimenujete expand_date in jo postavite v svojo pot. Zdaj morate v Gitu nastaviti filter (poimenujte ga dater) in mu povedati, naj uporabi vaš filter expand_date za razmazovanje datotek pri izvleku. Za čiščenje tega na potrditvi boste uporabili regularni izraz Perl:

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

Ta del kode Perl odstrani vsebino niza $Date$, da se vrnete na izhodiščno stanje. Ko je filter pripravljen, ga lahko preizkusite z nastavitvijo atributa Git za datoteko, ki vključi nov filter, in ustvarite datoteko z vašo ključno besedo $Date$:

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

Če potrdite te spremembe in ponovno izvlečete datoteko, boste videli, da je bila beseda pravilno nadomeščena:

$ git add date_test.txt .gitattributes
$ git commit -m "Test 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$

Vidite, kako zmogljiva tehnika je lahko ta pristop za prilagojene aplikacije. Vendar morate biti previdni, saj se datoteka .gitattributes potrdi in se prenaša s projektom, medtem ko gonilnika (v tem primeru dater) ni, zato ne bo deloval povsod. Ko načrtujete te filtre, morate narediti, da elegantno odpovejo izvedbo in projekt bi moral še vedno pravilno delovati.

Izvoz vašega repozitorija

Podatki atributov v Gitu vam omogočajo tudi izvajanje zanimivih operacij pri izvozu arhiva vašega projekta.

export-ignore

Gitu lahko sporočite, naj ne izvozi določenih datotek ali direktorijev pri ustvarjanju arhiva. Če obstaja poddirektorij ali datoteka, ki je ne želite vključiti v svoj arhiv, vendar jo želite vključiti v svoj projekt, lahko take datoteke določite z atributom export-ignore.

Recimo, da imate nekaj testnih datotek v poddirektoriju test/, in da jih ni smiselno vključiti v izvoženo arhivsko datoteko vašega projekta. Dodati morate naslednjo vrstico v svojo datoteko z atributi Git:

test/ export-ignore

Zdaj, ko za ustvarjanje arhiva vašega projekta uporabite ukaz git archive, ta mapa ne bo vključena v arhiv.

export-subst

Pri izvozu datotek za nalaganje lahko na izbrane dele datotek, označene z atributom export-subst, uporabite oblikovanje in obdelavo razširitve ključnih besed, ki jih ponuja git log.

Na primer, če želite vključiti datoteko z imenom LAST_COMMIT v vaš projekt in imeti avtomatsko vstavljanje metapodatkov o zadnjem potrdilu vanj ob izvedbi git archive, lahko v datotekah .gitattributes in LAST_COMMIT nastavite nekaj takega:

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'

Ko poženete git archive, bo vsebina arhivirane datoteke videti nekako takole:

$ 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

Zamenjave lahko vključujejo na primer sporočilo o potrditvi in katerikoli git notes ali git log pa lahko opravi preprosto ovijanje besedil:

$ 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.

Dobljeni arhiv je primeren za delo nalaganja, vendar kot vsak izvoženi arhiv, ni primeren za nadaljnje razvojno delo.

Strategije združevanja

Atribute Git pa lahko tudi uporabite, da Gitu sporočite, naj za določene datoteke v svojem projektu uporabi različne strategije združevanja. Ena zelo uporabna možnost je, da Gitu sporočite, naj pri konfliktih ne poskuša združevati določenih datotek, ampak naj raje uporabi vašo stran združevanja pred drugimi.

To je koristno, če se je veja v vašem projektu razšla ali specializirala, vi pa želite združiti spremembe nazaj vanjo, hkrati pa želite prezreti določene datoteke. Recimo, da imate datoteko z nastavitvami podatkovne baze imenovano database.xml, ki se razlikuje v dveh vejah, in želite združiti spremembe iz druge veje, ne da bi pokvarili podatkovno datoteko. To lahko nastavite z atributom, kot je ta:

database.xml merge=ours

In nato definirate navidezno strategijo združevanja ours:

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

Če združite drugo vejo, boste videli nekaj takega, namesto da imate v datoteki database.xml konflikte združevanja:

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

V tem primeru ostane database.xml na katerikoli različici, ki ste jo prvotno imeli.

scroll-to-top