¿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?

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.


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.


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.


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

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


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.


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

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


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) 

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

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

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.


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


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.


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.


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

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.

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


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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.