Jak odróżnić ten sam plik między dwoma różnymi zatwierdzeniami w tej samej gałęzi?

1143

Jak w Git mogę porównać ten sam plik między dwoma różnymi zatwierdzeniami (nieprzylegającymi) w tej samej gałęzi (na przykład master)?

Szukam funkcji porównania, takiej jak Visual SourceSafe (VSS) lub Team Foundation Server (TFS).
Czy jest to możliwe w Git?

systempuntoout
źródło

Odpowiedzi:

1475

Z strony git-diffpodręcznika:

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

Na przykład, aby zobaczyć różnicę dla pliku „main.c” między teraz a dwoma zatwierdzeniami wstecz, oto trzy równoważne polecenia:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c
mipadi
źródło
43
Nie ..jest to naprawdę konieczne, ale będzie z nim współpracowało (może z wyjątkiem dość starych wersji). Możesz także użyć git loglub gitkznaleźć SHA1 do użycia, jeśli dwa zatwierdzenia są bardzo daleko od siebie. gitkw menu kontekstowym ma również opcję „diff selected -> this” i „diff this -> selected”.
Cascabel
17
Czy to zadziała, nawet jeśli nazwa pliku zostanie zmodyfikowana między 2 zatwierdzeniami?
reubenjohn
26
Więc jaki jest cel „-”
user64141
29
@ user64141 Jest --to przydatne np. gdy masz plik o nazwie -p. Dobry do użycia w skryptach, tylko w rzadkich przypadkach potrzebnych w praktyce.
Palec
13
Uwaga: musisz użyć ścieżek względem katalogu głównego repozytorium. Ścieżki względem bieżącego katalogu roboczego nie będą działać.
Kevin Wheeler
280

Możesz także porównać dwa różne pliki w dwóch różnych wersjach, takich jak to:

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

Jakub Narębski
źródło
25
zwróć uwagę, że wygląda na to, że <file_1>i <file_2>znajduje się w bieżącym katalogu, a nie w katalogu zarządzanym git najwyższego poziomu, należy dodać ./na Unixie:<revision_1>:./filename_1
Andre Holzner
7
<wersja>: można ją pominąć, dzięki czemu można różnicować z plikiem, który nie został jeszcze zatwierdzony.
Jarosław Nikitenko,
2
Należy pamiętać, że w systemie Windows należy używać „/” dla ścieżek plików, a nie „\”.
np8
87

Jeśli skonfigurowałeś „difftool”, możesz użyć

git difftool revision_1:file_1 revision_2:file_2

Przykład: porównanie pliku z ostatniego zatwierdzenia do poprzedniego zatwierdzenia w tym samym oddziale: Zakładając, że jeśli jesteś w folderze głównym projektu

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

Powinieneś mieć następujące wpisy w pliku ~ / .gitconfig lub w projekcie / .git / config. Zainstaluj p4merge [To jest moje ulubione narzędzie do porównywania i scalania]

[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
źródło
50

Sprawdź $ git log, skopiuj identyfikator SHA-1 dwóch różnych zatwierdzeń i uruchom git diffpolecenie z tymi identyfikatorami. na przykład:

$ git diff (sha-id-one) (sha-id-two)
Wibhuti
źródło
18
Jeśli chcesz różnicę dla określonego pliku, dodaj do niego ścieżkę na końcu polecenia.
hBrent
Wykonaj także „git pull”, aby pobrać pełne informacje o drzewie, jeśli dwa zatwierdzenia dotyczą różnych gałęzi. W przeciwnym razie pojawi się błąd „fatal: bad object”.
user238607
4
git diff (sha-id-one) (sha-id-two) -- filename.ext bez nazwy pliku wyświetli listę różnic wszystkich plików w tych dwóch zatwierdzeniach.
SherylHohman
40

Jeśli chcesz zobaczyć wszystkie zmiany w pliku między dwoma zatwierdzeniami na zasadzie zatwierdzania przez zatwierdzenie, możesz to zrobić

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

cxreg
źródło
Co to jest „$ start_commit” i „$ end_commit”? Czy są dosłowne, a jeśli nie, czy możesz podać przykład?
Peter Mortensen
Są to zmienne powłoki, które zawierają wersję początkową i końcową, które mogą być literałami sha1 lub
odnośnikami
21

Oto skrypt Perla, który wypisuje polecenia Git diff dla danego pliku znalezione w poleceniu Git log.

Na przykład

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

Wydajność:

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

które można następnie wyciąć i wkleić w sesji okna powłoki lub przesłać do potoku /bin/sh.

Uwagi:

  1. liczba (w tym przypadku 3) określa liczbę wierszy do wydrukowania
  2. plik (w tym przypadku pom.xml) musi się zgadzać w obu miejscach (możesz owinąć go funkcją powłoki, aby zapewnić ten sam plik w obu miejscach) lub umieścić go w katalogu binarnym jako skrypt powłoki

Kod:

# 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;
}
użytkownik2520657
źródło
14

Jeśli chcesz zrobić różnicę za pomocą więcej niż jednego pliku, metodą określoną przez @mipadi:

Np. Różnicuj między HEADswoim a master, aby znaleźć wszystkie .coffeepliki:

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

Spowoduje to rekurencyjne przeszukiwanie your_search_folder/wszystkich .coffeeplików i różnicę między nimi a ich masterwersjami.

Andrei-Niculae Petre
źródło
13

Jeśli masz kilka plików lub katalogów i chcesz porównać nieciągłe zatwierdzenia, możesz to zrobić:

Utwórz gałąź tymczasową ( w tym przykładzie „wersja” )

git checkout -b revision

Przewiń do pierwszego celu zatwierdzenia

git reset --hard <commit_target>

Wiśniowe wybieranie tych, którzy są zainteresowani

git cherry-pick <commit_interested> ...

Zastosuj diff

git diff <commit-target>^

Kiedy skończysz

git branch -D revision
dvdvck
źródło
2
Dzięki za to rozwiązanie. Działa dobrze w moim przypadku użycia. Jedyne, co chciałbym zaktualizować, to to, że kiedy skończysz, nie możesz usunąć gałęzi, dopóki go nie wyłączysz.
Steven Dix,
9

To kolejny sposób na wykorzystanie niesamowitości Gita ...

git difftool HEAD HEAD@{N} /PATH/FILE.ext
Eddie B.
źródło
Z tej odpowiedzi zdefiniowałem alias, który działa z bash:difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #"
blueogive
2

Jeśli chcesz proste wizualne porównanie w systemie Windows, takie jak Visual SourceSafe lub Team Foundation Server (TFS), spróbuj tego:

  • kliknij plik prawym przyciskiem myszy w Eksploratorze plików
  • wybierz „Git History”

Uwaga: po uaktualnieniu do systemu Windows 10 straciłem opcje menu kontekstowego Git. Możesz jednak osiągnąć to samo, używając „gitk” lub „gitk filename” w oknie poleceń.

Po wywołaniu „Git History” uruchomi się narzędzie Git GUI z historią pliku w lewym górnym panelu. Wybierz jedną z wersji, którą chcesz porównać. Następnie kliknij drugą wersję prawym przyciskiem myszy i wybierz jedną z nich

Zróżnicuj to -> wybrane

lub

Zróżnicowane wybrane -> to

Różnice oznaczone kolorami pojawią się w dolnym lewym panelu.

Ratunek
źródło
Uwaga dla downvoterów: jest to proste rozwiązanie, łatwe do wdrożenia i rozwiązujące problem PO. Działa w systemie Windows, z którego OP wyraźnie korzysta (patrz odniesienia do TFS i VSS w pytaniu).
Zasób