Bagaimana cara membedakan file yang sama antara dua commit berbeda di cabang yang sama?

1144

Di Git, bagaimana saya bisa membandingkan file yang sama antara dua komit yang berbeda (tidak berdekatan) pada cabang yang sama (master misalnya)?

Saya mencari fitur perbandingan seperti yang ada di Visual SourceSafe (VSS) atau Team Foundation Server (TFS).
Apakah mungkin di Git?

systempuntoout
sumber

Jawaban:

1476

Dari halaman git-diffmanual:

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

Misalnya, untuk melihat perbedaan untuk file "main.c" antara sekarang dan dua komit kembali, berikut adalah tiga perintah yang setara:

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c
mipadi
sumber
43
Itu ..tidak benar-benar diperlukan, meskipun itu akan bekerja dengannya (kecuali dalam versi yang cukup lama, mungkin). Anda juga dapat menggunakan git logatau gitkmenemukan SHA1 untuk digunakan, jika kedua komit tersebut terpisah sangat jauh. gitkjuga memiliki "diff selected -> this" dan "diff this -> selected" dalam menu konteksnya.
Cascabel
17
Apakah ini akan berfungsi bahkan jika nama file diubah di antara 2 commit?
reubenjohn
26
Jadi apa tujuan dari "-"
user64141
29
@ user64141 --Berguna misalnya ketika Anda memiliki file bernama -p. Baik untuk digunakan dalam skrip, hanya dalam kasus yang jarang diperlukan dalam praktek
Palec
13
Catatan: Anda perlu menggunakan path relatif ke root dari repo. Jalur relatif ke direktori kerja saat ini tidak akan berfungsi.
Kevin Wheeler
281

Anda juga dapat membandingkan dua file berbeda dalam dua revisi berbeda, seperti ini:

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

Jakub Narębski
sumber
25
perhatikan bahwa sepertinya jika <file_1>dan <file_2>berada di direktori saat ini, bukan pada direktori git dikelola tingkat atas, kita harus bergantung ./pada Unix:<revision_1>:./filename_1
Andre Holzner
7
<revision>: dapat dinonaktifkan, sehingga Anda dapat berbeda dengan file yang belum berkomitmen.
Yaroslav Nikitenko
2
Perhatikan bahwa pada Windows kita harus menggunakan '/' untuk jalur file, bukan '\'.
np8
88

Jika Anda telah mengkonfigurasi "difftool" yang dapat Anda gunakan

git difftool revision_1:file_1 revision_2:file_2

Contoh: Membandingkan file dari komit terakhir ke komit sebelumnya di cabang yang sama: Asumsikan bahwa jika Anda berada di folder root proyek Anda

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

Anda harus memiliki entri berikut di file ~ / .gitconfig Anda atau dalam file project / .git / config. Instal p4merge [Ini adalah alat diff dan merge yang saya sukai]

[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
sumber
50

Periksa $ git log, salin ID SHA-1 dari dua commit yang berbeda, dan jalankan git diffperintah dengan ID tersebut. sebagai contoh:

$ git diff (sha-id-one) (sha-id-two)
Vibhuti
sumber
18
Jika Anda ingin diff untuk file tertentu, tambahkan path ke sana di akhir perintah.
hBrent
Juga lakukan "git pull" untuk mengunduh info lengkap pohon jika kedua komit berada di seluruh cabang yang berbeda. Kalau tidak, Anda akan mendapatkan kesalahan "fatal: bad object".
user238607
4
git diff (sha-id-one) (sha-id-two) -- filename.ext tanpa nama file itu akan mencantumkan diff dari semua file dalam dua komit.
SherylHohman
40

Jika Anda ingin melihat semua perubahan pada file di antara kedua commit berdasarkan komitmen, Anda juga dapat melakukannya

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

cxreg
sumber
Apa itu "$ start_commit" dan "$ end_commit"? Apakah itu literal, atau jika tidak, dapatkah Anda memberikan contoh?
Peter Mortensen
Itu adalah variabel shell yang berisi revisi awal dan akhir, yang sebaliknya bisa sha1 literal atau referensi
cxreg
21

Berikut adalah skrip Perl yang mencetak perintah Git diff untuk file yang diberikan seperti yang ditemukan dalam perintah Git log.

Misalnya

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

Hasil:

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

yang kemudian dapat dipotong dan disisipkan dalam sesi jendela shell atau disalurkan ke /bin/sh.

Catatan:

  1. angka (3 dalam hal ini) menentukan berapa banyak garis untuk dicetak
  2. file (pom.xml dalam kasus ini) harus setuju di kedua tempat (Anda bisa membungkusnya dalam fungsi shell untuk menyediakan file yang sama di kedua tempat) atau meletakkannya di direktori biner sebagai skrip shell

Kode:

# 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;
}
pengguna2520657
sumber
14

Jika Anda ingin membuat diff dengan lebih dari satu file, dengan metode yang ditentukan oleh @mipadi:

Misalnya perbedaan antara HEADdan Anda master, untuk menemukan semua .coffeefile:

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

Ini akan secara rekursif mencari your_search_folder/semua .coffeefile Anda dan membuat perbedaan antara mereka dan masterversinya.

Andrei-Niculae Petre
sumber
13

Jika Anda memiliki beberapa file atau direktori dan ingin membandingkan komitmen yang tidak berkelanjutan, Anda dapat melakukan ini:

Buat cabang sementara ( "revisi" dalam contoh ini)

git checkout -b revision

Putar balik ke target komit pertama

git reset --hard <commit_target>

Cherry memilih mereka yang tertarik

git cherry-pick <commit_interested> ...

Terapkan diff

git diff <commit-target>^

Ketika kamu selesai

git branch -D revision
dvdvck
sumber
2
Terima kasih atas solusi ini. Ini bekerja dengan baik untuk use case saya. Satu-satunya hal yang akan saya perbarui adalah bahwa ketika Anda selesai Anda tidak dapat menghapus cabang sampai Anda mematikannya.
Steven Dix
9

Hanya cara lain untuk menggunakan kehebatan Git ...

git difftool HEAD HEAD@{N} /PATH/FILE.ext
Eddie B
sumber
Saya mendefinisikan alias dari jawaban ini yang bekerja dengan bash:difftool-file = "!git difftool HEAD@{\"$2\"} HEAD \"$1\" #"
blueogive
2

Jika Anda ingin perbandingan visual sederhana pada Windows seperti yang Anda dapatkan di Visual SourceSafe atau Team Foundation Server (TFS), coba ini:

  • klik kanan pada file di File Explorer
  • pilih 'Sejarah Git'

Catatan: Setelah memutakhirkan ke Windows 10 saya telah kehilangan opsi menu konteks Git. Namun, Anda dapat mencapai hal yang sama menggunakan 'gitk' atau 'gitk filename' di jendela perintah.

Setelah Anda memanggil 'Git History', alat Git GUI akan mulai, dengan riwayat file di panel kiri atas. Pilih salah satu versi yang ingin Anda bandingkan. Kemudian klik kanan pada versi kedua dan pilih salah satu

Diff ini -> dipilih

atau

Diff dipilih -> ini

Perbedaan kode warna akan muncul di panel kiri bawah.

Sumber
sumber
Catatan untuk downvoters: ini adalah solusi sederhana, mudah diimplementasikan dan mengatasi masalah OP. Ini bekerja pada Windows yang OP jelas menggunakan (lihat referensi TFS dan VSS dalam pertanyaan).
Sumberdaya