¿Cómo recuperar el hash para el commit actual en Git?

1934

Me gustaría conservar (por ahora) la capacidad de vincular los conjuntos de cambios de Git a los elementos de trabajo almacenados en TFS.

Ya escribí una herramienta (usando un gancho de Git) en la que puedo inyectar identificadores de trabajo en el mensaje de un conjunto de cambios de Git.

Sin embargo, también me gustaría almacenar el identificador de la confirmación Git (el hash) en un campo de elemento de trabajo TFS personalizado. De esta forma puedo examinar un elemento de trabajo en TFS y ver qué conjuntos de cambios de Git están asociados con el elemento de trabajo.

¿Cómo puedo recuperar fácilmente el hash del commit actual de Git?

Sardaukar
fuente

Respuestas:

2810

Para convertir la referencia arbitraria de objetos extendidos en SHA-1, use simplemente git-rev-parse , por ejemplo

git rev-parse HEAD

o

git rev-parse --verify HEAD

Nota al margen: si desea convertir las referencias ( ramas y etiquetas ) en SHA-1, haygit show-refygit for-each-ref.

Jakub Narębski
fuente
81
--verifyimplica que:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Linus Unnebäck
648
git rev-parse --short HEADdevuelve la versión corta del hash, por si alguien se lo preguntaba.
Thane Brimhall
55
Agregando a lo que dijo Thane, también se puede añadir una longitud específica de --short, como --short=12, para obtener un número específico de dígitos a partir del hash.
Tyson Phalp
32
@ TysonPhalp: --short=Nse trata de un número mínimo de dígitos; git usa un mayor número de dígitos si acortado uno sería indistinguible de otro acortado acortar. Prueba, por ejemplo, git rev-parse --short=2 HEADo git log --oneline --abbrev=2.
Jakub Narębski
36
Además de lo que dijeron Thane, Tyson y Jakub, puedes imprimir el hash completo, pero resaltar los hexits necesarios para identificar el commit azul congit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz
424

Si solo quieres el hash acortado:

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

Además, usar% H es otra forma de obtener el hash largo.

fuera de la cultura
fuente
107
O, al parecer, agregar --short al comando rev-parse anterior parece funcionar.
cultura
15
Creo que git loges de porcelana y git rev-parsees fontanería.
Amedee Van Gasse
Uno de los beneficios de este método es que devolverá la versión corta del hash con la longitud correcta ajustada a las colisiones de hash que ocurren para repositorios más grandes. Al menos en versiones recientes de git.
Ilia Sidorenko
44
Esta es una forma incorrecta / incorrecta de hacerlo porque este método le dará el hash incorrecto si tiene una cabeza separada. Por ejemplo, si el commit actual es 12ab34 ... y el commit anterior fue 33aa44 ... entonces si hago 'git checkout 33aa44' y luego ejecuto su comando, todavía regresaré 12ab34 ... a pesar de que mi cabeza realmente apunte a 33aa44 ...
theQuestionMan
3
@theQuestionMan No experimento el comportamiento que describe; git checkout 33aa44; git log -n 1me da 33aa44. ¿Qué versión de git estás usando?
cultura
150

Otro, usando git log:

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

Es muy similar al de @outofculture, aunque un poco más corto.

Paul Pladijs
fuente
Y el resultado no está entre comillas simples.
crokusek
55
Esta es la respuesta correcta, ya que funciona incluso si comprueba una confirmación específica en lugar de HEAD.
Parsa
1
@Parsa: al verificar HEADpuntos de confirmación específicos para esta confirmación en lugar de una rama con nombre conocida como cabeza separada .
ChristofSenn
125

Para obtener el SHA completo:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

Para obtener la versión abreviada:

$ git rev-parse --short HEAD
cbf1b9a
Alejandro
fuente
Si git commitse necesitan dos valores hash, como uno del branchque está trabajando actualmente y a master branch, también podría usarlo git rev-parse FETCH_HEADsi necesita el valor hash para el master commitque utilizó mergeen su actual branch. por ejemplo, si tiene branches mastery feature/new-featurepara un repositorio determinado, mientras está encendido feature/new-feature, puede usarlo git fetch origin master && git merge FETCH_HEADy luego git rev-parse --short FETCH_HEADsi necesita el commithash del masterque acaba de mergeacceder para cualquier script que pueda tener.
EVAL
72

Para completar, ya que nadie lo ha sugerido todavía. .git/refs/heads/masteres un archivo que contiene solo una línea: el hash de la última confirmación master. Entonces puedes leerlo desde allí.

O, como comando:

cat .git/refs/heads/master

Actualizar:

Tenga en cuenta que git ahora admite el almacenamiento de algunas referencias de cabeza en el archivo pack-ref en lugar de como un archivo en la carpeta / refs / heads /. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html

