Wie kann ich den Hash für das aktuelle Commit in Git abrufen?

1934

Ich möchte (vorerst) die Möglichkeit behalten, Git-Änderungssätze mit in TFS gespeicherten Workitems zu verknüpfen.

Ich habe bereits ein Tool geschrieben (mit einem Hook von Git), mit dem ich Workitemidentifier in die Nachricht eines Git-Änderungssatzes einfügen kann.

Ich möchte jedoch auch die Kennung des Git-Commits (den Hash) in einem benutzerdefinierten TFS-Workitem-Feld speichern. Auf diese Weise kann ich ein Workitem in TFS untersuchen und feststellen, welche Git-Änderungssätze dem Workitem zugeordnet sind.

Wie kann ich den Hash einfach aus dem aktuellen Commit von Git abrufen?

Sardaukar
quelle

Antworten:

2810

Verwenden Sie beispielsweise einfach git-rev-parse , um eine beliebige erweiterte Objektreferenz in SHA-1 umzuwandeln

git rev-parse HEAD

oder

git rev-parse --verify HEAD

Nebenbemerkung: Wenn Sie Referenzen ( Zweige und Tags ) in SHA-1 umwandeln möchten, gibt esgit show-refundgit for-each-ref.

Jakub Narębski
quelle
81
--verifyimpliziert, dass:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Linus Unnebäck
648
git rev-parse --short HEADGibt die Kurzversion des Hash zurück, nur für den Fall, dass sich jemand wundert.
Thane Brimhall
54
Zusätzlich zu , was gesagt Thane, können Sie auch eine bestimmte Länge addieren --short, wie --short=12eine bestimmte Anzahl von Stellen aus dem Hash zu bekommen.
Tyson Phalp
32
@TysonPhalp: --short=Nist ungefähr minimale Anzahl von Ziffern; git verwendet eine größere Anzahl von Ziffern, wenn eine verkürzte nicht von einer verkürzten anderen Festschreibung zu unterscheiden wäre. Versuchen Sie es zB git rev-parse --short=2 HEADoder git log --oneline --abbrev=2.
Jakub Narębski
36
Zusätzlich zu dem, was Thane, Tyson und Jakub gesagt haben, können Sie den vollständigen Hash drucken, aber die Hexits hervorheben, die erforderlich sind, um das Commit-Blau mitgit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz
423

Wenn Sie nur den verkürzten Hash möchten:

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

Darüber hinaus ist die Verwendung von% H ein weiterer Weg, um den langen Hash zu erhalten.

aus der Kultur
quelle
107
Oder es scheint, als würde das Hinzufügen von --short zum obigen Befehl rev-parse funktionieren.
Outofculture
15
Ich denke, git logist Porzellan und git rev-parseist Sanitär.
Amedee Van Gasse
Einer der Vorteile dieser Methode besteht darin, dass die Kurzversion des Hashs mit der richtigen Länge zurückgegeben wird, die an die Hash-Kollisionen angepasst ist, die bei größeren Repos auftreten. Zumindest in neueren Versionen von git.
Ilia Sidorenko
4
Dies ist eine schlechte / falsche Vorgehensweise, da diese Methode Ihnen den falschen Hash liefert, wenn Sie einen abgetrennten Kopf haben. Wenn zum Beispiel das aktuelle Commit 12ab34 ist ... und das vorherige Commit 33aa44 war ... dann, wenn ich 'git checkout 33aa44' mache und dann Ihren Befehl ausführe, erhalte ich immer noch 12ab34 zurück ... obwohl mein Kopf tatsächlich zeigt bis 33aa44 ...
theQuestionMan
3
@theQuestionMan Ich erlebe das von Ihnen beschriebene Verhalten nicht. git checkout 33aa44; git log -n 1gibt mir 33aa44. Welche Version von Git verwenden Sie?
Outofculture
150

Eine andere, die Git Log verwendet:

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

Es ist dem von @outofculture sehr ähnlich, wenn auch etwas kürzer.

Paul Pladijs
quelle
Und das Ergebnis ist nicht in einfachen Anführungszeichen.
Crokusek
5
Dies ist die richtige Antwort, da sie auch dann funktioniert, wenn Sie stattdessen ein bestimmtes Commit auschecken HEAD.
Parsa
1
@Parsa: Beim Auschecken eines bestimmten Commits wird HEADauf dieses Commit verwiesen und nicht auf einen benannten Zweig, der als losgelöster Kopf bezeichnet wird .
ChristofSenn
124

Um die volle SHA zu erhalten:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

So erhalten Sie die verkürzte Version:

