Culpa de Git: ¿compromisos previos?

391

¿Es posible ver quién editó una línea específica antes de la confirmación informada por git blame, como un historial de confirmaciones para una línea determinada?

Por ejemplo, ejecuto lo siguiente (en el excelente uncrustifyproyecto):

$ git blame -L10,+1 src/options.cpp
^fe25b6d (Ben Gardner 2009-10-17 13:13:55 -0500 10) #include "prototypes.h"

¿Cómo puedo averiguar quién editó esa línea antes de confirmar fe25b6d? ¿Y quién lo editó antes de ese compromiso?

Sedate Alien
fuente
77
si la razón por la que está buscando confirmaciones anteriores son los cambios en el espacio en blanco, use la -wopción También hay -Mpara el código movido / copiado
brita_
Para buscar todas las confirmaciones que involucran una palabra dada, vea mi script a continuación
VonC
Aquí hay un script útil para agregar esta funcionalidad en github greasyfork.org/en/scripts/…
Aaron Hoffman
3
No estoy seguro de cómo se veía Github cuando @AaronHoffman publicó, pero ahora es mucho más fácil culpar, y culpar a las versiones anteriores , en Github .
ruffin

Respuestas:

389
git blame -L 10,+1 fe25b6d^ -- src/options.cpp

Puede especificar una revisión para git blame para mirar hacia atrás a partir de (en lugar del valor predeterminado de HEAD); fe25b6d^es el padre de fe25b6d.

Ámbar
fuente
107
¿Puedes obtener un historial completo sin tener que volver a ingresar el comando varias veces con diferentes hashes?
Anders Zommarin
13
No creo que Git tenga una forma integrada de obtener todas las culpas que tocaron un número de línea (lo que tiene sentido, ya que una línea dada puede no tener un número de línea consistente en todo el historial de un archivo debido a inserciones y eliminaciones de líneas).
Ámbar
17
@Amber: Estoy bastante seguro de que tienes razón de que la función no existe, pero parece que podría implementarse ingenuamente, simplemente haciendo lo que haría un humano: culparlo una vez, tomar la información reportada, culpar a eso , y así.
Cascabel
15
git gui hace que sea bastante fácil verificar el historial de una línea ya que se puede hacer clic en las versiones.
Zitrax
55
@shadyabhi --se usa comúnmente como un separador en los argumentos de la línea de comandos; en el caso de Git, generalmente se usa para separar cosas como los hash de confirmación de una lista de nombres de archivos.
Ámbar
192

Puede usar git log -L para ver la evolución de un rango de líneas.

Por ejemplo :

git log -L 15,23:filename.txt

significa "rastrear la evolución de las líneas 15 a 23 en el archivo llamado filename.txt".

Navneet
fuente
12
Esta es una respuesta sólida y aborda la pregunta anterior de Anders Zommarin sobre cómo ver los cambios en líneas específicas a lo largo del tiempo.
bigtex777
44
FYI: git log -L <start>, <end>: <file> requiere Git 1.8.4+ ver: git-scm.com/docs/git-log#git-log--Lltstartgtltendgtltfilegt para opciones de sintaxis
Neon
30

La respuesta de Amber es correcta pero no me pareció clara; La sintaxis es:

git blame {commit_id} -- {path/to/file}

Nota: --se utiliza para separar el árbol-ish sha1 de las rutas de archivos relativas. 1

Por ejemplo:

git blame master -- index.html

¡Crédito completo a Amber por saber todas las cosas! :)

ThorSummoner
fuente
1
Estoy de acuerdo con tu sentimiento Sin embargo, el sistema de comentarios está demasiado restringido para presentar toda la información con claridad. He agregado el contenido de esta respuesta en un comentario; Sin embargo, insisto en dejar esta respuesta es un lugar para facilitar el acceso.
ThorSummoner
1
Debería ser una publicación separada o una edición. Me gusta esto como una respuesta separada.
Flimm
27

