Bagaimana saya bisa membuat Git mengikuti symlink?

217

Apakah yang terbaik adalah skrip shell yang menggantikan symlink dengan salinan, atau adakah cara lain untuk memberitahu Git untuk mengikuti symlink?

PS: Saya tahu itu tidak terlalu aman, tetapi saya hanya ingin melakukannya dalam beberapa kasus tertentu.

Mat
sumber
5
apakah ada kerugian menggunakan tautan keras untuk hal seperti ini?
Ehtesh Choudhury
12
Dengan Windows 7, "mklink / d" (tautan simbolik direktori) tidak berfungsi dengan git, tetapi "mklink / j" (juction) berfungsi dengan baik.
yoyo
1
Jika file di-autogenerasi oleh aplikasi yang membuat ulang sedemikian rupa sehingga menghapus file dan membuat yang baru, maka ya, ini adalah masalah yang tidak bisa diselesaikan oleh hardlink ke file.
Martin Pecka
1
@EhteshChoudhury Anda tidak dapat membuat tautan keras untuk direktori
Gaurav Kansal

Jawaban:

46

CATATAN: Nasihat ini sekarang kedaluwarsa sesuai komentar sejak Git 1.6.1. Git dulu berperilaku seperti ini, dan tidak lagi melakukannya.


Git secara default mencoba menyimpan symlink alih-alih mengikutinya (untuk kekompakan, dan umumnya yang diinginkan orang).

Namun, saya tidak sengaja berhasil menambahkan file di luar symlink ketika symlink adalah direktori.

Yaitu:

  /foo/
  /foo/baz
  /bar/foo --> /foo
  /bar/foo/baz

dengan melakukan

 git add /bar/foo/baz

tampaknya berfungsi ketika saya mencobanya. Namun perilaku itu tidak diinginkan oleh saya pada saat itu, jadi saya tidak dapat memberi Anda informasi lebih dari itu.

Kent Fredric
sumber
72
Berkomitmen 725b06050a083474e240a2436121e0a80bb9f175 dan 806d13b1ccdbdde4bbdfb96902791c4b7ed125f6 memperkenalkan perubahan yang berhenti Anda menambahkan file di luar direktori symlinked, jadi ini tidak akan bekerja di versi git sejak 1.6.1
Mark Longair
1
$ git add src / main / path / ConvertSymlinkToDir fatal: 'src / main / path / ConvertSymlinkToDir' berada di luar tautan simbolis
user1767316
2
@ user1767316 membaca semuanya, dan komentar. Dulu bekerja, tidak lagi. Perangkat lunak berubah, tetapi jawaban stack-overflow diterima tidak. Saya sudah mengklarifikasi ini belum berfungsi. Lihatlah jawaban lain.
Kent Fredric
ya @KentFrederic tetapi menyadap pesan kesalahan yang tepat kembali membantu menumpuk pencarian pengguna untuk solusi untuk masalahnya. mencoba untuk membatalkan downvote tetapi dikunci maaf. Di satu sisi jawaban Anda benar diberi peringatan, di sisi lain orang harus memberi prioritas untuk menjawab bekerja sekarang daripada di masa lalu
user1767316
143

Apa yang saya lakukan untuk menambahkan agar file dalam symlink ke Git (saya tidak menggunakan symlink tetapi):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Lakukan perintah ini di direktori yang dikelola Git. TARGETDIRECTORYharus dibuat sebelum SOURCEDIRECTORYdipasang ke dalamnya.

Ini berfungsi dengan baik di Linux, tetapi tidak pada OS X! Trik itu juga membantu saya dengan Subversi. Saya menggunakannya untuk memasukkan file dari akun Dropbox, tempat webdesigner melakukan tugasnya.

pengguna252400
sumber
8
Akan menjadi pendekatan yang sangat bagus jika sudo tidak diperlukan.
MestreLion
13
Untuk membatalkan ikatan ini, gunakan umount [mydir]. (+1 untuk tip luar biasa Anda, @ user252400)
JellicleCat
10
Ini hanya berfungsi selama sesi. Apa cara terbaik untuk menjadikannya "abadi"?
Adobe
17
@Adobe: letakkan di / etc / fstab, seperti: / sourcedir / targetdir none bind
Alexander Garden
8
sshfs dapat mencapai trik semacam itu tanpa memerlukan sudo, di sini.
PypeBros
75

Mengapa tidak membuat symlink sebaliknya? Berarti alih-alih menautkan dari repositori Git ke direktori aplikasi, tautkan sebaliknya.

