Bagaimana Git menangani tautan simbolik?

1607

Jika saya memiliki file atau direktori yang merupakan tautan simbolik dan saya komit ke repositori Git, apa yang terjadi padanya?

Saya akan berasumsi bahwa itu meninggalkannya sebagai tautan simbolis sampai file dihapus dan kemudian jika Anda menarik file kembali dari versi lama itu hanya membuat file normal.

Apa yang dilakukan ketika saya menghapus file yang dirujuk? Apakah itu hanya melakukan tautan yang menggantung?

Alex
sumber
19
.gitignoremelihat symlink sebagai file, bukan folder.
0xcaff
6
Yah, jelas ada lebih banyak pertanyaan daripada jawaban yang tersirat. Sebagai contoh, saya bertanya-tanya berikut ini: jika saya membuat tautan sym di repositori saya ke beberapa file besar di repositori itu, dorong perubahan, dan kemudian tarik perubahan itu ke komputer lain, apa yang akan terjadi? Apakah file besar akan disimpan sebagai file besar di kedua lokasi, atau akankah tautan sym dipertahankan, sehingga pada mesin yang baru, file tautan menunjuk ke file besar asli?
jvriesem
7
Ini adalah utas lama tetapi komentar ini mungkin masih berguna. Menanggapi jviesem, tautan lunak pada dasarnya adalah file dengan nama file lain. Jadi, begitu Anda menariknya ke mesin yang berbeda, tautan akan diunduh dan akan memiliki nama file besar di sistem file asli. Jika pada mesin baru namanya tidak valid, maka tautan akan memiliki nama yang tidak valid. File besar tidak akan diunduh ke mesin baru.
lasaro
6
@ Lasaro, cara untuk menghindari tautan yang rusak di git repo adalah dengan selalu menggunakan jalur relatif ketika membuat symlink, menggunakan ../..sesuai kebutuhan.
Wildcard
8
Perhatikan bahwa di sebagian besar versi Windows Anda memerlukan izin tinggi untuk membuat symlink. Jika Anda menggunakan Windows dan git pullmembuat file alih-alih symlink, coba jalankan klien Git Anda sebagai administrator.
axmrnv

Jawaban:

1348

Git hanya menyimpan konten tautan (yaitu jalur dari objek sistem file yang ditautkannya) dalam 'gumpalan' seperti halnya untuk file normal. Kemudian menyimpan nama, mode dan jenis (termasuk fakta bahwa itu adalah symlink) di objek pohon yang mewakili direktori yang berisi.

Ketika Anda checkout pohon yang berisi tautan, itu mengembalikan objek sebagai symlink terlepas dari apakah objek sistem file target ada atau tidak.

Jika Anda menghapus file yang dirujuk symlink, itu tidak memengaruhi symlink yang dikontrol Git. Anda akan memiliki referensi yang menggantung. Terserah kepada pengguna untuk menghapus atau mengubah tautan untuk menunjuk ke sesuatu yang valid jika diperlukan.

CB Bailey
sumber
328
BTW. Jika Anda menggunakan sistem file seperti FAT yang tidak mendukung tautan simbolik, dan repositori Anda menggunakannya, Anda dapat mengatur core.symlinksvariabel konfigurasi menjadi false, dan symlink akan diperiksa sebagai file teks biasa berukuran kecil yang berisi teks tautan.
Jakub Narębski
14
@ JakubNarębski Saya melihat ini sebelumnya. Ada file teks di repo kami dengan satu baris, jalur ke perpustakaan yang kami gunakan. Tidak tahu apa tujuan dari itu. Saya tahu sekarang apa yang terjadi.
Matt K
25
Saya ragu-ragu untuk mengomentari jawaban yang sangat terpilih tetapi saya pikir ungkapan "seperti halnya file biasa" mungkin menyesatkan pendatang baru.
Matius Hannigan
10
(kehabisan waktu edit) Ini seperti file normal hanya karena kontennya dalam gumpalan. Perbedaan penting adalah bahwa untuk file normal gumpalan adalah konten file tetapi untuk symlink gumpalan memiliki pathname dari file yang ditautkan. @ JakubNarębski Mengenai "file teks kecil biasa" .. Anda akan berharap mereka kecil dan teks tetapi tentu saja gumpalan adalah gumpalan dan berpotensi bisa besar dan biner. Lihat stackoverflow.com/questions/18411200/… untuk saat file salah ketik sebagai symlink.
Matthew Hannigan
2
Pastikan untuk memeriksa pengaturan global Anda untuk symlink dan pengaturan lokal untuk symlink. Jika pengaturan disalin dari TortiseGit atau windows, maka Anda bisa symlinks = falsemengacaukannya.
phyatt
251