Es posible que desee ver:

git gui blame <filename>

Le ofrece una buena visualización gráfica de los cambios, como "culpa git", pero con enlaces en los que se puede hacer clic por línea, para pasar a confirmaciones anteriores. Pase el mouse sobre los enlaces para obtener una ventana emergente con detalles de confirmación. No mis créditos ... lo encontré aquí:

http://zsoltfabok.com/blog/2012/02/git-blame-line-history/

git guies una interfaz gráfica Tcl / Tc para git. Sin ningún otro parámetro, inicia una aplicación gráfica bastante simple pero útil para confirmar archivos, trozos o incluso líneas simples y otros comandos similares como enmendar, revertir, empujar ... Es parte del conjunto de aplicaciones git. En Windows está incluido en el instalador. En debian, no sé sobre otros sistemas * nix, debe instalarse por separado:

apt-get install git-gui

De los documentos:

https://git-scm.com/docs/git-gui

DESCRIPCIÓN

Una interfaz gráfica de usuario basada en Tcl / Tk para Git. git gui se enfoca en permitir a los usuarios realizar cambios en su repositorio al hacer nuevos commits, enmendar los existentes, crear sucursales, realizar fusiones locales y buscar / empujar a repositorios remotos.

A diferencia de gitk, git gui se enfoca en la generación de confirmación y la anotación de un solo archivo y no muestra el historial del proyecto. Sin embargo, proporciona acciones de menú para iniciar una sesión de gitk desde git gui.

Se sabe que git gui funciona en todos los sistemas UNIX populares, Mac OS X y Windows (tanto en Cygwin como en MSYS). En la medida de lo posible, se siguen las pautas específicas de la interfaz de usuario del sistema operativo, lo que hace que git gui sea una interfaz bastante nativa para los usuarios.

Comandos

culpa

Inicie un visor de culpa en el archivo especificado en la versión dada (o directorio de trabajo si no se especifica).

navegador

Inicie un navegador de árbol que muestre todos los archivos en la confirmación especificada. Los archivos seleccionados a través del navegador se abren en el visor de culpas.

citool

Inicie git gui y haga arreglos para hacer exactamente un commit antes de salir y regresar al shell. La interfaz se limita a solo realizar acciones, lo que reduce ligeramente el tiempo de inicio de la aplicación y simplifica la barra de menú.

versión

Muestra la versión actual de git gui.

Holger Böhnke
fuente
A mi no me funciona. Puedo hacer clic en el cambio en la línea dada, pero eso solo cambia la vista para que sea para ese compromiso, y la línea actual ahora se muestra como this: pero ¿cómo veo la versión anterior de la línea y cuándo se agregó?
BeeOnRope
Este es el caso de un uso que conozco donde GUI Git es la mejor solución
cambunctious
17

Sobre la base de la respuesta anterior, este bash one-liner debería darte lo que estás buscando. Muestra el historial de culpa de git para una línea particular de un archivo particular, a través de las últimas 5 revisiones:

LINE=10 FILE=src/options.cpp REVS=5; for commit in $(git rev-list -n $REVS HEAD $FILE); do git blame -n -L$LINE,+1 $commit -- $FILE; done

En la salida de este comando, es posible que vea el contenido del cambio de línea, o el número de línea que se muestra puede incluso cambiar, para una confirmación particular.

Esto a menudo indica que la línea se agregó por primera vez, después de esa confirmación en particular. También podría indicar que la línea se movió desde otra parte del archivo.

Will Sheppard
fuente
55
Tenga en cuenta que estas son las últimas revisiones de $ REVS en las que cambió $ FILE, en lugar de las últimas revisiones de $ REVS en las que cambió $ LINE.
Max Nanasy
¿A qué respuesta te refieres?
Flimm
Ya no me acuerdo. Posiblemente podría haber preparado mejor mi respuesta para el futuro.
Will Sheppard
11

