Bagaimana BENAR-BENAR menunjukkan log file berganti nama dengan git?

132

Saya relatif baru untuk git, saya menggunakan Subversion sebelumnya.

Saya perhatikan bahwa sebagian besar grafis front-end git dan plugin IDE sepertinya tidak dapat menampilkan sejarah file jika file telah diganti namanya. Saat saya gunakan

git log --follow

pada baris perintah, saya bisa melihat seluruh log di seluruh nama.

Menurut Linus Torvalds , --follow switch adalah "SVN noob", pengguna git yang serius tidak menggunakannya:

--follow adalah total hack, dimaksudkan untuk memuaskan pengguna ex-SVN yang tidak pernah tahu apa-apa tentang hal-hal seperti menjadi orang tua atau grafik revisi yang bagus.

Ini tidak sepenuhnya mendasar, tetapi implementasi "--follow" saat ini benar-benar merupakan hal preprocessing cepat yang melesat ke logika jalan revisi, daripada menjadi sesuatu yang benar-benar integral.

Ini benar-benar dirancang sebagai "SVN noob" pleaser, bukan sebagai "fungsi git nyata". Idenya adalah bahwa Anda akan lolos dari pola pikir (rusak) yang mengubah nama menjadi penting dalam gambaran besar.

Pertanyaan Saya : Bagaimana cara pengguna hardcore git di antara Anda mendapatkan riwayat file saat diubah namanya? Apa cara 'nyata' untuk melakukan ini?

Mike
sumber
17
@ David Hall: git mv oldfile newfiletidak menyebabkan perubahan nama direkam sama sekali - itu hanya sama dengan menghapus satu file dan menambahkan yang lain. git hanya berhasil mengganti nama dan salinan dari status pohon di setiap komit setelah fakta.
Mark Longair
20
@ David Hall: Jika Anda mengganti nama file dengan alat lain di luar git (misalnya /bin/mv oldfile newfile), tetapi lakukan git add newfile; git rm oldfile, hasilnya tidak dapat dibedakan dari itu git mv oldfile newfile.
Mark Longair
1
Ideologi ini berantakan jika Anda pernah memindahkan file ke repositori baru, dalam hal ini ketidakmampuan untuk memindahkan seluruh sejarahnya mungkin menjadi masalah besar. Meskipun tentu saja ada batasan berapa banyak sejarah yang benar-benar dapat datang dengan file dalam proyek yang kompleks.
Roman Starkov
1
Catatan: git log --followmeningkatkan sedikit dengan git 2.9 (Juni 2016): lihat jawaban saya di bawah ini
VonC
1
Pada v2.15, Anda mungkin ingin bereksperimen dengan --color-movedsaat Anda diff.
Michael

Jawaban:

71

Saya berpikir bahwa drive umum di balik titik Linus adalah bahwa - dan mengambil ini dengan sedikit garam - pengguna git hardcore tidak pernah peduli tentang sejarah "file". Anda meletakkan konten dalam repositori git karena konten secara keseluruhan memiliki sejarah yang bermakna.

Ganti nama file adalah kasus kecil "konten" yang bergerak di antara jalur. Anda mungkin memiliki fungsi yang bergerak di antara file yang mungkin dilacak pengguna git dengan "pickaxe" secara fungsional (misalnya log -S).

Perubahan "path" lainnya termasuk menggabungkan dan memisahkan file; git tidak terlalu peduli file mana yang Anda anggap namanya diubah dan mana yang Anda anggap disalin (atau diganti namanya dan dihapus) itu hanya melacak konten lengkap pohon Anda.

git mendorong pemikiran "seluruh pohon" di mana banyak sistem kontrol versi sangat berpusat pada file. Inilah sebabnya mengapa git merujuk pada "jalan" lebih sering daripada mengacu pada "nama file".

