Bagaimana cara membaca output dari git diff?

271

Halaman manual git-diffagak panjang, dan menjelaskan banyak kasus yang tampaknya tidak perlu bagi pemula. Sebagai contoh:

git diff origin/master
Poseid
sumber
1
dengan menggunakan editor teks yang berbeda, notasi rentang @ ... @ untuk nomor baris menjadi jelas.
Poseid
Editor teks yang mana?
Jus12

Jawaban:

489

Mari kita lihat contoh lanjutan lanjutan dari sejarah git (dalam komit 1088261f di repositori git.git ):

diff --git a/builtin-http-fetch.c b/http-fetch.c
similarity index 95%
rename from builtin-http-fetch.c
rename to http-fetch.c
index f3e63d7..e8f44ba 100644
--- a/builtin-http-fetch.c
+++ b/http-fetch.c
@@ -1,8 +1,9 @@
 #include "cache.h"
 #include "walker.h"

-int cmd_http_fetch(int argc, const char **argv, const char *prefix)
+int main(int argc, const char **argv)
 {
+       const char *prefix;
        struct walker *walker;
        int commits_on_stdin = 0;
        int commits;
@@ -18,6 +19,8 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix)
        int get_verbosely = 0;
        int get_recover = 0;

+       prefix = setup_git_directory();
+
        git_config(git_default_config, NULL);

        while (arg < argc && argv[arg][0] == '-') {

Mari kita menganalisis garis patch ini demi baris.

  • Baris pertama

    diff --git a / builtin-http-fetch.cb / http-fetch.c
    adalah header "git diff" dalam formulir diff --git a/file1 b/file2. Nama file a/dan b/sama kecuali kecuali mengubah nama / menyalin (seperti dalam kasus kami). The --gitadalah untuk berarti bahwa diff adalah di "git" format diff.

  • Berikutnya adalah satu atau lebih baris tajuk yang diperluas. Tiga yang pertama

    indeks kesamaan 95%
    ganti nama dari builtin-http-fetch.c
    ganti nama menjadi http-fetch.c
    beri tahu kami bahwa file diubah namanya dari builtin-http-fetch.cmenjadi http-fetch.cdan bahwa kedua file tersebut 95% identik (yang digunakan untuk mendeteksi nama ini).

    Baris terakhir di header extended diff, yaitu
    indeks f3e63d7..e8f44ba 100644
    memberi tahu kami tentang mode file yang diberikan ( 100644berarti bahwa itu file biasa dan bukan eg symlink, dan tidak memiliki bit izin yang dapat dieksekusi), dan tentang hash preimage yang dipersingkat (versi file sebelum diberikan perubahan) dan postimage ( versi file setelah perubahan). Baris ini digunakan oleh git am --3wayuntuk mencoba melakukan penggabungan 3 arah jika tambalan tidak dapat diterapkan sendiri.

  • Berikutnya adalah dua baris tajuk terpadu terpadu

    --- a / builtin-http-fetch.c
    +++ b / http-fetch.c
    Dibandingkan dengan diff -Uhasil, ia tidak memiliki nama file dari-file-modifikasi-waktu atau ke-file-modifikasi setelah sumber (preimage) dan tujuan (postimage). Jika file dibuat sumbernya adalah /dev/null; jika file dihapus, targetnya adalah /dev/null.
    Jika Anda mengatur diff.mnemonicPrefixvariabel konfigurasi ke benar, di tempat a/dan b/prefiks dalam header dua-baris ini Anda dapat memiliki bukan c/, i/, w/dan o/sebagai awalan, masing-masing dengan apa yang Anda membandingkan; lihat git-config (1)

  • Berikutnya datang satu atau lebih perbedaan pendapat; setiap bingkah menunjukkan satu area di mana file berbeda. Bakhil format terpadu dimulai dengan garis seperti

    @@ -1,8 +1,9 @@
    atau
    @@ -18,6 +19,8 @@ int cmd_http_fetch (int argc, const char ** argv, ...
    Itu dalam format @@ from-file-range to-file-range @@ [header]. Dari-file-range dalam bentuk -<start line>,<number of lines>, dan ke-file-range adalah +<start line>,<number of lines>. Garis awal dan jumlah garis mengacu pada posisi dan panjang bingkah di preimage dan postimage, masing-masing. Jika jumlah baris tidak ditampilkan itu berarti 0.

    Header opsional menunjukkan fungsi C di mana setiap perubahan terjadi, jika itu adalah file C (seperti -popsi dalam GNU diff), atau yang setara, jika ada, untuk jenis file lainnya.

  • Berikutnya adalah deskripsi di mana file berbeda. Garis-garis yang umum untuk kedua file dimulai dengan karakter spasi. Garis-garis yang sebenarnya berbeda antara dua file memiliki salah satu karakter indikator berikut di kolom cetak kiri:

    • '+' - Baris ditambahkan di sini ke file pertama.
    • '-' - Baris dihapus di sini dari file pertama.


    Jadi, misalnya, potongan pertama

     #include "cache.h"
     #include "walker.h"
    
    -int cmd_http_fetch(int argc, const char **argv, const char *prefix)
    +int main(int argc, const char **argv)
     {
    +       const char *prefix;
            struct walker *walker;
            int commits_on_stdin = 0;
            int commits;
    

    berarti cmd_http_fetchdigantikan oleh main, dan const char *prefix;baris itu ditambahkan.

    Dengan kata lain, sebelum perubahan, fragmen yang sesuai dari file 'builtin-http-fetch.c' saat itu tampak seperti ini:

    #include "cache.h"
    #include "walker.h"
    
    int cmd_http_fetch(int argc, const char **argv, const char *prefix)
    {
           struct walker *walker;
           int commits_on_stdin = 0;
           int commits;
    

    Setelah perubahan, fragmen file sekarang 'http-fetch.c' ini terlihat seperti ini:

    #include "cache.h"
    #include "walker.h"
    
    int main(int argc, const char **argv)
    {
           const char *prefix;
           struct walker *walker;
           int commits_on_stdin = 0;
           int commits;
    
  • Mungkin ada

    \ Tidak ada baris baru di akhir file
    baris sekarang (tidak dalam contoh diff).

Seperti yang dikatakan Donal Fellows , yang terbaik adalah berlatih membaca perbedaan pada contoh kehidupan nyata, di mana Anda tahu apa yang telah Anda ubah.

Referensi:

Jakub Narębski
sumber
1
@Geremia: Git menggunakan heuristik berbasis kesamaan untuk mengganti nama deteksi ... dan juga untuk memindahkan kode dan menyalin deteksi git blame -C -C, begitulah cara kerjanya; itu adalah keputusan desain Git. Format git diff hanya menunjukkan indeks kesamaan (atau perbedaan) dengan pengguna.
Jakub Narębski
1
@Geremia: Untuk lebih tepatnya, [header]adalah yang terdekat sebelumnya seperti dengan awal fungsi yang mendahului sebongkah. Dalam kebanyakan kasus, baris ini menyertakan nama fungsi di mana bilangan diff berada. Ini dapat dikonfigurasi dengan diffgitattribute diatur ke driver berbeda, dan driver berbeda termasuk xfuncnamevariabel konfigurasi.
Jakub Narębski
1
@AnthonyGeoghegan: baris mungkin dihapus (maka jumlah baris dalam postimage adalah 0), atau ditambahkan (maka jumlah baris dalam preimage adalah 0).
Jakub Narębski
1
@KasunSiyambalapitiya: Format diff terpadu yang digunakan Git (berbeda dengan format perbedaan konteks ^ [1]) tidak membedakan antara baris yang dimodifikasi, dan baris yang dihapus dan ditambahkan. [1]: gnu.org/software/diffutils/manual/html_node/Context-Format.html
Jakub Narębski
1
@ JakubNarębski: Jumlah baris default ke 1, bukan ke 0. Ini sesederhana itu. Dalam praktiknya, itu hanya muncul sebagai "-1" dan / atau "+1" untuk file baris tunggal karena tidak ada konteks untuk ditampilkan.
Guido Flohr
68

@@ -1,2 +3,4 @@ bagian dari diff

Bagian ini perlu waktu untuk saya mengerti, jadi saya telah membuat contoh minimal.

Formatnya pada dasarnya sama dengan diff -uunified diff.

Misalnya:

diff -u <(seq 16) <(seq 16 | grep -Ev '^(2|3|14|15)$')

Di sini kami menghapus baris 2, 3, 14 dan 15. Output:

@@ -1,6 +1,4 @@
 1
-2
-3
 4
 5
 6
@@ -11,6 +9,4 @@
 11
 12
 13
-14
-15
 16

@@ -1,6 +1,4 @@ cara:

  • -1,6berarti bahwa bagian dari file pertama ini dimulai pada baris 1 dan menunjukkan total 6 baris. Oleh karena itu menunjukkan garis 1 hingga 6.

    1
    2
    3
    4
    5
    6
    

    -berarti "tua", seperti yang biasa kita panggil diff -u old new.

  • +1,4berarti bahwa bagian dari file kedua ini dimulai pada baris 1 dan menunjukkan total 4 baris. Karenanya ia menunjukkan baris 1 hingga 4.

    + berarti "baru".

    Kami hanya memiliki 4 baris, bukan 6 karena 2 baris telah dihapus! Cowok baru itu hanya:

    1
    4
    5
    6
    

@@ -11,6 +9,4 @@ untuk cowok kedua adalah analog:

  • pada file lama, kami memiliki 6 baris, mulai dari baris 11 dari file lama:

    11
    12
    13
    14
    15
    16
    
  • pada file baru, kami memiliki 4 baris, mulai dari baris 9 file baru:

    11
    12
    13
    16
    

    Perhatikan bahwa baris 11adalah baris ke-9 dari file baru karena kita telah menghapus 2 baris pada bingkah sebelumnya: 2 dan 3.

Header sebongkah

Bergantung pada versi git dan konfigurasi Anda, Anda juga bisa mendapatkan baris kode di sebelah @@baris, misalnya func1() {di:

@@ -4,7 +4,6 @@ func1() {

Ini juga bisa diperoleh dengan -pbendera polos diff.

Contoh: file lama:

func1() {
    1;
    2;
    3;
    4;
    5;
    6;
    7;
    8;
    9;
}

Jika kita menghapus garis 6, diff menunjukkan:

@@ -4,7 +4,6 @@ func1() {
     3;
     4;
     5;
-    6;
     7;
     8;
     9;

Perhatikan bahwa ini bukan garis yang benar untuk func1: ia melewatkan garis 1dan 2.

Fitur luar biasa ini sering memberi tahu persis ke fungsi atau kelas mana masing-masing hunk milik, yang sangat berguna untuk menafsirkan diff.

Bagaimana algoritma untuk memilih header bekerja dengan tepat dibahas di: Di mana kutipan dari header git diff hunk berasal?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
sumber
11
Ini untuk siapa saja yang masih belum mengerti. Dalam @@ -1,6 +1,4 @@pls tidak membaca -1sebagai minus oneatau +1sebagai plus onegantinya membaca ini sebagai line 1 to 6di tua (pertama) file. Catatan di sini - implies "old"bukan minus. BTW, terima kasih atas klarifikasi ... haash.
dkjain
dari ini @@ -1,8 +1,9 @@ apakah mungkin untuk menafsirkan apa yang sebenarnya terjadi. misalnya 1) satu baris telah ditambahkan 2) satu baris sedang dimodifikasi dan satu baris ditambahkan dan seterusnya. Atau apakah itu dari cara lain, karena harus ada cara untuk mendapatkannya ketika git diff correclty mengidentifikasi baris apa yang telah dimodifikasi dalam kode. Tolong bantu saya karena saya benar-benar harus menyelesaikan ini
Kasun Siyambalapitiya
Harap dicatat bahwa ini tidak benar dan sangat menyesatkan, pernyataan ini dalam jawaban di atas: " +1,4mengatakan bahwa bagian ini sesuai dengan baris 1 hingga 4 dari file kedua ". Ini karena +1,4dapat merujuk ke garis konteks non-kontingen. Sebaliknya, apa yang +1,4sebenarnya " " maksud adalah bahwa " ada 4garis (yaitu garis konteks) dalam 'versi' file ". Hal ini penting untuk memahami arti dari +, -, dan <whitespace>pada awal garis, yang berlaku untuk interpretasi bakhil. Contoh yang lebih visual: youtube.com/watch?v=1tqMjJeyKpw
Damilola Olowookere
23

Inilah contoh sederhana.

diff --git a/file b/file 
index 10ff2df..84d4fa2 100644
--- a/file
+++ b/file
@@ -1,5 +1,5 @@
 line1
 line2
-this line will be deleted
 line4
 line5
+this line is added

Berikut penjelasannya (lihat detailnya di sini ).

  • --git bukan perintah, ini berarti versi git dari diff (bukan unix)
  • a/ b/direktori, itu tidak nyata. itu hanya kenyamanan ketika kita berurusan dengan file yang sama (dalam kasus saya a / ada di indeks dan b / ada di direktori kerja)
  • 10ff2df..84d4fa2 adalah gumpalan ID dari 2 file ini
  • 100644 adalah "mode bits," yang menunjukkan bahwa ini adalah file biasa (tidak dapat dieksekusi dan bukan tautan simbolik)
  • --- a/file +++ b/filetanda minus menunjukkan garis dalam a / versi tetapi hilang dari b / versi; dan tanda tambah menunjukkan baris-baris yang hilang pada / tetapi ada pada b / (dalam kasus saya --- berarti baris yang dihapus dan +++ berarti baris yang ditambahkan dalam b / dan ini file dalam direktori kerja)
  • @@ -1,5 +1,5 @@untuk memahami ini, lebih baik bekerja dengan file besar; jika Anda memiliki dua perubahan di tempat yang berbeda Anda akan mendapatkan dua entri seperti @@ -1,5 +1,5 @@; misalkan Anda memiliki file line1 ... line100 dan dihapus line10 dan tambahkan line100 baru - Anda akan mendapatkan:
@@ -7,7 +7,6 @@ line6
 line7
 line8
 line9
-this line10 to be deleted
 line11
 line12
 line13
@@ -98,3 +97,4 @@ line97
 line98
 line99
 line100
+this is new line100
irudyak
sumber
Terima kasih. "100644 adalah bit mode, menunjukkan bahwa ini adalah file biasa (tidak dapat dieksekusi dan bukan tautan simbolik)". Apakah "mode bits" sebuah konsep di Linux, atau hanya di Git?
Tim
@Tim Tidak spesifik untuk git. 3 digit kanan ( 644) harus dibaca dalam oktal (nilai: 1, 2, 4 masing-masing izin eXecute, Tulis, dan Baca) dan sesuai dengan urutan tersebut untuk Pemilik (Pengguna), lalu Grup, lalu izin lainnya. Jadi singkatnya 644akan berarti jika ditulis secara simbolis u=rw,og=r, yang dapat dibaca oleh semua orang tetapi hanya dapat ditulis oleh pemilik. Digit lainnya di sebelah kiri menyandikan informasi lain, seperti jika itu adalah symlink, dll. Nilai dapat dilihat github.com/git/git/blob/… , 1 pertama di posisi ini adalah "file biasa".
Patrick Mevzek
15

Format output default (yang awalnya berasal dari program yang dikenal seolah- diffolah Anda ingin mencari info lebih lanjut) dikenal sebagai "unified diff". Ini pada dasarnya mengandung 4 jenis garis:

  • garis konteks, yang dimulai dengan satu spasi,
  • garis penyisipan yang menunjukkan garis yang telah disisipkan, yang dimulai dengan +,
  • baris penghapusan, yang dimulai dengan a -, dan
  • baris metadata yang menjelaskan hal-hal tingkat tinggi seperti file mana yang dibicarakan, opsi apa yang digunakan untuk menghasilkan diff, apakah file tersebut mengubah izinnya, dll.

Saya menyarankan Anda berlatih membaca perbedaan antara dua versi file di mana Anda tahu persis apa yang Anda ubah. Seperti itu Anda akan mengenali apa yang sedang terjadi ketika Anda melihatnya.

Donal Fellows
sumber
5
+1: Saran tentang latihan sangat bagus - mungkin jauh lebih cepat daripada mencoba membaca dokumentasi secara obsesif.
Cascabel
6

Di mac saya:

info difflalu pilih: Output formats-> Context-> Unified format-> Detailed Unified:

Atau man online berbeda pada gnu mengikuti jalur yang sama ke bagian yang sama:

File: diff.info, Node: Detail Unified, Selanjutnya: Contoh Unified, Up: Unified Format

Penjelasan terperinci tentang Format Terpadu ..........................................

Format output terpadu dimulai dengan header dua baris, yang terlihat seperti ini:

 --- FROM-FILE FROM-FILE-MODIFICATION-TIME
 +++ TO-FILE TO-FILE-MODIFICATION-TIME

Cap waktu tampak seperti `2002-02-21 23: 30: 39.942229878 -0800 'untuk menunjukkan tanggal, waktu dengan detik fraksional, dan zona waktu.

Anda dapat mengubah konten tajuk dengan opsi `--label = LABEL '; lihat * Catatan Nama Alternatif ::.

Berikutnya datang satu atau lebih perbedaan pendapat; setiap bingkah menunjukkan satu area di mana file berbeda. Bakhal format terpadu terlihat seperti ini:

 @@ FROM-FILE-RANGE TO-FILE-RANGE @@
  LINE-FROM-EITHER-FILE
  LINE-FROM-EITHER-FILE...

Garis-garis yang umum untuk kedua file dimulai dengan karakter spasi. Garis-garis yang sebenarnya berbeda antara dua file memiliki salah satu karakter indikator berikut di kolom cetak kiri:

`+ 'Baris ditambahkan di sini ke file pertama.

`- 'Baris dihapus di sini dari file pertama.

Stefan
sumber
1
Perhatikan bahwa git tidak mencetak bagian 'XXX-FILE-MODIFICATION-TIME', karena tidak masuk akal untuk sistem kontrol versi. Untuk membandingkan file pada catatan waktu sistem file dapat berfungsi sebagai kontrol versi "orang miskin".
Jakub Narębski
3

Tidak jelas dari pertanyaan Anda bagian mana dari diff yang Anda anggap membingungkan: sebenarnya diff, atau informasi header tambahan yang dicetak git. Untuk jaga-jaga, berikut ini ikhtisar singkat header.

Baris pertama adalah sesuatu seperti diff --git a/path/to/file b/path/to/file- jelas itu hanya memberi tahu Anda untuk apa file bagian diff ini. Jika Anda mengatur variabel konfigurasi boolean diff.mnemonic prefix, adan bakan diubah menjadi huruf yang lebih deskriptif seperti cdan w(komit dan pohon kerja).

Berikutnya, ada "garis mode" - garis yang memberi Anda deskripsi tentang perubahan yang tidak melibatkan perubahan konten file. Ini termasuk file baru / dihapus, file berganti nama / disalin, dan perubahan izin.

Akhirnya, ada garis seperti index 789bd4..0afb621 100644. Anda mungkin tidak akan pernah mempedulikannya, tetapi angka hex 6 digit tersebut adalah hash SHA1 disingkat dari gumpalan lama dan baru untuk file ini (gumpalan adalah objek git yang menyimpan data mentah seperti isi file). Dan tentu saja, 100644ini adalah mode file - tiga digit terakhir jelas izin; tiga yang pertama memberikan informasi metadata file tambahan ( posting SO menggambarkan itu ).

Setelah itu, Anda beralih ke output unified diff standar (seperti klasik diff -U). Ini dibagi menjadi bakhil - sebongkah adalah bagian dari file yang berisi perubahan dan konteksnya. Setiap potongan didahului oleh sepasang ---dan +++garis - garis yang menunjukkan file yang dimaksud, kemudian perbedaan aktual adalah (secara default) tiga baris konteks di kedua sisi -dan +garis-garis yang menunjukkan baris yang dihapus / ditambahkan.

Cascabel
sumber
++ untuk indexsaluran. Dikonfirmasi dengangit hash-object ./file
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功