Deestan
fuente
10
Esto supone que la rama actual es master, lo cual no es necesariamente cierto.
gavrie
12
En efecto. Por eso dije explícitamente que esto es para master.
Deestan
20
.git/HEADnormalmente apunta a una referencia, si tiene un SHA1 allí, está en modo de cabezal separado.
Eckes
8
Esto no es muy sólido en comparación con otros enfoques, en particular porque supone que hay un .gitsubdirectorio, que no es necesariamente el caso. Vea la --separate-git-dirbandera en la git initpágina del manual.
jub0bs
16
+1 porque a veces no quieres instalar el ejecutable git (por ejemplo, en tu Dockerfile)
wim
50

Cometer hash

git show -s --format=%H

Comportamiento abreviado hash

git show -s --format=%h

Haga clic aquí para más git showejemplos.

ecwpz91
fuente
50

Siempre hay git describetambién. Por defecto te da -

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75
John Tyree
fuente
18
Git describe devuelve el primer TAG accesible desde una confirmación. ¿Cómo me ayuda esto a obtener el SHA?
Sardaukar
42
Me gusta git describe --long --dirty --abbrev=10 --tags, me dará algo así como 7.2.0.Final-447-g65bf4ef2d4447 confirmaciones después de la etiqueta 7.2.0.Final y los primeros 10 diálogos del SHA-1 global en el HEAD actual son "65bf4ef2d4". Esto es muy bueno para las cadenas de versión. Con --long siempre agregará el conteo (-0-) y el hash, incluso si la etiqueta coincide exactamente.
Eckes
14
Si no existen etiquetas, entonces git describe --always"mostrará un objeto de confirmación abreviado de forma única como reserva"
Ronny Andersson
Yo uso git describe --tags --first-parent --abbrev=11 --long --dirty --always. La --alwaysopción significa que proporciona un resultado (hash) incluso si no hay etiquetas. Esto --first-parentsignifica que no se confunde con las confirmaciones de fusión y solo sigue los elementos de la rama actual. Tenga en cuenta también que se --dirtyagregará -dirtyal resultado si la rama actual tiene cambios no confirmados.
ingyhere
30

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

Robert Munteanu
fuente
3
git-rev-list se trata de generar una lista de objetos de confirmación; es git-rev-parse traducir el nombre del objeto (por ejemplo, HEAD) a SHA-1
Jakub Narębski
21

Si necesita almacenar el hash en una variable durante un script, puede usar

last_commit=$(git rev-parse HEAD)

O, si solo quieres los primeros 10 caracteres (como lo hace github.com)

last_commit=$(git rev-parse HEAD | cut -c1-10) 
Henk
fuente
26
También hay los parámetros --shorto --short=numberpara git rev-parse; No es necesario utilizar una tubería y cut.
Julian D.
15

Si quieres la forma súper hacky de hacerlo:

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

Básicamente, git almacena la ubicación de HEAD en .git / HEAD, en el formulario ref: {path from .git}. Este comando lee eso, corta el "ref:" y lee cualquier archivo al que apunte.

Esto, por supuesto, fallará en el modo de cabeza separada, ya que HEAD no será "ref: ...", sino el hash en sí mismo, pero ya sabes, no creo que esperes tanta inteligencia en tu golpe. -liners. Sin embargo, si no crees que el punto y coma son trampas ...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH
Fordi
fuente
1
no es necesario instalar git, me gusta. (la imagen de construcción de mi ventana acoplable no tiene git)
Helin Wang
también es útil porque puedes ejecutar esto fácilmente desde fuera del repositorio de git
samaspin
Formalicé esto en un script para mi máquina local. Entonces, pensé, oye: la implementación que hice es lo suficientemente simple como para ilustrar cómo resolver un problema no relacionado (análisis de argumentos en scripts de shell POSIX sin programas externos), pero lo suficientemente complejo como para proporcionar una pequeña variación y explotar la mayoría de los características de sh. Media hora de comentarios de documentación más tarde, y aquí hay un resumen
Fordi
Mirándolo, hice una versión más extensa para detectar Git y SVN, y tomar la revisión git hash / svn. Esta vez no es una cadena limpia, pero se analiza fácilmente la línea de comandos y se puede usar como etiqueta de versión: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi
14

La forma más sucinta que conozco:

git show --pretty=%h 

Si desea un número específico de dígitos del hash, puede agregar:

