Come recuperare l'hash per il commit corrente in Git?


1934

Vorrei conservare (per ora) la possibilità di collegare i changeset Git ai workitem memorizzati in TFS.

Ho già scritto uno strumento (usando un hook di Git) in cui posso iniettare identificatori di lavoro nel messaggio di un changeset di Git.

Tuttavia, vorrei anche memorizzare l'identificatore del commit Git (l'hash) in un campo di lavoro TFS personalizzato. In questo modo posso esaminare un workitem in TFS e vedere quali cambiamenti Git sono associati al workitem.

Come posso recuperare facilmente l'hash dall'attuale commit da Git?

Risposte:


2810

Per trasformare il riferimento arbitrario di oggetti estesi in SHA-1 , ad esempio , utilizzare semplicemente git-rev-parse

git rev-parse HEAD

o

git rev-parse --verify HEAD

Sidenote: se vuoi trasformare riferimenti ( rami e tag ) in SHA-1, c'ègit show-refegit for-each-ref.


81
--verifyimplica che:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Linus Unnebäck,

648
git rev-parse --short HEADrestituisce la versione breve dell'hash, nel caso in cui qualcuno si chiedesse.
Thane Brimhall,

55
Aggiungendo ciò che Thane ha detto, puoi anche aggiungere una lunghezza specifica --short, ad esempio --short=12, per ottenere un numero specifico di cifre dall'hash.
Tyson Phalp,

32
@TysonPhalp: --short=Nindica un numero minimo di cifre; git usa un numero maggiore di cifre se una accorciata sarebbe indistinguibile da altre accorciate. Prova ad esempio git rev-parse --short=2 HEADo git log --oneline --abbrev=2.
Jakub Narębski,

36
Aggiungendo a quanto detto Thane, Tyson e Jakub, è possibile stampare l'hash completo, ma evidenziare gli esadecimi necessari per identificare il blu di commit congit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz

424

Se vuoi solo l'hash abbreviato:

git log --pretty=format:'%h' -n 1

Inoltre, usare% H è un altro modo per ottenere l'hash lungo.


107
O, a quanto pare, l'aggiunta di --short al comando rev-parse sopra sembra funzionare.
outofculture

15
Penso che git logsia in porcellana e git rev-parseidraulico.
Amedee Van Gasse,

Uno dei vantaggi di questo metodo è che restituirà la versione breve dell'hash con la giusta lunghezza adattata alle collisioni dell'hash che si verificano per repository più grandi. Almeno nelle ultime versioni di git.
Ilia Sidorenko,

4
Questo è un modo sbagliato / errato di farlo perché questo metodo ti darà l'hash sbagliato se hai una testa staccata. Ad esempio, se il commit corrente è 12ab34 ... e il commit precedente era 33aa44 ... quindi se eseguo "git checkout 33aa44" e quindi eseguo il comando, tornerò ancora 12ab34 ... nonostante la mia testa effettivamente punta a 33aa44 ...
theQuestionMan il

3
@theQuestionMan Non provo il comportamento che descrivi; git checkout 33aa44; git log -n 1mi dà 33aa44. Quale versione di Git stai usando?
outofculture

150

Un altro, usando git log:

git log -1 --format="%H"

È molto simile a @outofculture anche se un po 'più breve.


E il risultato non è a virgoletta singola.
crokusek,

5
Questa è la risposta corretta, poiché funziona anche se si esegue il checkout di un commit specifico anziché HEAD.
Parsa,

1
@Parsa: quando si verifica un commit specifico HEADpunta a questo commit piuttosto che una branche nominata è conosciuta come testa distaccata .
ChristofSenn,

125

Per ottenere lo SHA completo:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

Per ottenere la versione abbreviata:

$ git rev-parse --short HEAD
cbf1b9a

Se git commitsono necessari due hash, come uno con branchcui stai attualmente lavorando e un master branch, puoi anche usarlo git rev-parse FETCH_HEADse hai bisogno dell'hash per quello master commitche hai mergeinserito nella tua corrente branch. ad es. se hai branches mastere feature/new-featureper un determinato repository., mentre in quel feature/new-featuremomento potresti usare git fetch origin master && git merge FETCH_HEADe poi git rev-parse --short FETCH_HEADse ti serviva l' commithash da masterte che hai appena mergeinserito per qualsiasi script che potresti avere.
EVAL

72

Per completezza, dal momento che nessuno lo ha ancora suggerito. .git/refs/heads/masterè un file che contiene solo una riga: l'hash dell'ultimo commit su master. Quindi puoi leggerlo da lì.

Oppure, come comando:

cat .git/refs/heads/master

Aggiornare:

Si noti che git ora supporta la memorizzazione di alcuni riferimenti head nel file pack-ref anziché come file nella cartella / refs / heads /. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html


10
Questo presuppone che sia l'attuale ramo master, il che non è necessariamente vero.
Gavrie,

12
Infatti. Ecco perché ho detto esplicitamente che è per master.
Deestan,

20
.git/HEADin genere punta a un riferimento, se hai uno SHA1 lì, sei in modalità testa staccata.
Controlla il