$ git rev-parse --short HEAD
cbf1b9a
Alexander
quelle
Wenn zwei git commitHashes benötigt werden, z. B. einer von dem branch, mit dem Sie gerade arbeiten, und a master branch, können Sie ihn auch verwenden, git rev-parse FETCH_HEADwenn Sie den Hash für den benötigen, den master commitSie mergein Ihre aktuelle Version eingegeben haben branch. zB wenn Sie branches masterund feature/new-featurefür ein bestimmtes Repo haben, während feature/new-featureSie es verwenden könnten git fetch origin master && git merge FETCH_HEADund dann, git rev-parse --short FETCH_HEADwenn Sie den commitHash von dem benötigen, den masterSie gerade mergefür alle Skripte eingegeben haben, die Sie möglicherweise haben.
EVAL
72

Der Vollständigkeit halber, da noch niemand darauf hingewiesen hat. .git/refs/heads/masterist eine Datei, die nur eine Zeile enthält: den Hash des letzten Commits master. Sie können es also einfach von dort aus lesen.

Oder als Befehl:

cat .git/refs/heads/master

Aktualisieren:

Beachten Sie, dass git jetzt das Speichern einiger Head-Refs in der Pack-Ref-Datei anstatt als Datei im Ordner / refs / Heads / unterstützt. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html

Deestan
quelle
10
Dies setzt voraus, dass der aktuelle Zweig ist master, was nicht unbedingt wahr ist.
Gavrie
12
Tatsächlich. Deshalb habe ich ausdrücklich gesagt, dass dies für ist master.
Deestan
20
.git/HEADZeigt normalerweise auf einen Schiedsrichter. Wenn Sie einen SHA1 darin haben, befinden Sie sich im Modus mit losgelöstem Kopf.
eckes
8
Dies ist im Vergleich zu anderen Ansätzen nicht sehr robust, insbesondere weil davon ausgegangen wird, dass es ein .gitUnterverzeichnis gibt, was nicht unbedingt der Fall ist. Siehe die --separate-git-dirFlagge in der git initManpage.
Jub0bs
16
+1 weil du manchmal nicht willst, dass die ausführbare Git-Datei installiert wird (z. B. in deiner Docker-Datei)
wim
50

Hash festlegen

git show -s --format=%H

Abgekürzter Commit-Hash

git show -s --format=%h

Klicken Sie hier für weitere git showBeispiele.

ecwpz91
quelle
50

Das gibt es immer git describeauch. Standardmäßig gibt es Ihnen -

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75
John Tyree
quelle
18
Git description gibt den ersten TAG zurück, der von einem Commit erreichbar ist. Wie hilft mir das, die SHA zu bekommen?
Sardaukar
42
Ich mag git describe --long --dirty --abbrev=10 --tagses, wenn ich 7.2.0.Final-447-g65bf4ef2d4nach dem 7.2.0.Final-Tag 447 Commits bekomme und die ersten 10 Digests des globalen SHA-1 am aktuellen HEAD "65bf4ef2d4" sind. Dies ist sehr gut für Versionszeichenfolgen. Mit --long werden immer die Anzahl (-0-) und der Hash hinzugefügt, auch wenn das Tag genau übereinstimmt.
eckes
14
Wenn keine Tags vorhanden sind, git describe --alwayswird "eindeutig abgekürztes Festschreibungsobjekt als Fallback angezeigt"
Ronny Andersson,
Ich benutze git describe --tags --first-parent --abbrev=11 --long --dirty --always. Die --alwaysOption bedeutet, dass ein Ergebnis (Hash) bereitgestellt wird, auch wenn keine Tags vorhanden sind. Dies --first-parentbedeutet, dass es nicht durch Zusammenführungs-Commits verwirrt wird und nur Elementen im aktuellen Zweig folgt. Beachten Sie auch, dass dies an das Ergebnis --dirtyangehängt wird -dirty, wenn der aktuelle Zweig nicht festgeschriebene Änderungen aufweist.
Ingyhere
30

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

Robert Munteanu
quelle
3
Bei git-rev-list geht es darum, eine Liste von Festschreibungsobjekten zu generieren. Es ist git-rev-parse, den Objektnamen (z. B. HEAD) in SHA-1 zu übersetzen
Jakub Narębski
21

Wenn Sie den Hash während eines Skripts in einer Variablen speichern müssen, können Sie ihn verwenden

last_commit=$(git rev-parse HEAD)

Oder wenn Sie nur die ersten 10 Zeichen möchten (wie es github.com tut)

