¿Cómo encuentro el git commit más reciente que modificó un archivo?

180

Quiero encontrar la confirmación más reciente que modificó un archivo fuente.

Puedo usar git blamepara ver todas las fechas de las confirmaciones por línea, pero es difícil ver exactamente qué confirmación fue la última en tocar el archivo.

¿Cómo puedo encontrar la última confirmación que tocó un archivo determinado en mi repositorio git?

Cory Klein
fuente

Respuestas:

230

git log admite mirar el historial de archivos (y directorios) específicos, por lo que puede llamarlo así:

git log my/file.c

Si realmente sólo desea listar el uno más reciente confirmación, por ejemplo, para utilizar en un script, utilice la -n 1opción:

git log -n 1 --pretty=format:%H -- my/file.c

--pretty=format:%hle dice git logque muestre solo el hash de confirmación. El --separador evita que el nombre del archivo se interprete como un nombre de confirmación, en caso de que sea ambiguo.

Jo Liss
fuente
12
Si desea saber la última vez que se modificó un archivo sin importar la rama, puede considerar todas las ramas agregando la --allopción.
KC
44

Si solo desea encontrar la confirmación más reciente, entonces no desea git-log, desea git-rev-list, que enumera los objetos de confirmación que cambian ese archivo, en esa ruta de confirmación, comenzando con el más reciente (cronológicamente). Simplemente pon:

git rev-list -1 <commit> <filename>

Porque git-rev-listen su caso, solo suministra:

  • El número de confirmaciones para incluir, o -1 solo para el más reciente,
  • La rama (o id de confirmación) para comenzar a mirar hacia atrás, HEAD si ya está en ella o --todos si desea todas las confirmaciones conocidas, y
  • La ruta relativa a su archivo.

Esto solo devuelve la ID de confirmación más reciente en la rama actual para alterar ese archivo, por ejemplo: 215095e2e338525be0baeeebdf66bfbb304e7270

Para un ejemplo más complejo, puede usar nombres de etiquetas e incluso referencias remotas e incluir nombres de ruta relativos con comodines, por ejemplo:

git rev-list origin/user/bob/testbranch -1 src/bfiles/*.txt

... Lo que te diría cuál fue el cambio más reciente en la coincidencia de comodines en la historia de esa rama. Las opciones para la lista de revoluciones son extremas, es uno de los comandos de plomería más importantes, por lo que puede incluir o excluir cualquier criterio que pueda imaginar.

Por supuesto, consulte la página del manual git-rev-list (1) .

Michael Erickson
fuente
Realmente no explicaste por qué usar git-loges inferior.
Piotr Dobrogost
77
No diría inferior, solo que proporciona información extraña por defecto. git-rev-list solo devuelve la ID de confirmación, que es lo que desea si va a alimentar la respuesta en un script u otro proceso de automatización. git-log devuelve información sobre los commits seleccionados, primero usando git-rev-list para recopilar los identificadores de commit, luego recolectando información sobre cada commit. Si solo va a filtrar la información de confirmación y usar los identificadores, entonces puede usar git-rev-list en primer lugar. Como el registro se basa en la lista de revoluciones, toma la mayoría de los mismos parámetros de filtro.
Michael Erickson
3
git-logEs de porcelana, git-rev-listes de fontanería.
blitzen9872
27

Si desea obtener el hash de la última confirmación para modificar un conjunto específico de archivos (y desea evitar awk), puede usar:

git log -n 1 --pretty=format:%h -- <path>

Esto puede ser útil para obtener el hash de confirmación para usarlo posteriormente con git describe.

Por ejemplo (en caso de que sea útil para alguien) ...

Creo una identificación de versión actual considerando la última confirmación para cambiar cualquier archivo fuente (suponiendo que marque versiones con etiquetas como mycode-1.2.1):

COMMIT=$(git log -n 1 --pretty=format:%h -- *.c *.h)
if VN=$(git describe --always --abbrev=5 --match "mycode-*" $COMMIT 2>/dev/null) &&
case "$VN" in
mycode-*)
    git update-index -q --refresh
    test -z "$(git diff-index --name-only HEAD *.c *.h)" ||
    VN="$VN-mod" ;;
*) VN="mycode-unknown-g$VN" ;;
esac
then
    continue
else
VN="mycode-unknown"
fi

Esto produce identificadores como:

  • mycode-1.2.1 - cuando el estado actual de los archivos de origen corresponde a una versión etiquetada
  • mycode-1.2.1-g3k7s2 - cuando el estado actual de los archivos de origen corresponde a la confirmación después de una versión etiquetada
  • mycode-1.2.1-g3k7s2-mod - cuando se ha modificado el estado actual de los archivos fuente desde la última confirmación después de una versión etiquetada
  • mycode-unknown - cuando aún no se ha creado una etiqueta de versión
TheBamf
fuente
55
$VNparece una especie de pesadilla SVN muertos vivientes
ThorSummoner
10

No estoy seguro de si esto es lo que quieres, pero si haces una git log <thefile>para obtener las confirmaciones que alteraron ese archivo. Puedes elegir el más alto. Debería ser el que estás buscando.

Noufal Ibrahim
fuente
44
si usa git log -n1 -- <thefile>(o canaliza la salida a head -1si desea desperdiciar recursos) no tiene que elegir manualmente la línea superior (vea la respuesta de Jo Liss )
Tobias Kienzler
44
Buen punto. Creo que también puede omitir -ny usar -1directamente.
Noufal Ibrahim
3

Para obtener solo la referencia en una línea, intente:

git log -n1 --oneline <path> | awk '{print $1;}'
multiplicación rápida
fuente
2

Una vez que tenga la identificación SHA de la confirmación que desea ver usando git log FILENAME, debería poder hacer git show SHA_ID_HERElo que hizo para esa confirmación en particular. Ni siquiera necesita ingresar la identificación completa; Los primeros 6 caracteres deberían ser suficientes.

Joe
fuente
44
eso es un poco más de lo que pidió el OP, pero para su información, puede combinar esto en una sola línea:git show $(git log -1 --pretty="%H" -- FILENAME)
Tobias Kienzler