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.
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.
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.
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.
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.
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.
Podatki atributov v Gitu vam omogočajo tudi izvajanje zanimivih operacij pri izvozu arhiva vašega projekta.
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.
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.
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.