last_commit=$(git rev-parse HEAD | cut -c1-10) 
Henk
quelle
26
Es gibt auch die --shortoder --short=numberParameter zu git rev-parse; keine Notwendigkeit, ein Rohr zu verwenden und cut.
Julian D.
15

Wenn Sie den super-hackigen Weg wollen, es zu tun:

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

Grundsätzlich speichert git die Position von HEAD in .git / HEAD in der Form ref: {path from .git}. Dieser Befehl liest das aus, schneidet das "ref:" ab und liest die Datei aus, auf die er zeigt.

Dies wird natürlich im Modus mit losgelöstem Kopf fehlschlagen, da HEAD nicht "ref: ..." ist, sondern der Hash selbst - aber Sie wissen, ich glaube nicht, dass Sie so viel Intelligenz in Ihrem Bash erwarten -Liner. Wenn Sie nicht glauben, dass Semikolons schummeln ...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH
Fordi
quelle
1
Keine Notwendigkeit, Git zu installieren, ich mag es. (Mein Docker Build Image hat kein Git)
Helin Wang
auch nützlich, weil Sie dies leicht von außerhalb des Git Repo
ausführen können
Ich habe dies zu einem Skript für meinen lokalen Computer formalisiert. Dann dachte ich, hey: Die Implementierung, die ich vorgenommen habe, ist so einfach, dass sie zeigt, wie ein nicht verwandtes Problem gelöst werden kann (Argumente in rohen POSIX-Shell-Skripten ohne externe Programme analysieren), aber komplex genug, um ein wenig Abwechslung zu bieten und die meisten davon auszunutzen Merkmale von sh. Eine halbe Stunde Dokumentationskommentare später, und hier ist eine Zusammenfassung: gist.github.com/Fordi/29b8d6d1ef1662b306bfc2bd99151b07
Fordi
Als ich es mir ansah, machte ich eine umfangreichere Version, um Git und SVN zu erkennen und die Git-Hash / SVN-Revision zu greifen. Diesmal keine saubere Zeichenfolge, aber einfach über die Befehlszeile zu analysieren und als Versions-Tag verwendbar: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi
14

Der prägnanteste Weg, den ich kenne:

git show --pretty=%h 

Wenn Sie eine bestimmte Anzahl von Ziffern des Hashs möchten, können Sie Folgendes hinzufügen:

--abbrev=n
Brian Peterson
quelle
14
Dies funktioniert zwar technisch, git showwird jedoch als Porzellanbefehl bezeichnet (dh dem Benutzer zugewandt) und sollte daher nicht in Skripten verwendet werden, da sich die Ausgabe ändern kann. Die Antwort oben ( git rev-parse --short HEAD) sollte stattdessen verwendet werden.
jm3
4
@ jm3 das ist rückwärts. "Porzellan" -Befehle haben stabile Ausgaben, die für Skripte vorgesehen sind. Suche git help shownach porcelain.
John Tyree
2
@JohnTyree Dies ist ein verwirrendes Thema, aber jm3 hatte Recht: Porzellanbefehle sollen nicht analysiert, sondern lesbar sein. Wenn Sie einen Porzellanbefehl in einem Skript verwenden müssen und ein stabiles Format haben möchten, gibt es manchmal (zum Beispiel mit Git-Status, Push und Schuld) eine Option, die genau das tut. Leider wird diese Option aufgerufen --porcelain, weshalb dies verwirrend ist. Sie können die Details in dieser großartigen Antwort von VonC finden
Fabio sagt Reinstate Monica
1
Lieber Gott, der beschlossen hat, diese Option zu nennen - Porzellan Ich möchte sie finden und ... Oh, warte, ich müsste Git verwenden, um sie zu finden, egal
Britton Kerin
14

Vielleicht möchten Sie einen Alias, damit Sie sich nicht an alle raffinierten Details erinnern müssen. Nachdem Sie einen der folgenden Schritte ausgeführt haben, können Sie einfach Folgendes eingeben:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Nach der akzeptierten Antwort gibt es zwei Möglichkeiten, dies einzurichten:

1) Lehren Sie Git auf explizite Weise, indem Sie die globale Konfiguration bearbeiten (meine ursprüngliche Antwort):

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

2) Oder wenn Sie eine Verknüpfung möchten, um Git eine Verknüpfung beizubringen, wie kürzlich von Adrien kommentiert:

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

Verwenden Sie ab hier, git lastcommitum den Hash des letzten Commits anzuzeigen.

Miraculixx
quelle
3
Adrien de Sentenac merkt an, dass Sie anstatt die Git-Konfigurationsdatei manuell zu bearbeiten, einfach git config --global alias.lastcommit "rev-parse HEAD"
Folgendes
12