CB Bailey
sumber
Hai Charles, Terima kasih atas jawaban Anda. Tampaknya saya menggunakan git dengan cara yang sama seperti saya menggunakan SVN. Walaupun saya mengerti bahwa git sangat berbeda dari sistem kontrol versi lain, banyak konsep di git masih terasa asing bagi saya ... Saya mungkin harus menyelesaikan buku git yang baru saja saya beli.
Mike
24
Maksud Linus adalah bahwa gui yang "benar" akan dapat melacak potongan kode di seluruh file, dan dia berharap kita akan memiliki alat seperti itu sekarang. Sayangnya, kami masih belum memiliki kemewahan itu, dan - ikuti masih berguna.
Michael Parker
11
Apakah git benar-benar memberi Anda solusi selain --followuntuk ini?
Griwes
13
Saya berpendapat bahwa pemikiran "seluruh pohon" ditingkatkan dengan --followmenjadi standar. Yang saya maksud adalah ketika saya ingin melihat sejarah kode dalam suatu file, saya benar-benar tidak biasanya peduli apakah file itu diganti namanya atau tidak, saya hanya ingin melihat sejarah kode, terlepas dari perubahan nama. Jadi menurut saya masuk akal untuk --followmenjadi default karena saya tidak peduli dengan file individual; --followmembantu saya untuk mengabaikan nama file individual, yang biasanya sangat tidak penting.
Diubah
2
Jadi ... jika saya memutuskan untuk peduli dengan "konten" daripada file, bagaimana cara mencetak komit yang relevan dengan konten yang saat ini ada di file ini? Saya akan senang jika git melacak semua file yang berbeda untuk saya dan melaporkan log semua perubahan - Saya hanya tidak melihat bagaimana cara mendapatkannya.
Ed Avis
36

Saya memiliki masalah yang sama persis dengan yang Anda hadapi. Meskipun saya tidak bisa menjawab, saya yakin Anda dapat membaca email ini yang ditulis Linus pada tahun 2005, itu sangat relevan dan mungkin memberi Anda petunjuk tentang cara menangani masalah ini:

... Saya mengklaim bahwa SCM yang mencoba melacak nama pada dasarnya rusak kecuali jika melakukannya untuk alasan internal (yaitu untuk memungkinkan delta yang efisien), tepatnya karena penggantian nama tidak masalah. Mereka tidak membantu Anda, dan mereka tidak apa yang Anda tertarik pula .

Yang penting adalah menemukan "dari mana asalnya", dan arsitektur git melakukannya dengan sangat baik - jauh lebih baik daripada hal lain di luar sana. ...

Saya menemukannya direferensikan oleh posting blog ini, yang juga dapat berguna bagi Anda untuk menemukan solusi yang layak:

Dalam pesan itu, Linus menguraikan bagaimana sistem pelacakan konten yang ideal memungkinkan Anda menemukan bagaimana blok kode masuk ke bentuk saat ini. Anda akan mulai dari blok kode saat ini dalam file, kembali ke histori untuk menemukan komit yang mengubah file. Kemudian Anda memeriksa perubahan komit untuk melihat apakah blok kode yang Anda tertarik dimodifikasi olehnya, sebagai komit yang mengubah file mungkin tidak menyentuh blok kode yang Anda minati, tetapi hanya beberapa bagian lain dari mengajukan.

Ketika Anda menemukan bahwa sebelum komit blok kode tidak ada di file, Anda memeriksa komit lebih dalam. Anda mungkin menemukan bahwa itu adalah salah satu dari banyak situasi yang mungkin terjadi, termasuk:

  1. Komit benar-benar memperkenalkan blok kode. Penulis komit adalah penemu fitur keren yang Anda cari asalnya (atau pihak yang bersalah yang memperkenalkan bug); atau
  2. Blok kode tidak ada dalam file, tetapi lima salinan identik itu ada di file yang berbeda, yang semuanya menghilang setelah komit. Penulis komit kode duplikat refactored dengan memperkenalkan fungsi pembantu tunggal; atau
  3. (sebagai kasus khusus) Sebelum komit, file yang saat ini berisi blok kode yang Anda minati tidak ada, tetapi file lain dengan konten yang hampir identik memang ada, dan blok kode yang Anda minati, bersama dengan semua konten lain dalam file ada saat itu, memang ada di file lain itu. Itu pergi setelah komit. Penulis komit mengganti nama file sambil memberikan sedikit modifikasi.

Di git, alat pelacak konten utama Linus belum ada secara otomatis sepenuhnya. Tetapi sebagian besar bahan penting sudah tersedia.

Tolong, terus beri tahu kami tentang kemajuan Anda dalam hal ini.

