Git et permet referir-te a un únic commit, un conjunt de commits, o un rang de commits de diverses maneres. No són necessàriament òbvies però són útils de conèixer.
Pots referir-te a qualsevol commit individual pel seu hash SHA-1 complet de 40 caràcters, però també hi ha maneres més amigables per referir-te als commits. Aquesta secció descriu les diverses maneres en què pots referir-te a qualsevol commit.
Git és prou intel·ligent per esbrinar a quin commit et refereixes si proporciones els primers caràcters del hash SHA-1, sempre que aquest hash parcial tingui almenys quatre caràcters de llarg i sigui no ambigu; és a dir, cap altre objecte a la base de dades d’objectes pot tenir un hash que comenci amb el mateix prefix.
Per exemple, per examinar un commit específic on saps que vas afegir certa funcionalitat, primer podries executar el comandament git log per localitzar el commit:
$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Jan 2 18:32:33 2009 -0800
Fix refs handling, add gc auto, update tests
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Merge commit 'phedders/rdocs'
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 14:58:32 2008 -0800
Add some blame and merge stuffEn aquest cas, suposem que t’interessa el commit el hash del qual comença amb 1c002dd…. Pots inspeccionar aquest commit amb qualsevol de les següents variants del comandament git show (assumint que les versions més curtes són no ambigües):
$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002dGit pot esbrinar una abreviatura curta i única per als teus valors SHA-1. Si passes --abbrev-commit al comandament git log, la sortida utilitzarà valors més curts però els mantindrà únics; per defecte utilitza set caràcters però els fa més llargs si és necessari per mantenir el SHA-1 no ambigu:
$ git log --abbrev-commit --pretty=oneline
ca82a6d Change the version number
085bb3b Remove unnecessary test code
a11bef0 Initial commitGeneralment, vuit a deu caràcters són més que suficients per ser únics dins d’un projecte. Per exemple, a partir de febrer de 2019, el nucli de Linux (que és un projecte força gran) té més de 875.000 commits i gairebé set milions d’objectes a la seva base de dades d’objectes, sense dos objectes els SHA-1 dels quals siguin idèntics als primers 12 caràcters.
|
Note
|
UNA NOTA CURTA SOBRE SHA-1
Moltes persones es preocupen en algun moment que, per casualitat, tinguin dos objectes diferents al seu repositori que es mapegin al mateix valor SHA-1. Què llavors? Si per casualitat confirmes un objecte que es mapeja al mateix valor SHA-1 que un objecte anterior diferent al teu repositori, Git veurà l’objecte anterior ja a la teva base de dades Git, assumirà que ja estava escrit i simplement el reutilitzarà. Si intentes revisar aquell objecte una altra vegada en algun moment, sempre obtindràs les dades del primer objecte. No obstant això, has de ser conscient de com de ridículament improbable és aquest escenari. La signatura SHA-1 és de 20 bytes o 160 bits. El nombre d’objectes aleatòriament mapejats necessaris per assegurar una probabilitat del 50% d’una sola col·lisió és d’uns 2^80 (la fórmula per determinar la probabilitat de col·lisió és Aquí tens un exemple per donar-te una idea del que caldria per obtenir una col·lisió SHA-1. Si tots els 6.500 milions d’humans a la Terra estiguessin programant, i cada segon, cadascú produís codi equivalent a tot l’historial del nucli de Linux (6,5 milions d’objectes Git) i l’empenyés a un enorme repositori Git, trigaria aproximadament 2 anys fins que aquell repositori contingués suficients objectes per tenir una probabilitat del 50% d’una sola col·lisió SHA-1. Així, una col·lisió orgànica SHA-1 és menys probable que cada membre del teu equip de programació sigui atacat i mort per llops en incidents no relacionats la mateixa nit. Si hi dediques diversos milers de dòlars en potència de computació, és possible sintetitzar dos fitxers amb el mateix hash, com es va provar a https://shattered.io/ el febrer de 2017. Git s’està movent cap a l’ús de SHA256 com a algoritme de hash per defecte, que és molt més resistent als atacs de col·lisió, i té codi en lloc per ajudar a mitigar aquest atac (tot i que no pot eliminar-lo completament). |
Una manera directa de referir-se a un commit particular és si és el commit al cap d’una branca; en aquest cas, simplement pots utilitzar el nom de la branca en qualsevol comandament Git que esperi una referència a un commit. Per exemple, si vols examinar l’últim objecte commit en una branca, els següents comandaments són equivalents, assumint que la branca topic1 apunta al commit ca82a6d…:
$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1Si vols veure a quin SHA-1 específic apunta una branca, o si vols veure a què es redueixen aquests exemples en termes de SHA-1, pots utilitzar una eina de fontaneria de Git anomenada rev-parse. Pots veure ch10-git-internals.asc per a més informació sobre eines de fontaneria; bàsicament, rev-parse existeix per a operacions de nivell inferior i no està dissenyat per ser utilitzat en operacions diàries. No obstant això, pot ser útil algunes vegades quan necessites veure què està passant realment. Aquí pots executar rev-parse a la teva branca.
$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949Una de les coses que Git fa en segon pla mentre treballes és mantenir un “reflog” — un registre de on han estat les teves referències HEAD i de branca durant els últims mesos.
Pots veure el teu reflog utilitzant git reflog:
$ git reflog
734713b HEAD@{0}: commit: Fix refs handling, add gc auto, update tests
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by the 'recursive' strategy.
1c002dd HEAD@{2}: commit: Add some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEADCada vegada que la punta de la teva branca s’actualitza per qualsevol motiu, Git emmagatzema aquesta informació per a tu en aquest historial temporal. Pots utilitzar les teves dades de reflog per referir-te a commits més antics també. Per exemple, si vols veure el cinquè valor anterior de HEAD del teu repositori, pots utilitzar la referència @{5} que veus a la sortida de reflog:
$ git show HEAD@{5}També pots utilitzar aquesta sintaxi per veure on estava una branca fa una quantitat específica de temps. Per exemple, per veure on estava la teva branca master ahir, pots escriure:
$ git show master@{yesterday}Això et mostraria on estava la punta de la teva branca master ahir. Aquesta tècnica només funciona per a dades que encara estan al teu reflog, així que no la pots utilitzar per buscar commits més antics de fa uns mesos.
Per veure la informació de reflog formatada com la sortida de git log, pots executar git log -g:
$ git log -g master
commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: commit: Fix refs handling, add gc auto, update tests
Author: Scott Chacon <schacon@gmail.com>
Date: Fri Jan 2 18:32:33 2009 -0800
Fix refs handling, add gc auto, update tests
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Merge commit 'phedders/rdocs'És important tenir en compte que la informació de reflog és estrictament local: és un registre només del que has fet tu al teu repositori. Les referències no seran les mateixes en una còpia del repositori d’una altra persona; a més, just després de clonar un repositori per primera vegada, tindràs un reflog buit, ja que encara no ha ocorregut cap activitat al teu repositori. Executar git show HEAD@{2.months.ago} et mostrarà el commit coincident només si vas clonar el projecte fa almenys dos mesos; si el vas clonar més recentment, només veuràs el teu primer commit local.
|
Tip
|
Pensa en el reflog com la versió de Git de l’historial de la shell
Si tens un antecedent UNIX o Linux, pots pensar en el reflog com la versió de Git de l’historial de la shell, la qual cosa emfatitza que el que hi ha és clarament rellevant només per a tu i la teva "sessió", i no té res a veure amb ningú altre que pugui estar treballant a la mateixa màquina. |
|
Note
|
Escapant claus en PowerShell
En utilitzar PowerShell, les claus com $ git show HEAD@{0} # no funcionarà
$ git show HEAD@`{0`} # correcte
$ git show "HEAD@{0}" # correcte |
L’altra manera principal d’especificar un commit és a través dels seus ancestres. Si col·loques un ^ (accent circumflex) al final d’una referència, Git la resol per significar el pare d’aquell commit. Suposem que mires l’historial del teu projecte:
$ git log --pretty=format:'%h %s' --graph
* 734713b Fix refs handling, add gc auto, update tests
* d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd Add some blame and merge stuff
|/
* 1c36188 Ignore *.gem
* 9b29157 Add open3_detach to gemspec file listLlavors, pots veure el commit anterior especificant HEAD^, que significa "el pare de HEAD":
$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 15:08:43 2008 -0800
Merge commit 'phedders/rdocs'|
Note
|
Escapant l’accent circumflex a Windows
A Windows a $ git show HEAD^ # no funcionarà a Windows
$ git show HEAD^^ # correcte
$ git show "HEAD^" # correcte |
També pots especificar un número després del ^ per identificar quin pare vols; per exemple, d921970^2 significa "el segon pare de d921970". Aquesta sintaxi és útil només per a commits de fusió, que tenen més d’un pare: el primer pare d’un commit de fusió és de la branca en què estaves quan vas fusionar (freqüentment master), mentre que el segon pare d’un commit de fusió és de la branca que es va fusionar (digues, topic):
$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date: Thu Dec 11 14:58:32 2008 -0800
Add some blame and merge stuff
$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Paul Hedderly <paul+git@mjr.org>
Date: Wed Dec 10 22:22:03 2008 +0000
Some rdoc changesL’altra especificació principal d’ancestres és la ~ (tilde). Això també es refereix al primer pare, així que HEAD~ i HEAD^ són equivalents. La diferència es fa evident quan especifiques un número. HEAD~2 significa "el primer pare del primer pare", o "el besavi" — travessa els primers pares el nombre de vegades que especifiques. Per exemple, a l’historial llistat anteriorment, HEAD~3 seria:
$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date: Fri Nov 7 13:47:59 2008 -0500
Ignore *.gemAixò també es pot escriure HEAD^, que de nou és el primer pare del primer pare del primer pare:
$ git show HEAD~~~
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date: Fri Nov 7 13:47:59 2008 -0500
Ignore *.gemTambé pots combinar aquestes sintaxis: pots obtenir el segon pare de la referència anterior (assumint que era un commit de fusió) utilitzant HEAD~3^2, i així successivament.
Ara que pots especificar commits individuals, veiem com especificar rangs de commits. Això és particularment útil per gestionar les teves branques: si tens moltes branques, pots utilitzar especificacions de rang per respondre preguntes com "Quin treball hi ha en aquesta branca que encara no he fusionat a la meva branca principal?"
L’especificació de rang més comuna és la sintaxi de doble punt. Això bàsicament demana a Git que resolgui un rang de commits que són accessibles des d’un commit però no ho són des d’un altre. Per exemple, suposem que tens un historial de commits que sembla com a Historial d’exemple per a la selecció de rang.
Suposem que vols veure què hi ha a la teva branca experiment que encara no s’ha fusionat a la teva branca master. Pots demanar a Git que et mostri un registre només d’aquests commits amb master..experiment — això significa "tots els commits accessibles des d'`experiment` que no ho són des de `master`". Per a la brevetat i claredat en aquests exemples, s’utilitzen les lletres dels objectes commit del diagrama en lloc de la sortida real del registre en l’ordre en què es mostrarien:
$ git log master..experiment
D
CSi, d’altra banda, vols veure l’oposat: tots els commits a master que no estan a experiment, pots invertir els noms de les branques. experiment..master et mostra tot el que hi ha a master no accessible des d'`experiment`:
$ git log experiment..master
F
EAixò és útil si vols mantenir la branca experiment actualitzada i previsualitzar el que estàs a punt de fusionar. Una altra utilització freqüent d’aquesta sintaxi és veure el que estàs a punt d’enviar a un repositori remot:
$ git log origin/master..HEADAquest comandament et mostra qualsevol commit a la teva branca actual que no està a la branca master al teu remot origin. Si executes un git push i la teva branca actual està seguint origin/master, els commits llistats per git log origin/master..HEAD són els commits que es transferiran al servidor. També pots deixar de banda un costat de la sintaxi per fer que Git assumeixi HEAD. Per exemple, pots obtenir els mateixos resultats que a l’exemple anterior escrivint git log origin/master.. — Git substitueix HEAD si falta un costat.
La sintaxi de doble punt és útil com a taquigrafia, però potser vols especificar més de dues branques per indicar la teva revisió, com veure quins commits hi ha a qualsevol de diverses branques que no estan a la branca en què ets actualment. Git et permet fer això utilitzant el caràcter ^ o --not abans de qualsevol referència de la qual no vulguis veure commits accessibles. Així, els següents tres comandaments són equivalents:
$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refAAixò és bo perquè amb aquesta sintaxi pots especificar més de dues referències a la teva consulta, cosa que no pots fer amb la sintaxi de doble punt. Per exemple, si vols veure tots els commits que són accessibles des de refA o refB però no des de refC, pots utilitzar qualsevol d’aquests:
$ git log refA refB ^refC
$ git log refA refB --not refCAixò crea un sistema de consulta de revisions molt potent que t’ajudarà a esbrinar què hi ha a les teves branques.
L’última sintaxi principal de selecció de rang és la sintaxi de triple punt, que especifica tots els commits que són accessibles per qualsevol de dues referències però no per ambdues. Mira enrere l’historial de commits d’exemple a Historial d’exemple per a la selecció de rang. Si vols veure què hi ha a master o experiment però no a cap referència comuna, pots executar:
$ git log master...experiment
F
E
D
CUn altre cop, això et dona una sortida de log normal però et mostra només la informació de commit per a aquests quatre commits, apareixent en l’ordre tradicional de data de commit.
Un interruptor comú per utilitzar amb el comandament log en aquest cas és --left-right, que et mostra de quin costat del rang és cada commit. Això ajuda a fer la sortida més útil:
$ git log --left-right master...experiment
< F
< E
> D
> CAmb aquestes eines, pots fer que Git sàpiga molt més fàcilment quin commit o commits vols inspeccionar.