Ich brauchte etwas anderes: Zeigen Sie den vollständigen sha1 des Commits an, aber fügen Sie am Ende ein Sternchen hinzu, wenn das Arbeitsverzeichnis nicht sauber ist. Sofern ich nicht mehrere Befehle verwenden wollte, funktioniert keine der Optionen in den vorherigen Antworten.

Hier ist der eine Liner, der dies tut:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Ergebnis:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Erläuterung: Beschreibt (unter Verwendung von mit Anmerkungen versehenen Tags) das aktuelle Commit, jedoch nur mit Tags, die "NOT A TAG" enthalten. Da Tags keine Leerzeichen enthalten können, stimmt dies nie mit einem Tag überein. Da ein Ergebnis angezeigt werden soll --always, wird der Befehl mit der vollständigen ( --abbrev=0) sha1 des Commits zurückgesetzt und ein Sternchen angehängt, wenn sich das Arbeitsverzeichnis befindet --dirty.

Wenn Sie das Sternchen nicht anhängen möchten, funktioniert dies wie alle anderen Befehle in den vorherigen Antworten:
git describe --always --abbrev=0 --match "NOT A TAG"
Ergebnis:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe

Rado
quelle
Danke, stolpere nur darüber und es erspart mir das eine oder andere Echo dafür :)
hakre
1
Es funktioniert bei mir ohne die --match "NOT A TAG". Getestet in Git 2.18.0 sowie 2.7.4. Gibt es eine Situation, in der dieses Argument benötigt wird?
Thomas
@Thomas Es funktioniert nicht, wenn Sie irgendwo im Verlauf des aktuellen Commits ein mit Anmerkungen versehenes Tag haben. Das gefälschte Tag stellt sicher, dass der Befehl description kein Tag verwendet, um das Commit zu beschreiben.
Rado
8
git show-ref --head --hash head

Wenn Sie jedoch Geschwindigkeit anstreben , ist dies der von Deestan erwähnte Ansatz

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

ist deutlich schneller als jede andere hier aufgeführte Methode.

Dennis
quelle
show-refMir scheint die beste Option für Scripting zu sein, da es sich um ein Sanitär - Befehl und damit garantiert (oder zumindest sehr wahrscheinlich) ist stabil in zukünftigen Versionen bleiben: andere Antworten verwenden rev-parse, show, describe, oder log, die alle Porzellan - Befehle sind. In Fällen, in denen Geschwindigkeit nicht von entscheidender Bedeutung ist, gilt der Hinweis auf der show-refManpage: "Die Verwendung dieses Dienstprogramms wird empfohlen, um direkt auf Dateien im Verzeichnis .git zuzugreifen."
Pont
6

Hier ist ein Einzeiler in der Bash-Shell, der direkt aus Git-Dateien liest:

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

Sie müssen den obigen Befehl in Ihrem Git-Stammordner ausführen.

Diese Methode kann nützlich sein, wenn Sie Repository-Dateien haben, der gitBefehl jedoch nicht installiert wurde.

Wenn dies nicht funktioniert, überprüfen Sie im .git/refs/headsOrdner, welche Art von Köpfen Sie haben.

Kenorb
quelle
5

Fügen Sie in Ihrem Home-Verzeichnis in der Datei ".gitconfig" Folgendes hinzu

[alias]
sha = rev-parse HEAD

dann haben Sie einen leichteren Befehl, an den Sie sich erinnern können:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600
jo_
quelle
3

Führen Sie bei git bash einfach $ git log -1 aus

Sie werden sehen, diese Zeilen folgen Ihrem Befehl.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.
Batty
quelle
0

Hier ist eine weitere Implementierung mit direktem Zugriff:

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

Dies funktioniert auch über http, was für lokale Paketarchive nützlich ist (ich weiß: Für öffentliche Websites wird nicht empfohlen, das Verzeichnis .git zugänglich zu machen):

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

Hier ist eine andere Möglichkeit, dies zu tun :)

git log | grep -o '\w\{8,\}' | head -n 1
Marcelo Lazaroni
quelle
0
cat .git/HEAD

Beispielausgabe:

ref: refs/heads/master

Analysieren Sie es:

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

Wenn Sie Windows haben, können Sie wsl.exe verwenden:

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

Ausgabe:

refs/heads/master

Dieser Wert kann später zum Auschecken verwendet werden, zeigt jedoch auf seine SHA. Um es so zu machen, dass es auf den aktuellen Zweig mit seinem Namen verweist, gehen Sie wie folgt vor:

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

Ausgänge:

master

Sergei
quelle