Alberto Bacchelli
sumber
Terima kasih telah memposting artikel tersebut. Baru setelah saya membacanya, saya sepenuhnya memahami gagasan sejarah konten! Saya telah memikirkan hal ini dengan cara yang salah!
DavidG
Email dari Linus itu luar biasa, terima kasih telah memposting ini.
mik01aj
Fakta yang menyenangkan, Git v2.15 menambahkan--color-moved gerakan menuju "sistem pelacakan ideal." Saya sedang bermain dengannya untuk melihatnya melacak garis yang dipindahkan dalam file, tetapi menyadari secara tidak sengaja bahwa itu melacak garis yang dipindahkan di seluruh diff.
Michael
2
Linus menjelaskan situasi yang kompleks. Tapi di sini kita punya situasi sederhana: file baru saja diganti namanya (atau dipindahkan ke direktori lain). Maka harus ada solusi sederhana. Saya pikir masalah ini berasal dari fakta yang bertentangan dengan Subversion, pengguna tidak dapat menginstruksikan Git pada waktu komit dari mana file berasal, dan itu --followbisa salah (misalnya, jika 2 file memiliki konten yang sama, atau jika ada modifikasi selain memindahkan file).
vinc17
13

Saya perhatikan bahwa sebagian besar grafis front-end git dan plugin IDE sepertinya tidak dapat menampilkan sejarah file jika file telah diganti namanya

Anda akan senang mengetahui bahwa beberapa alat Git UI populer sekarang mendukung ini. Ada puluhan alat Git UI yang tersedia sehingga saya tidak akan mencantumkan semuanya, tapi misalnya:

  • SourceTree, saat melihat log file, memiliki kotak centang "Ikuti file berganti nama" di kiri bawah
  • TortoiseGit memiliki kotak centang "follow renames" pada jendela log di kiri bawah.

Info lebih lanjut tentang alat Git UI:

Michael Parker
sumber
Sumber berfungsi baik untuk saat mengganti nama sekali, saat mengganti nama dua kali, detail perubahan tidak tersedia untuk komit sebelum penggantian nama. Saya melaporkan bug di sini: jira.atlassian.com/browse/SRCTREE-5715
Intel
gitk bekerja sangat baik bahkan ketika sebuah file diganti nama dua kali dalam sejarah. Perintahnya terlihat seperti ini "gitk --follow path / to / file"
Intel
6

Catatan: git 2.9 (June2016) akan sedikit meningkatkan sifat "buggy" dari git log --follow:

Lihat commit ca4e3ca (30 Mar 2016) oleh SZEDER Gábor ( szeder) .
(Digabung oleh Junio ​​C Hamano - gitster- dalam komit 26effb8 , 13 Apr 2016)

diffcore: memperbaiki urutan iterasi file yang identik selama deteksi nama diubah

Jika dua jalur ' dir/A/file' dan ' dir/B/file' memiliki konten yang identik dan direktori induk diubah namanya, misalnya ' git mv dir other-dir', maka diffcorelaporkan nama persisnya yang berikut:

renamed:    dir/B/file -> other-dir/A/file
renamed:    dir/A/file -> other-dir/B/file

(catat inversinya di sini:, B/file -> A/filedan A/file -> B/file)

Meskipun secara teknis tidak salah, ini membingungkan tidak hanya bagi pengguna, tetapi juga untuk perintah git yang membuat keputusan berdasarkan informasi ganti nama, misalnya ' git log --follow other-dir/A/file' mengikuti ' dir/B/file' di belakang ganti nama.

Perilaku ini adalah efek samping dari commit v2.0.0-rc4 ~ 8 ^ 2 ~ 14 ( diffcore-rename.c: menyederhanakan menemukan nama yang tepat, 2013-11-14): hashmap menyimpan sumber mengembalikan entri dari ember yang sama, yaitu sumber yang cocok dengan tujuan saat ini , dalam urutan LIFO.
Jadi iterasi pertama-tama memeriksa ' other-dir/A/file' dan ' dir/B/file' dan, setelah menemukan konten dan nama dasar yang identik, melaporkan nama yang tepat.

VONC
sumber
2

Di Linux, saya telah memverifikasi bahwa SmartGit dan GitEye dapat mengikuti perubahan nama saat mengikuti sejarah file tertentu. Namun, tidak seperti gitk dan GitEye, SmartGit menunjukkan tampilan file dan tampilan repositori yang terpisah (yang berisi struktur direktori tetapi bukan daftar file yang ada di dalamnya)

Prusswan
sumber