Sebagai contoh, katakanlah saya sedang menyiapkan aplikasi yang diinstal ~/applicationyang memerlukan file konfigurasi config.conf:

  • Saya menambah config.confrepositori Git saya, misalnya di ~/repos/application/config.conf.
  • Lalu saya membuat symlink dari ~/applicationdengan menjalankan ln -s ~/repos/application/config.conf.

Pendekatan ini mungkin tidak selalu berhasil, tetapi sejauh ini berhasil bagi saya.

menara
sumber
5
Tampaknya menjadi satu-satunya cara, dan itu tidak terlalu buruk ... saya pikir Anda adalah pendekatan yang cukup elegan. git melacak konten, bukan file. Jadi menjaga semua konten bersama dan menghubungkan dari sana ke tempat lain masuk akal
MestreLion
12
Dalam kasus saya, saya ingin tautan dari satu repo git ke yang lain, jadi saya dapat mengedit file di kedua lokasi dan komit kembali ke remote masing-masing. Pada Windows 7, persimpangan ("mklink / j") melakukan trik.
yoyo
3
tentu saja. kadang jawabannya hanya sesederhana itu.
BBW Sebelum Windows
bagaimana jika Anda ingin mendapatkan kedua sumber DAN tujuan? (karena keduanya memiliki kode berbeda yang ingin Anda miliki dalam repositori yang berbeda)
DrGC
1
Tidak menjawab pertanyaan :( Saya ingin sebagian dari repositori saya disinkronkan ke iCloud saya. Sayangnya, iCloud tidak mengikuti symlink, jadi saya pikir saya dapat membuat git follow symlink, dan menyimpan file asli di iCloud. Ternyata tidak ada yang mengikuti symlinks: \
Jerry Green
49

Gunakan tautan keras sebagai gantinya. Ini berbeda dari tautan lunak (simbolik). Semua program, termasuk gitakan memperlakukan file sebagai file biasa. Perhatikan bahwa isi dapat dimodifikasi dengan mengubah baik sumber atau tujuan.

Di macOS (sebelum 10.13 Sierra Tinggi)

Jika Anda sudah menginstal git dan Xcode, instal hardlink . Ini adalah alat mikroskopis untuk membuat tautan keras .

Untuk membuat tautan keras, cukup:

hln source destination

macOS pembaruan Sierra Tinggi

Apakah Apple File System mendukung tautan keras direktori?

Tautan keras direktori tidak didukung oleh Apple File System. Semua tautan keras direktori dikonversi ke tautan simbolis atau alias ketika Anda mengonversi dari format volume HFS + ke APFS di macOS.

Dari FAQ APFS di developer.apple.com

Ikuti https://github.com/selkhateeb/hardlink/issues/31 untuk alternatif di masa mendatang.

Di Linux dan rasa Unix lainnya

The lnperintah dapat membuat hard link:

ln source destination

Di Windows (Vista, 7, 8, ...)

Seseorang menyarankan untuk menggunakan mklink membuat persimpangan pada Windows, tetapi saya belum mencobanya:

mklink /j "source" "destination"
fregante
sumber
7
Hanya sebuah catatan: ini pada dasarnya adalah apa yang saya cari, tetapi kemudian saya mengetahui bahwa di Linux, sebuah hardlink sayangnya tidak dapat melewati batas filesystem (yang merupakan kasus penggunaan saya).
sdaau
26
Anda tidak dapat menghubungkan tautan ke direktori, bukan?
Nanne
1
ln source destinationbekerja di OS X juga. Diuji pada El Capitan.
Mahdi Dibaiee
7
@Nanne tidak ada, tetapi Anda dapat melakukannya: cp -al source destination. `-l 'berarti file tautan keras alih-alih menyalin.
Paolo
6
Sayangnya Anda tidak dapat menghubungkan tautan dengan direktori, atau melintasi batas-batas sistem file. Ini membuat solusi ini dua kali lipat tidak berfungsi bagi saya.
Konrad Rudolph
25

Ini adalah kait pra-komit yang menggantikan gumpalan symlink dalam indeks, dengan konten dari symlink tersebut.

Masukkan ini .git/hooks/pre-commit, dan membuatnya dapat dieksekusi:

#!/bin/sh
# (replace "find ." with "find ./<path>" below, to work with only specific paths)

# (these lines are really all one line, on multiple lines for clarity)
# ...find symlinks which do not dereference to directories...
find . -type l -exec test '!' -d {} ';' -print -exec sh -c \
# ...remove the symlink blob, and add the content diff, to the index/cache
    'git rm --cached "$1"; diff -au /dev/null "$1" | git apply --cached -p1 -' \
# ...and call out to "sh".
    "process_links_to_nondir" {} ';'

# the end

Catatan

Kami menggunakan fungsionalitas yang sesuai dengan POSIX sebanyak mungkin; Namun, diff -atidak sesuai dengan POSIX, mungkin antara lain.

Mungkin ada beberapa kesalahan / kesalahan dalam kode ini, meskipun agak diuji.

Abbafei
sumber
4
Sangat menyenangkan melihat upaya untuk benar-benar menjawab pertanyaan untuk file dan bukan direktori. Namun, catatan bahwa di atas akan masih menunjukkan typechangedi git statusuntuk file-file yang sebenarnya symlink meskipun git sekarang hal-hal yang mereka tidak.
David Fraser
1
Terima kasih untuk ini; hanya ingin tahu, ada apa process_links_to_nondir?
sdaau
@sdaau Ini adalah nama / argv[0]yang digunakan sebagai nama-perintah untuk shproses. (Butuh sedikit waktu untuk memikirkannya, karena saya tidak ingat apa itu β˜ΊπŸ˜ƒ)
Abbafei
3
@Abbafei Bisakah Anda memodifikasi skrip agar berfungsi pada Ubuntu (14.04)? Itu menunjukkan find: missing argument to -exec'. Mungkin diperlukan langkah demi langkah untuk mengeksekusi perintah alih-alih memipakan & menggabungkan semuanya menjadi satu baris.
Khurshid Alam
1
@ KhurshidAlam Bagi saya itu berfungsi untuk menghapus baris komentar di antara baris perintah. Namun, kait tidak berfungsi seperti yang diharapkan (saya mendapatkan typechange@DavidFraser seperti, tetapi file yang ditautkan tampaknya tidak akan dipentaskan lagi)
Scz
14

Aktif MacOS(Saya punya Mojave / 10.14, gitversi 2.7.1), gunakan bindfs.

brew install bindfs

cd /path/to/git_controlled_dir

mkdir local_copy_dir

bindfs </full/path/to/source_dir> </full/path/to/local_copy_dir>

Sudah diisyaratkan oleh komentar lain, tetapi tidak jelas disediakan dalam jawaban lain. Semoga ini menghemat waktu seseorang.

ijoseph
sumber
tampaknya bagus untuk tim yang semuanya berjalan di mac os, saya pikir tautan keras yang diuraikan di bawah ini akan berfungsi untuk windows dan linux.
Devin G Rhode
Ini sangat membantu, dan saya pikir solusi terbaik untuk kemampuan yang bermanfaat tetapi tidak ada pada MacOS. Namun perlu dicatat bahwa saya mendapatkan Failed to resolve... No such file or directorykesalahan kecuali saya menggunakan nama path lengkap dengan bindfsperintah.
electromaggot
Terima kasih @electromaggot. Menambahkan klarifikasi bahwa jalur lengkap diperlukan
ijoseph
1
Berfungsi bagus di Macos Catalina!
Jerry Green
13

Saya dulu menambahkan file di luar symlink untuk beberapa waktu sekarang. Ini digunakan untuk bekerja dengan baik, tanpa membuat pengaturan khusus. Karena saya memperbarui ke Git 1.6.1, ini tidak berfungsi lagi.

Anda mungkin bisa beralih ke Git 1.6.0 untuk membuat ini berfungsi. Saya harap versi Git di masa depan akan memiliki bendera untuk git-addmemungkinkannya mengikuti symlink lagi.

Erik Schnetter
sumber
12

Saya bosan dengan setiap solusi di sini baik yang sudah usang atau membutuhkan root, jadi saya membuat solusi berbasis LD_PRELOAD (hanya Linux).

Itu menghubungkan ke internal Git, menimpa 'apakah ini symlink?' berfungsi, memungkinkan symlink untuk diperlakukan sebagai isinya. Secara default, semua tautan ke luar repo diuraikan; lihat tautan untuk detailnya.

Alcaro
sumber
Solusi yang sangat kreatif digunakan LD_PRELOADuntuk mengganti fungsi perpustakaan!
iBug
Ya, tetapi harus diuraikan di sini. Bisakah kamu melakukan itu?
Peter Mortensen
Tidak yakin berapa banyak elaborasi akan membantu; kecuali saya menyalin seluruh kode sumber, jawaban ini akan selalu bergantung pada tautan itu, tempat readme juga dapat ditemukan. Tapi ya, saya kira saya bisa mereproduksi bagian-bagian penting dari readme.
Alcaro
Ini tidak dikompilasi pada OS X (Mojave 10.14.2). Dapatkan empat kesalahan yang mengeluh tentang 'strchrnul' (maksud Anda 'strchr'?) Dan satu tentang '__xstat64' (maksud Anda '__lxstat64'?). Akhirnya saya mendapatkan "akses anggota ke dalam kesalahan 'dirent64'" tipe tidak lengkap. Terjadi terlepas dari apakah saya menggunakan "make", "make OPT = 1" atau "sh install.sh".
Erik Veland
@ErikVeland Saya mencoba sedikit, tetapi sepertinya OSX tidak mendukung LD_PRELOAD, atau yang serupa. Berbagai dokumen menyarankan berbagai hal, tetapi semuanya sudah berumur beberapa tahun, dan Apple suka barang-barang yang sudah ketinggalan zaman; Saya tidak bisa membuat mereka bekerja. Maaf.
Alcaro
6

Dengan Gitp4 (Q1 2015), ada satu kasus lain di mana Git tidak akan mengikuti symlink lagi: lihat commit e0d201b oleh Junio ​​C Hamano ( gitster) (pengelola utama Git)

apply: jangan menyentuh file di luar tautan simbolik

Karena Git melacak tautan simbolik sebagai tautan simbolik, jalur yang memiliki tautan simbolik di bagian terdepannya (misalnya path/to/dir/file, di mana path/to/dirtautan simbolik ke tempat lain, baik itu di dalam atau di luar pohon yang bekerja) tidak pernah dapat muncul dalam tambalan yang berlaku secara sah , kecuali tambalan yang sama terlebih dahulu menghapus tautan simbolik untuk memungkinkan direktori dibuat di sana.

Mendeteksi dan menolak tambalan semacam itu.

Demikian pula, ketika input membuat tautan simbolik path/to/dirdan kemudian membuat file path/to/dir/file, kita perlu menandainya sebagai kesalahan tanpa benar-benar membuat path/to/dirtautan simbolik di sistem file.

Alih-alih, untuk setiap tambalan di input yang meninggalkan jalur (yaitu bukan penghapusan) di hasilnya, kami memeriksa semua lintasan terkemuka terhadap pohon yang dihasilkan yang akan dibuat oleh tambalan dengan memeriksa semua tambalan di input dan kemudian target tambalan aplikasi (baik indeks atau pohon kerja).

Dengan cara ini, kami:

  • menangkap kerusakan atau kesalahan untuk menambahkan tautan simbolis path/to/dirdan file path/to/dir/filepada saat yang sama,
  • sambil memungkinkan tambalan yang valid yang menghapus simbol link path/to/dirdan kemudian menambahkan file path/to/dir/file.

Itu berarti, dalam hal ini, pesan kesalahan tidak akan seperti generik "%s: patch does not apply", tetapi yang lebih spesifik:

affected file '%s' is beyond a symbolic link
VONC
sumber
4

Hmmm, mount --bindsepertinya tidak berhasil pada Darwin.

Adakah yang punya trik itu?

[diedit]

OK, saya menemukan jawabannya di Mac OS X adalah membuat hardlink. Kecuali bahwa API itu tidak diekspos melalui ln, jadi Anda harus menggunakan program kecil Anda sendiri untuk melakukan ini. Berikut ini tautan ke program itu:

Membuat tautan keras direktori di Mac OS X

Nikmati!

J Chris A
sumber
1
Jika direktori tujuan hardlink ini adalah subdirektori dari repo git lain, ini akan menjadi kekacauan. Melakukan operasi git di hardlink akan berlaku untuk repo git lain ini. Cukup periksa kembali apa yang Anda lakukan.
yegle
4
Dimungkinkan untuk melakukan ini melalui code.google.com/p/bindfs yang dapat diinstal menggunakan port.
Kit Sunde
0

Saya menggunakan Git 1.5.4.3 dan ini mengikuti symlink yang diteruskan jika memiliki garis miring. Misalnya

# Adds the symlink itself
$ git add symlink

# Follows symlink and adds the denoted directory's contents
$ git add symlink/
Peter Mortensen
sumber
5
setidaknya pada OSX ini menghasilkanfatal: 'src/' is beyond a symbolic link
Dan Rosenstark
2
Seperti dijelaskan oleh @Mark Longair, ini hanya bekerja sampai git 1.6.1
MestreLion
itu masalah saya, terima kasih!
Mike Q
0

Konversi dari symlink dapat bermanfaat. Tautkan dalam folder Git alih-alih symlink oleh skrip .

Yurij73
sumber
Anda ingin menambahkan rincian lebih lanjut ke jawaban Anda?
Devin G Rhode