¿Cómo difiero el mismo archivo entre dos confirmaciones diferentes en la misma rama?

1144

En Git, ¿cómo podría comparar el mismo archivo entre dos confirmaciones diferentes (no contiguas) en la misma rama (maestro, por ejemplo)?

Estoy buscando una función de comparación como la de Visual SourceSafe (VSS) o Team Foundation Server (TFS).
¿Es posible en Git?

systemmpuntoout
fuente

Respuestas:

1476

Desde la página del git-diffmanual:

git diff [--options] <commit> <commit> [--] [<path>...]

Por ejemplo, para ver la diferencia para un archivo "main.c" entre ahora y dos confirmaciones, aquí hay tres comandos equivalentes:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c
mipadi
fuente
43
No ..es realmente necesario, aunque funcionará con él (excepto en versiones bastante antiguas, tal vez). También puede usar git logo gitkencontrar SHA1 para usar, en caso de que las dos confirmaciones estén muy separadas. gitktambién tiene un "diff seleccionado -> esto" y "diff esto -> seleccionado" en su menú contextual.
Cascabel
17
¿Funcionará incluso si el nombre del archivo se modificó entre las 2 confirmaciones?
reubenjohn
26
Entonces, ¿cuál es el propósito de "-"
user64141
29
@ user64141 El --es útil, por ejemplo, cuando tiene un archivo llamado -p. Bueno para usar en scripts, solo en casos raros necesarios en la práctica.
Palec
13
Nota: debe usar rutas relativas a la raíz del repositorio. Las rutas relativas al directorio de trabajo actual no funcionarán.
Kevin Wheeler
281

También puede comparar dos archivos diferentes en dos revisiones diferentes, como esta:

git diff <revision_1>:<file_1> <revision_2>:<file_2>

Jakub Narębski
fuente
25
Tenga en cuenta que parece que si <file_1>y <file_2>se encuentran en el directorio actual, no en el directorio de nivel superior git administrado, uno tiene que anteponer ./en Unix:<revision_1>:./filename_1
Andre Holzner
77
<revisión>: puede omitirse, por lo que puede diferenciar con un archivo que aún no se confirmó.
Yaroslav Nikitenko
2
Tenga en cuenta que en Windows uno tiene que usar '/' para las rutas de archivo, no '\'.
np8
88

Si ha configurado el "difftool" puede usar

git difftool revision_1:file_1 revision_2:file_2

Ejemplo: comparar un archivo de su último compromiso con su compromiso anterior en la misma rama: suponiendo que si está en la carpeta raíz del proyecto

$git difftool HEAD:src/main/java/com.xyz.test/MyApp.java HEAD^:src/main/java/com.xyz.test/MyApp.java

Debe tener las siguientes entradas en su ~ / .gitconfig o en el archivo de proyecto / .git / config. Instale el p4merge [Esta es mi herramienta de combinación y diferencia preferida]

[merge]
    tool = p4merge
    keepBackup = false
[diff]
    tool = p4merge
    keepBackup = false