Anda dapat mengetahui apa yang Git lakukan dengan file dengan melihat apa yang dilakukannya ketika Anda menambahkannya ke indeks. Indeks seperti pra-komit. Dengan indeks yang dikomit, Anda dapat menggunakan git checkoutuntuk membawa semua yang ada di indeks kembali ke direktori kerja. Jadi, apa yang dilakukan Git ketika Anda menambahkan tautan simbolis ke indeks?

Untuk mengetahuinya, pertama, buat tautan simbolik:

$ ln -s /path/referenced/by/symlink symlink

Git belum tahu tentang file ini. git ls-filesmemungkinkan Anda memeriksa indeks Anda ( -shasil cetak statseperti):

$ git ls-files -s ./symlink
[nothing]

Sekarang, tambahkan konten tautan simbolik ke toko objek Git dengan menambahkannya ke indeks. Ketika Anda menambahkan file ke indeks, Git menyimpan kontennya di toko objek Git.

$ git add ./symlink

Jadi, apa yang ditambahkan?

$ git ls-files -s ./symlink
120000 1596f9db1b9610f238b78dd168ae33faa2dec15c 0       symlink

Hash adalah referensi ke objek dikemas yang dibuat di toko objek Git. Anda bisa memeriksa objek ini jika Anda mencari di .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15croot repositori Anda. Ini adalah file yang disimpan Git di repositori, yang nanti bisa Anda periksa. Jika Anda memeriksa file ini, Anda akan melihatnya sangat kecil. Itu tidak menyimpan konten file yang ditautkan.

(Catatan 120000adalah mode yang tercantum dalam ls-filesoutput. Ini akan menjadi sesuatu seperti 100644untuk file biasa.)

Tapi apa yang dilakukan Git dengan objek ini ketika Anda memeriksanya dari repositori dan ke sistem file Anda? Itu tergantung pada core.symlinkskonfigurasi. Dari man git-config:

core.symlinks

Jika salah, tautan simbolik diperiksa sebagai file biasa berukuran kecil yang berisi teks tautan.

Jadi, dengan tautan simbolik dalam repositori, saat checkout Anda mendapatkan file teks dengan referensi ke path sistem file lengkap, atau tautan simbolik yang tepat, tergantung pada nilai core.symlinkskonfigurasi.

Bagaimanapun, data yang dirujuk oleh symlink tidak disimpan dalam repositori.

Dmitry Minkovsky
sumber
1
Jawaban hebat
CervEd
147

Catatan "Editor": Posting ini mungkin berisi informasi yang ketinggalan zaman. Silakan lihat komentar dan pertanyaan ini mengenai perubahan dalam Git sejak 1.6.1.

Direktori yang dikaitkan:

Penting untuk mencatat apa yang terjadi ketika ada direktori yang merupakan tautan lunak. Setiap Git pull dengan pembaruan menghapus tautan dan menjadikannya direktori normal. Inilah yang saya pelajari dengan cara yang sulit. Beberapa wawasan di sini dan di sini.

Contoh

Sebelum

 ls -l
 lrwxrwxrwx 1 admin adm   29 Sep 30 15:28 src/somedir -> /mnt/somedir

git add/commit/push

It remains the same

Setelah git pullDAN beberapa pembaruan ditemukan

 drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir
Shekhar
sumber
4
Perlu dicatat bahwa peringatan ini tentang direktori yang disinkronkan tidak berlaku untuk symlink yang berversi. Kasus tepi utama yang dimaksud adalah bahwa orang-orang yang menghubungkan beberapa atau semua pohon yang bekerja ke jalur yang berbeda (katakanlah ke partisi yang berbeda dengan lebih banyak ruang disk) dan mengharapkan git untuk memeriksa kode melalui symlink yang ada. Artinya, jika Anda memiliki proyek yang berisi symlink berversi ke file atau direktori, perilaku symlink-as-blob yang normal akan mempertahankan symlink, dengan benar mengubah versi ke symlink tersebut, dan jika tidak berfungsi seperti yang diharapkan.
John Whitley
Perilaku di atas diuji dengan git 1.6.5.6; tapi saya sangat curiga bahwa perilaku versi sudah benar di git untuk beberapa waktu.
John Whitley
22
Apakah perilaku ini ada di semua versi git atau apakah ini sudah diperbaiki?
jbotnik
24
Sepertinya perilaku ini sudah diperbaiki sekarang, lihat: stackoverflow.com/a/1943656/1334781
Ron Wertlen
2
Shekar: Apakah Anda akan mengedit jawaban Anda untuk mencerminkan perubahan git dalam beberapa tahun terakhir?
einpoklum