Una solución muy única para este problema es usar git log:

git log -p -M - siga --stat - ruta / a / su / archivo

Como explica Andre aquí

Mannu
fuente
1
git config --global alias.changes 'log -p -M --follow --stat --'git changes path/to/your/file
Creé
Esta es, con mucho, la mejor respuesta y exactamente lo que estaba buscando. Simple y elegante
maesk
10

Si está utilizando IDB de Idea de JetBrains (y derivados), puede seleccionar varias líneas, hacer clic derecho para el menú contextual, luego Git -> Mostrar historial para selección. Verá una lista de confirmaciones que estaban afectando a las líneas seleccionadas:

ingrese la descripción de la imagen aquí

warvariuc
fuente
Esto funcionó mejor que las otras respuestas para mí (usando IntelliJ). Tomó un tiempo cargar todas las revisiones pero valió la pena la espera.
Steve Chambers
2

A partir de Git 2.23 puedes usar git blame --ignore-rev

Para el ejemplo dado en la pregunta, esto sería:

git blame -L10,+1 src/options.cpp --ignore-rev fe25b6d

(Sin embargo, es una pregunta capciosa porque ¡fe25b6d es la primera revisión del archivo!)

Michael Platings
fuente
1

Basándose en la respuesta de Will Shepard, su salida incluirá líneas duplicadas para confirmaciones donde no hubo cambios, por lo que puede filtrarlas de la siguiente manera (usando esta respuesta )

LINE=1 FILE=a; for commit in $(git rev-list HEAD $FILE); do git blame -n -L$LINE,+1 $commit -- $FILE; done | sed '$!N; /^\(.*\)\n\1$/!P; D'

Tenga en cuenta que eliminé el argumento REVS y esto vuelve a la confirmación de raíz. Esto se debe a la observación anterior de Max Nanasy.

DavidN
fuente
1

Basándome en la respuesta de DavidN y quiero seguir el archivo renombrado:

LINE=8 FILE=Info.plist; for commit in $(git log --format='%h%%' --name-only --follow -- $FILE | xargs echo | perl -pe 's/\%\s/,/g'); do hash=$(echo $commit | cut -f1 -d ','); fileMayRenamed=$(echo $commit | cut -f2 -d ','); git blame -n -L$LINE,+1 $hash -- $fileMayRenamed; done | sed '$!N; /^\(.*\)\n\1$/!P; D'

ref: muestra bien el historial de cambio de nombre de archivo en git log

Bill Chan
fuente
0

Utilizo este pequeño script bash para ver un historial de culpa.

Primer parámetro: archivo a mirar

Parámetros posteriores: pasados ​​a culpar a git

#!/bin/bash
f=$1
shift
{ git log --pretty=format:%H -- "$f"; echo; } | {
  while read hash; do
    echo "--- $hash"
    git blame $@ $hash -- "$f" | sed 's/^/  /'
  done
}

Puede proporcionar parámetros de culpa como -L 70, + 10 pero es mejor usar la búsqueda de expresiones regulares de culpa git porque los números de línea generalmente "cambian" con el tiempo.

estancamientos
fuente
0

Construir sobre stangls 's respuesta , puse este script en mi camino (incluso en Windows) como git-BH:

Eso me permite buscar todas las confirmaciones en las que estaba involucrada una palabra:

git bh path/to/myfile myWord

Guión:

#!/bin/bash
f=$1
shift
csha=""
{ git log --pretty=format:%H -- "$f"; echo; } | {
  while read hash; do
    res=$(git blame -L"/$1/",+1 $hash -- "$f" 2>/dev/null | sed 's/^/  /')
    sha=${res%% (*}
    if [[ "${res}" != "" && "${csha}" != "${sha}" ]]; then
      echo "--- ${hash}"
      echo "${res}"
      csha="${sha}"
    fi
  done
}
VonC
fuente