Rekam operasi penyalinan file dengan Git

141

Ketika saya memindahkan file di git menggunakan git-mv status menunjukkan bahwa file tersebut telah diubah namanya dan bahkan jika saya mengubah beberapa bagian itu masih dianggap hal yang hampir sama (yang baik karena memungkinkan saya mengikuti sejarahnya) .

Ketika saya menyalin file, file asli memiliki beberapa sejarah yang saya ingin kaitkan dengan salinan baru.

Saya telah mencoba memindahkan file kemudian mencoba checkout kembali di lokasi asli - setelah pindah git tidak akan membiarkan saya checkout lokasi asli.

Saya telah mencoba melakukan copy sistem file dan kemudian menambahkan file - git mencantumkannya sebagai file baru.

Apakah ada cara untuk membuat git merekam operasi penyalinan file dengan cara yang mirip dengan cara git merekam nama file / memindahkan tempat sejarah dapat ditelusuri kembali ke file asli?

Hexdoll
sumber

Jawaban:

112

Git tidak melakukan pelacakan nama atau pelacakan salinan, yang berarti tidak merekam nama atau salinan. Apa yang dilakukannya adalah mengganti nama dan menyalin deteksi . Anda dapat meminta deteksi nama dalam git diff(dan git show) menggunakan -Mopsi, Anda dapat meminta deteksi salinan tambahan dalam file yang diubah dengan menggunakan -Copsi ( -Cmenyiratkan -M), dan Anda dapat meminta deteksi salinan lebih mahal di antara semua file dengan --find-copies-harderatau -C -C(yang menyiratkan -C, yang menyiratkan, -M). Lihat halaman manual git-diff .

Anda juga dapat mengonfigurasi git untuk selalu melakukan pengubahan nama deteksi dengan menetapkan diff.renamesnilai true boolean (misalnya trueatau 1), dan Anda dapat meminta git untuk melakukan deteksi salin juga dengan mengaturnya ke copyatau copies. Lihat halaman git-config .

Periksa juga -lopsi untuk git diffdan variabel konfigurasi terkait diff.renameLimit.


Catatan yang git log <pathspec>berfungsi berbeda di Git: di sini <pathspec>adalah set pembatas jalur, di mana path dapat menjadi (sub) nama direktori. Ini menyaring dan menyederhanakan riwayat sebelum mengubah nama dan menyalin deteksi mulai berlaku. Jika Anda ingin mengikuti penggantian nama dan salinan, gunakan git log --follow <filename>(yang saat ini agak terbatas, dan hanya berfungsi untuk satu file).

Jakub Narębski
sumber
1
@allyourcode: Apa yang membuat Anda bingung? Untuk mengaktifkan deteksi salin secara default Anda setel diff.renameske copies(misalnya ' git config diff.renames copies'). Saya setuju bahwa ini sedikit berlawanan dengan intuisi.
Jakub Narębski
Satu bagian yang sepertinya tidak bisa saya uraikan adalah "dan Anda dapat meminta untuk melakukan secara default juga mengganti nama deteksi". Apakah Anda mengatakan ada empat nilai yang dapat digunakan diff.renames (true, 1, copy, copy), dan mereka semua melakukan hal yang sama?
allyourcode
1
@allyourcode: Maaf, saya belum memperhatikan ini. Tetap sekarang, terima kasih.
Jakub Narębski
4
@ peschü: Git menggunakan database objek yang ditujukan untuk konten sebagai penyimpanan repositori. Konten file disimpan dalam konten 'gumpalan' di bawah alamat yang SHA-1 hash konten (well, ketik + panjang + isi). Ini berarti bahwa konten yang diberikan hanya disimpan satu kali. Nb. deduplikasi otomatis ini adalah alasan di balik pembuatan sistem cadangan "bup", menggunakan format paket git.
Jakub Narębski
1
Tidak seperti solusi di bawah ini, ini tidak bekerja dengan pelacakan perubahan dalam rentang. Log Git memungkinkan argumen rentang ( git log -L123,456:file.xyz) yang dengan benar mengikuti penggantian nama, tetapi bukan salinan, dan Anda tidak dapat meneruskan - ikuti dalam kasus itu; juga, AFAICT, ini tidak bekerja dengan menyalahkan git.
Clément
57

2020-05-19: Solusi berikut ini memiliki keuntungan karena tidak mengubah log dari file asli, tidak membuat konflik gabungan, dan menjadi lebih pendek.

Anda dapat memaksa Git untuk mendeteksi riwayat file yang disalin dalam tiga komit:

  • Alih-alih menyalin, beralihlah ke cabang baru dan pindahkan file ke lokasi barunya di sana.
  • Tambahkan kembali file asli di sana.
  • Gabungkan cabang baru ke cabang asli dengan opsi no-fast-forward --no-ff.

(Kredit pergi ke Raymond Chen .)


Solusi pertama memiliki empat komitmen:

  • Alih-alih menyalin, beralihlah ke cabang baru dan pindahkan file ke lokasi barunya di sana.
  • Beralih ke cabang asli dan ganti nama file.
  • Gabungkan cabang baru ke cabang asli, selesaikan konflik sepele dengan menyimpan kedua file.
  • Kembalikan nama file asli di komit terpisah.

(Solusi diambil dari https://stackoverflow.com/a/44036771/1389680 .)

Robert Pollak
sumber
7
Kesederhanaan, singkatnya, 100% ... Jawaban ini adalah layanan publik ... memperbaiki segala sesuatu yang terlihat
ptim
1
Apa perbedaan antara movedan rename?
vovan
@vovan Apakah Anda mengacu pada fakta bahwa dalam bash Anda akan menggunakan mvuntuk kedua operasi? Saya menggunakan 'move' untuk case yang mungkin melibatkan pengubahan direktori file, dan 'rename' untuk case yang tidak ada.
Robert Pollak
1
Saya mencoba mengikuti resep (baru) ini dan tidak berhasil. Mungkin membantu jika Anda menunjukkan perintah yang sebenarnya.
Greg Lindahl
@RobertPollak Saya telah mencoba berbagai versi ini tetapi tidak berhasil. Dengan "memindahkan file", maksud Anda git mv orig new? Dengan "readd the original", maksud Anda cp new orig && git add orig?
ᆼ ᆺ ᆼ