8
Questo non è molto robusto rispetto ad altri approcci, in particolare perché presuppone che esista una .gitsottodirectory, il che non è necessariamente il caso. Vedi la --separate-git-dirbandiera nella git initpagina man.
jub0bs,

16
Because1 perché a volte non vuoi installare eseguibile git (es. Nel tuo Dockerfile)
wim

50

Commettere l'hash

git show -s --format=%H

Hash di commit abbreviato

git show -s --format=%h

Clicca qui per altri git showesempi.


50

C'è sempre git describeanche. Di default ti dà -

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75

18
Git descrive restituisce il primo TAG raggiungibile da un commit. In che modo questo mi aiuta a ottenere lo SHA?
Sardaukar,

42
Mi piace git describe --long --dirty --abbrev=10 --tags, mi darà qualcosa di simile a 7.2.0.Final-447-g65bf4ef2d4447 commit dopo il tag 7.2.0.Final e i primi 10 digest dello SHA-1 globale nell'attuale HEAD sono "65bf4ef2d4". Questo è molto buono per le stringhe di versione. Con --long aggiungerà sempre il conteggio (-0-) e l'hash, anche se il tag sembra corrispondere esattamente.
Verifica il

14
Se non esistono tag git describe --always, "mostrerà l'oggetto commit abbreviato in modo univoco come fallback"
Ronny Andersson,

Io uso git describe --tags --first-parent --abbrev=11 --long --dirty --always. L' --alwaysopzione indica che fornisce un risultato (hash) anche se non ci sono tag. Ciò --first-parentsignifica che non viene confuso dai commit di unione e segue solo gli elementi nel ramo corrente. Si noti inoltre che --dirtyverrà aggiunto -dirtyal risultato se il ramo corrente ha modifiche senza commit.
ingyhere

30

Uso git rev-list --max-count=1 HEAD


3
git-rev-list riguarda la generazione di un elenco di oggetti commit; è git-rev-parse tradurre il nome dell'oggetto (ad esempio HEAD) in SHA-1
Jakub Narębski

21

Se è necessario memorizzare l'hash in una variabile durante uno script, è possibile utilizzare

last_commit=$(git rev-parse HEAD)

Oppure, se vuoi solo i primi 10 caratteri (come fa github.com)

last_commit=$(git rev-parse HEAD | cut -c1-10) 

26
Ci sono anche i parametri --shorto --short=numbera git rev-parse; non c'è bisogno di usare una pipa e cut.
Julian D.,

15

Se vuoi il modo super-hacky per farlo:

cat .git/`cat .git/HEAD | cut -d \  -f 2`

Fondamentalmente, git memorizza la posizione di HEAD in .git / HEAD, nel modulo ref: {path from .git}. Questo comando lo legge, taglia "ref:" e legge qualunque file abbia indicato.

Questo, ovviamente, fallirà in modalità a testa staccata, poiché HEAD non sarà "ref: ...", ma l'hash stesso - ma sai, non penso che ti aspetti che tanta intelligenza nella tua bash -liners. Se non pensi che i punti e virgola stiano tradendo, però ...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH

1
non c'è bisogno di installare git, mi piace. (l'immagine della mia finestra mobile non ha git)
Helin Wang,

utile anche perché puoi eseguirlo facilmente dall'esterno del repository git
samaspin il

Ho formalizzato questo in una sceneggiatura per la mia macchina locale. Quindi, ho pensato, ehi: l'implementazione che ho fatto è abbastanza semplice da illustrare come risolvere un problema non correlato (analisi degli argomenti negli script shell POSIX grezzi senza programmi esterni), ma abbastanza complesso da fornire una piccola variazione e sfruttare la maggior parte dei caratteristiche di sh. Mezz'ora di commenti sulla documentazione più avanti, ed eccone un riassunto
Fordi,

Guardandolo, ho realizzato una versione più ampia per rilevare Git e SVN e afferrare la revisione hash / svn di git. Questa volta non una stringa pulita, ma facilmente analizzabile dalla riga di comando e utilizzabile come tag di versione: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi

14

Il modo più conciso che conosco:

git show --pretty=%h 

Se vuoi un numero specifico di cifre dell'hash puoi aggiungere:

--abbrev=n