[difftool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
[mergetool]
    keepBackup = false
[difftool]
    keepBackup = false
[mergetool "p4merge"]
    path = C:/Program Files (x86)/Perforce/p4merge.exe
    cmd = p4merge.exe \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
Anver Sadhat
fuente
50

Verifique $ git log, copie la ID SHA-1 de las dos confirmaciones diferentes y ejecute el git diffcomando con esas ID. por ejemplo:

$ git diff (sha-id-one) (sha-id-two)
Vibhuti
fuente
18
Si desea el diff para un archivo específico, agregue la ruta al final del comando.
hBrent
También haga un "git pull" para descargar la información completa del árbol si los dos commits se encuentran en diferentes ramas. De lo contrario, obtendrá un error "fatal: objeto incorrecto".
usuario238607
44
git diff (sha-id-one) (sha-id-two) -- filename.ext sin el nombre del archivo, enumerará las diferencias de todos los archivos en esos dos commits.
SherylHohman
40

Si desea ver todos los cambios en el archivo entre las dos confirmaciones en una base de confirmación por confirmación, también puede hacer

git log -u $start_commit..$end_commit -- path/to/file

cxreg
fuente
¿Qué es "$ start_commit" y "$ end_commit"? ¿Son literales, o si no, puedes dar un ejemplo?
Peter Mortensen el
Esas son variables de shell que contienen la revisión de inicio y finalización, que en su lugar pueden ser literales o referencias sha1
cxreg
21

Aquí hay una secuencia de comandos Perl que imprime los comandos Git diff para un archivo dado como se encuentra en un comando de registro Git.

P.ej

git log pom.xml | perl gldiff.pl 3 pom.xml

Rendimientos:

git diff 5cc287:pom.xml e8e420:pom.xml
git diff 3aa914:pom.xml 7476e1:pom.xml
git diff 422bfd:pom.xml f92ad8:pom.xml

que luego se puede cortar y pegar en una sesión de ventana de shell o canalizar /bin/sh.

Notas:

  1. el número (3 en este caso) especifica cuántas líneas imprimir
  2. el archivo (pom.xml en este caso) debe estar de acuerdo en ambos lugares (puede envolverlo en una función de shell para proporcionar el mismo archivo en ambos lugares) o ponerlo en un directorio binario como un script de shell

Código:

# gldiff.pl
use strict;

my $max  = shift;
my $file = shift;

die "not a number" unless $max =~ m/\d+/;
die "not a file"   unless -f $file;

my $count;
my @lines;

while (<>) {
    chomp;
    next unless s/^commit\s+(.*)//;
    my $commit = $1;
    push @lines, sprintf "%s:%s", substr($commit,0,6),$file;
    if (@lines == 2) {
        printf "git diff %s %s\n", @lines;
        @lines = ();
    }
    last if ++$count >= $max *2;
}
usuario2520657
fuente
14

Si desea hacer una diferencia con más de un archivo, con el método especificado por @mipadi:

Por ejemplo, diff HEADy your master, para encontrar todos los .coffeearchivos:

git diff master..HEAD -- `find your_search_folder/ -name '*.coffee'`

Esto buscará recursivamente your_search_folder/todos sus .coffeearchivos y hará una diferencia entre ellos y sus masterversiones.

Andrei-Niculae Petre
fuente
13

Si tiene varios archivos o directorios y desea comparar confirmaciones no continuas, puede hacer esto:

Hacer una rama temporal ( "revisión" en este ejemplo)

git checkout -b revision

Rebobinar hasta el primer objetivo de confirmación

git reset --hard <commit_target>

Escogiendo cerezas en aquellos comprometidos interesados

git cherry-pick <commit_interested> ...

Aplicar diff

git diff <commit-target>^

Cuando termines

git branch -D revision
dvdvck
fuente
2
Gracias por esta solucion. Funcionó bien para mi caso de uso. Lo único que actualizaría es que cuando haya terminado, no puede eliminar la rama hasta que la apague.
Steven Dix
9

Solo otra forma de usar la genialidad de Git ...

git difftool HEAD HEAD@{N} /PATH/FILE.ext
Eddie B
fuente
difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #"
Definí
2

Si desea una comparación visual simple en Windows, como puede obtener en Visual SourceSafe o Team Foundation Server (TFS), intente esto:

  • haga clic derecho en el archivo en el Explorador de archivos
  • seleccione 'Historial de Git'

Nota: Después de actualizar a Windows 10, he perdido las opciones del menú contextual de Git. Sin embargo, puede lograr lo mismo usando 'gitk' o 'gitk filename' en una ventana de comando.

Una vez que llame a 'Git History', se iniciará la herramienta Git GUI, con un historial del archivo en el panel superior izquierdo. Seleccione una de las versiones que le gustaría comparar. Luego haga clic derecho en la segunda versión y elija

Difundir esto -> seleccionado

o

Diferencia seleccionada -> esto

Las diferencias codificadas por colores aparecerán en el panel inferior izquierdo.

Recurso
fuente
Nota para los votantes: esta es una solución simple, fácil de implementar y aborda el problema del OP. Funciona en Windows que el OP está usando claramente (ver referencias a TFS y VSS en la pregunta).
Recurso