--abbrev=n
Brian Peterson
fuente
14
Si bien esto funciona técnicamente, git showes lo que se conoce como un comando de porcelana (es decir, orientado al usuario), por lo que no debe usarse en scripts porque su salida está sujeta a cambios. La respuesta anterior ( git rev-parse --short HEAD) debe usarse en su lugar.
jm3
44
@ jm3 eso está al revés. Los comandos "Porcelana" tienen salidas estables destinadas a scripts. Buscar git help showpara porcelain.
John Tyree
2
@JohnTyree Este es un tema confuso, pero jm3 tenía razón: los comandos de porcelana no están destinados a ser analizados, sino a ser legibles por humanos. En caso de que necesite usar un comando de porcelana en un script y desee tener un formato estable, a veces hay (por ejemplo, con el estado de git, push y culpa) una opción que hace exactamente eso. Desafortunadamente, esa opción se llama --porcelain, por lo que esto es confuso. Puedes encontrar los detalles en esta gran respuesta de VonC
Fabio dice que
1
querido dios que decidió nombrar esa opción: porcelana, quiero encontrarlos y ... oh, espera, necesitaría usar git para encontrarlos sin pensar
Britton Kerin
14

Quizás desee un alias para no tener que recordar todos los detalles ingeniosos. Después de realizar uno de los pasos a continuación, simplemente podrá escribir:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Después de la respuesta aceptada , aquí hay dos formas de configurar esto:

1) Enseñe a git de manera explícita editando la configuración global (mi respuesta original):

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

2) O si le gusta un atajo para enseñarle un atajo, como comentó recientemente Adrien:

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

De aquí en adelante, use git lastcommitpara mostrar el hash del último commit.

miraculixx
fuente
3
Adrien de Sentenac señala que en lugar de editar manualmente el archivo de configuración de git, simplemente podría hacer:git config --global alias.lastcommit "rev-parse HEAD"
cgmb
12

Necesitaba algo un poco más diferente: mostrar el sha1 completo de la confirmación, pero agregue un asterisco al final si el directorio de trabajo no está limpio. A menos que quiera usar varios comandos, ninguna de las opciones en las respuestas anteriores funciona.

Aquí está el único revestimiento que hace:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Resultado:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Explicación: describe (usando etiquetas anotadas) el commit actual, pero solo con etiquetas que contienen "NOT A TAG". Como las etiquetas no pueden tener espacios, esto nunca coincide con una etiqueta y dado que queremos mostrar un resultado --always, el comando retrocede mostrando el --abbrev=0sha1 completo ( ) de la confirmación y agrega un asterisco si el directorio de trabajo lo es --dirty.

Si no desea agregar el asterisco, esto funciona como todos los otros comandos en las respuestas anteriores:
git describe --always --abbrev=0 --match "NOT A TAG"
Resultado:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe

Rado
fuente
Gracias, solo tropecé con él y me
ahorró
1
Funciona para mí sin el --match "NOT A TAG". Probado en git 2.18.0 y 2.7.4. ¿Hay alguna situación en la que se necesite este argumento?
Thomas
@Thomas no funcionará si tiene una etiqueta anotada en cualquier parte del historial del compromiso actual. La etiqueta falsa se asegura de que el comando describe no use una etiqueta para describir la confirmación,
Rado
8
git show-ref --head --hash head

Si vas por la velocidad, el enfoque mencionado por Deestan

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

es significativamente más rápido que cualquier otro método enumerado aquí hasta ahora.

Dennis
fuente
show-refme parece ser la mejor opción para secuencias de comandos, ya que es un comando de plomería y así garantizado (o al menos muy probable) se mantenga estable en futuras versiones: otras respuestas utilizan rev-parse, show, describe, o log, que son todos los comandos de porcelana. Y en los casos en que la velocidad no es esencial, se show-refaplica la nota de la página de manual: 'Se recomienda el uso de esta utilidad a favor de acceder directamente a los archivos en el directorio .git'.
Pont
6

Aquí hay una línea en el shell Bash que usa lectura directa de archivos git:

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

Debe ejecutar el comando anterior en su carpeta raíz git.

Este método puede ser útil cuando tiene archivos de repositorio, pero el gitcomando no se ha instalado.

Si no funciona, verifique en la .git/refs/headscarpeta qué tipo de cabezas tiene presente.

kenorb
fuente
5

en su directorio de inicio en el archivo ".gitconfig" agregue lo siguiente

[alias]
sha = rev-parse HEAD

entonces tendrás un comando más fácil de recordar:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600
jo_
fuente
3

En git bash, simplemente ejecute $ git log -1

verá, estas líneas siguiendo su comando.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.
Chalado
fuente
0

Aquí hay otra implementación de acceso directo:

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

Esto también funciona sobre http, que es útil para archivos de paquetes locales (lo sé: para sitios web públicos no se recomienda hacer accesible el directorio .git):

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

Aquí hay otra forma de hacerlo :)

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

Salida de ejemplo:

ref: refs/heads/master

Analízalo:

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

Si tiene Windows, entonces puede considerar usar wsl.exe:

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

Salida:

refs/heads/master

Este valor puede usarse para git checkout más tarde, pero se convierte en apuntando a su SHA. Para que apunte a la rama actual actual por su nombre, haga lo siguiente:

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

Salidas:

master

Sergei
fuente