14
Mentre questo funziona tecnicamente, git showè ciò che è noto come un comando di porcellana (cioè rivolto verso l'utente), e quindi non dovrebbe essere usato negli script perché il suo output è soggetto a modifiche. git rev-parse --short HEADInvece dovrebbe essere usata la risposta sopra ( ).
jm3

4
@ jm3 che è al contrario. I comandi "Porcelain" hanno output stabili destinati agli script. Cerca git help showper porcelain.
John Tyree,

2
@JohnTyree Questo è un argomento confuso, ma jm3 aveva ragione: i comandi di porcellana non sono pensati per essere analizzati, ma piuttosto per essere leggibili dall'uomo. Nel caso in cui sia necessario utilizzare un comando di porcellana in uno script e si desidera avere un formato stabile, a volte (ad esempio con stato git, push e biasimo) è presente un'opzione che fa proprio questo. Sfortunatamente, questa opzione è chiamata --porcelain, motivo per cui questo è confuso. Puoi trovare i dettagli in questa grande risposta di VonC
Fabio dice

1
caro dio che ha deciso di nominare quell'opzione - porcellana voglio trovarli e ... oh aspetta che dovrei usare git per trovarli non importa
Britton Kerin

14

Forse vuoi un alias in modo da non dover ricordare tutti i dettagli eleganti. Dopo aver eseguito uno dei passaggi seguenti, sarai in grado di digitare semplicemente:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Seguendo la risposta accettata , ecco due modi per impostare questo:

1) Insegna a git in modo esplicito modificando la configurazione globale (la mia risposta originale):

 # open the git config editor
 $ git config --global --edit
 # in the alias section, add
 ...
 [alias]
   lastcommit = rev-parse HEAD
 ...

2) O se ti piace una scorciatoia per insegnare a git una scorciatoia, come recentemente commentato da Adrien:

$ git config --global alias.lastcommit "rev-parse HEAD"

Da qui in poi, usa git lastcommitper mostrare l'hash dell'ultimo commit.


3
Adrien de Sentenac nota che invece di modificare manualmente il file git config, potresti semplicemente fare:git config --global alias.lastcommit "rev-parse HEAD"
cgmb

12

Avevo bisogno di qualcosa di un po 'più diverso: visualizzare l'intero sha1 del commit, ma aggiungere un asterisco alla fine se la directory di lavoro non è pulita. A meno che non volessi usare più comandi, nessuna delle opzioni nelle risposte precedenti funziona.

Ecco quello che fa:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Risultato:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Spiegazione: descrive (utilizzando tag annotati) il commit corrente, ma solo con tag contenenti "NOT A TAG". Poiché i tag non possono avere spazi, questo non corrisponde mai a un tag e poiché vogliamo mostrare un risultato --always, il comando ricade indietro visualizzando l'intero ( --abbrev=0) sha1 del commit e aggiunge un asterisco se la directory di lavoro è --dirty.

Se non si desidera aggiungere l'asterisco, funziona come tutti gli altri comandi nelle risposte precedenti:
git describe --always --abbrev=0 --match "NOT A TAG"
Risultato:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe


Grazie, inciampando e mi risparmia l'una o l'altra eco per quello :)
hakre

1
Funziona per me senza il --match "NOT A TAG". Testato in git 2.18.0 e 2.7.4. C'è qualche situazione in cui è necessario questo argomento?
Thomas,

@Thomas non funzionerà se hai un tag annotato in qualsiasi punto della cronologia del commit corrente. Il tag falso si assicura che il comando descrivi non usi un tag per descrivere il commit,
Rado

8
git show-ref --head --hash head

Se stai andando per la velocità, l'approccio citato da Deestan

cat .git/refs/heads/<branch-name>

è significativamente più veloce di qualsiasi altro metodo elencato qui finora.


show-refmi sembra essere l'opzione migliore per lo scripting, dal momento che è un comando idraulico e così garantito (o almeno molto probabile) rimanere stabile nelle versioni future: altre risposte usano rev-parse, show, describe, o log, che sono tutti i comandi di porcellana. E nei casi in cui la velocità non è essenziale, si show-refapplica la nota della manpage: "L'uso di questa utility è incoraggiato a favore dell'accesso diretto ai file nella directory .git".
Pont

6

Ecco una riga nella shell Bash usando la lettura diretta dai file git:

(head=($(<.git/HEAD)); cat .git/${head[1]})

Devi eseguire il comando sopra nella cartella principale di git.

Questo metodo può essere utile quando hai file di repository, ma il gitcomando non è stato installato.

Se non funziona, controlla nella .git/refs/headscartella che tipo di teste hai presente.


5

nella tua home-dir nel file ".gitconfig" aggiungi quanto segue

[alias]
sha = rev-parse HEAD

allora avrai un comando più facile da ricordare:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600

3

Su git bash, esegui semplicemente $ git log -1

vedrai che queste righe seguono il tuo comando.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.

0

Ecco un'altra implementazione ad accesso diretto:

head="$(cat ".git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(cat ".git/${head#ref: }")"
done

Questo funziona anche su http che è utile per gli archivi di pacchetti locali (lo so: per i siti Web pubblici non è consigliabile rendere accessibile la directory .git):

head="$(curl -s "$baseurl/.git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(curl -s "$baseurl/.git/${head#ref: }")"
done


0
cat .git/HEAD

Esempio di output:

ref: refs/heads/master

Analizzalo:

cat .git/HEAD | sed "s/^.\+ \(.\+\)$/\1/g"

Se hai Windows, puoi prendere in considerazione l'utilizzo di wsl.exe:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g"

Produzione:

refs/heads/master

Questo valore può essere utilizzato per eseguire il checkout in un secondo momento, ma diventa puntato al suo SHA. Per farlo puntare all'attuale ramo attuale con il suo nome fai:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g" | wsl sed "s/^refs\///g" | wsl sed "s/^heads\///g"

Uscite:

master

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.