Git - Perbedaan Antara 'Asumsikan-tidak berubah' dan 'Lewati-worktree'

450

Saya memiliki perubahan lokal pada file yang tidak ingin saya komit ke repositori saya. Ini adalah file konfigurasi untuk membangun aplikasi pada server, tetapi saya ingin membangun secara lokal dengan pengaturan yang berbeda. Secara alami, file selalu muncul ketika saya melakukan 'git status' sebagai sesuatu yang akan dipentaskan. Saya ingin menyembunyikan perubahan khusus ini dan tidak melakukan itu. Saya tidak akan membuat perubahan lain pada file.

Setelah beberapa penggalian di sekitar, saya melihat 2 opsi: 'menganggap-tidak berubah' dan 'lewati-worktree'. Pertanyaan sebelumnya di sini berbicara tentang mereka tetapi tidak benar-benar menjelaskan perbedaan mereka. Pertanyaan saya adalah ini: bagaimana dua perintah itu berbeda? Mengapa seseorang menggunakan yang satu atau yang lain?

ckb
sumber
1
Biasanya saya menggunakan .gitignoreuntuk tujuan yang sama. Apakah solusi ini akan berhasil untuk Anda?
samuil
45
samuil, .gitignore mengabaikan penambahan, tidak berubah. Ketika file sudah ada di git, itu akan dilacak jika terdaftar di .gitignore
Grigory
tetapi tidak dapatkah seseorang menghapus semua dan menambahkan semua untuk "menyegarkan" seperti yang dijelaskan di sini? stackoverflow.com/questions/7075923/… @Grigory
Daniel Springer
2
File tidak boleh diabaikan, jika saya mendapatkan maksud OP dengan benar. File tersebut harus ada di repositori, tetapi perubahan yang sangat spesifik yang dibuatnya tidak boleh dilakukan - setidaknya sekarang.
Simone

Jawaban:

666

Kamu ingin skip-worktree.

assume-unchangeddirancang untuk kasus-kasus di mana mahal untuk memeriksa apakah sekelompok file telah dimodifikasi; ketika Anda mengatur bit, git(tentu saja) mengasumsikan file yang sesuai dengan bagian indeks itu belum dimodifikasi dalam copy pekerjaan. Jadi itu menghindari kekacauan statpanggilan. Bit ini hilang setiap kali entri file dalam indeks berubah (jadi, ketika file diubah hulu).

skip-worktreelebih dari itu: bahkan ketika git tahu bahwa file telah dimodifikasi (atau perlu diubah oleh reset --hardatau sejenisnya), itu akan berpura-pura belum, menggunakan versi dari indeks sebagai gantinya. Ini berlanjut sampai indeks dibuang.

Ada ringkasan yang baik dari konsekuensi perbedaan ini dan kasus penggunaan khas di sini: http://fallengamer.livejournal.com/93321.html .

Dari artikel itu:

  • --assume-unchangedmengasumsikan bahwa pengembang tidak boleh mengubah file. Bendera ini dimaksudkan untuk meningkatkan kinerja untuk folder yang tidak berubah seperti SDK.
  • --skip-worktreeberguna ketika Anda menginstruksikan git untuk tidak menyentuh file tertentu karena pengembang harus mengubahnya. Sebagai contoh, jika repositori utama hulu meng-host beberapa file konfigurasi siap-produksi dan Anda tidak ingin secara tidak sengaja melakukan perubahan pada file-file itu, --skip-worktreepersis seperti yang Anda inginkan.
Borealid
sumber
3
Itu masuk akal. skip-worktree tampaknya memang cara untuk pergi. Terima kasih!
ckb
100
Catatan kecil untuk menghemat pencarian dan membaca beberapa detik. Untuk membatalkan --skip-worktreeefek dan menghapus tanda bendera ada --no-skip-worktreeopsi. Cara kerjanya persis sama. Ini berguna jika ada yang tergelincir dan file yang salah ditandai, atau jika keadaan telah berubah dan file yang sebelumnya dilewati tidak boleh diabaikan lagi.
drdaeman
18
Untuk menjawab pertanyaan saya sendiri di atas, perbedaan antara menggunakan --skip-worktreedan .git/info/excludefile adalah bahwa yang pertama akan bekerja bahkan untuk file yang saat ini dilacak. .git/info/exclude, seperti .gitignore, hanya akan mencegah secara tidak sengaja menambahkan file yang tidak terlacak ke indeks, tetapi tidak membuat perubahan pada file yang sudah dilacak.
LinusR
13
Bisakah ini didorong ke remote dan dipertahankan oleh semua klon?
CMCDragonkai
4
Hanya penggunaannya , Bu:git update-index --skip-worktree <file_name>
ruffin
108

Catatan: fallengamer melakukan beberapa tes pada 2011 (jadi mungkin sudah ketinggalan zaman), dan inilah temuannya :

Operasi

  • File diubah baik dalam repositori lokal dan upstream
    git pull:
    Git tetap mempertahankan perubahan lokal.
    Dengan demikian Anda tidak akan kehilangan data apa pun yang ditandai dengan salah satu bendera secara tidak sengaja.
    • File dengan assume-unchangedflag: Git tidak akan menimpa file lokal. Sebaliknya itu akan menghasilkan konflik dan saran bagaimana menyelesaikannya
    • File dengan skip-worktreeflag: Git tidak akan menimpa file lokal. Sebaliknya itu akan menghasilkan konflik dan saran bagaimana menyelesaikannya

  • File diubah baik dalam repositori lokal dan upstream, tetap mencoba untuk menarik. Menggunakan hasil dalam beberapa pekerjaan manual tambahan, tetapi setidaknya Anda tidak akan kehilangan data apa pun jika Anda memiliki perubahan lokal.
    git stash
    git pull
    skip-worktree
    • File dengan assume-unchangedflag: Buang semua perubahan lokal tanpa ada kemungkinan untuk mengembalikannya. Efeknya seperti ' git reset --hard'. ' git pull' Panggilan akan berhasil
    • File dengan skip-worktreeflag: Stash tidak akan berfungsi pada skip-worktreefile. ' git pull' akan gagal dengan kesalahan yang sama seperti di atas. Pengembang dipaksa untuk mengatur ulang skip-worktreeflag secara manual untuk dapat menyembunyikan dan menyelesaikan kegagalan pull.

  • Tidak ada perubahan lokal, file upstream berubah Kedua flag tidak akan mencegah Anda mendapatkan perubahan upstream. Git mendeteksi bahwa Anda melanggar janji dan memilih untuk mencerminkan kenyataan dengan mengatur ulang bendera.
    git pull
    assume-unchanged
    • File dengan assume-unchangedbendera: Konten diperbarui, bendera hilang.
      ' git ls-files -v' akan menunjukkan bahwa bendera diubah ke H(dari h).
    • File dengan skip-worktreebendera: Konten diperbarui, bendera dipertahankan.
      ' git ls-files -v' akan menampilkan Sbendera yang sama seperti sebelum pull.

  • Dengan file lokal diubah, Git tidak menyentuh file dan mencerminkan kenyataan (file yang dijanjikan tidak akan berubah sebenarnya telah diubah) untuk file.
    git reset --hard
    skip-worktreeassume-unchanged
    • File dengan assume-unchangedflag: Konten file dikembalikan. Bendera diatur ulang ke H(dari h).
    • File dengan skip-worktreeflag: Konten file utuh. Bendera tetap sama.

Dia menambahkan analisis berikut:

  • Sepertinya skip-worktreesedang berusaha sangat keras untuk mempertahankan data lokal Anda . Tapi itu tidak mencegah Anda untuk mendapatkan perubahan di hulu jika itu aman. Plus git tidak menyetel ulang flag pull.
    Tetapi mengabaikan perintah ' reset --hard' bisa menjadi kejutan buruk bagi pengembang.

  • Assume-unchangedflag bisa hilang pada pulloperasi dan perubahan lokal di dalam file tersebut sepertinya tidak penting untuk git.

Lihat:

Dia menyimpulkan:

Sebenarnya tak satu pun dari bendera itu cukup intuitif .

  • assume-unchangedmengasumsikan bahwa pengembang tidak boleh mengubah file. Jika file diubah - maka perubahan itu tidak penting. Bendera ini dimaksudkan untuk meningkatkan kinerja untuk folder yang tidak berubah seperti SDK.
    Tetapi jika janji itu rusak dan sebuah file benar-benar diubah, git mengembalikan bendera untuk mencerminkan kenyataan. Mungkin boleh saja memiliki beberapa flag yang tidak konsisten di folder yang pada umumnya tidak dimaksudkan untuk diubah.

  • Di sisi lain skip-worktreeberguna ketika Anda menginstruksikan git untuk tidak menyentuh file tertentu. Itu berguna untuk file konfigurasi yang sudah dilacak.
    Repositori utama hulu meng-host beberapa konfigurasi siap-produksi tetapi Anda ingin mengubah beberapa pengaturan dalam konfigurasi untuk dapat melakukan beberapa pengujian lokal. Dan Anda tidak ingin secara tidak sengaja memeriksa perubahan pada file tersebut untuk memengaruhi konfigurasi produksi. Dalam hal itu skip-worktreemembuat adegan yang sempurna.


Dengan Git 2.25.1 (Februari 2020), "Sebenarnya tidak satu pun dari bendera yang cukup intuitif" yang disebutkan di atas lebih lanjut diklarifikasi:

Lihat komit 7a2dc95 , komit 1b13e90 (22 Jan 2020) oleh brian m. carlson ( bk2204) .
(Digabung oleh Junio ​​C Hamano - gitster- dalam komit 53a8329 , 30 Jan 2020)
( Daftar Mailing Git )

doc: menghalangi pengguna untuk mencoba mengabaikan file yang dilacak

Ditandatangani oleh: Jeff King
Ditandatangani oleh: brian m. carlson

Sangat umum bagi pengguna untuk ingin mengabaikan perubahan pada file yang dilacak Git.

Skenario umum untuk kasus ini adalah pengaturan IDE dan file konfigurasi, yang umumnya tidak boleh dilacak dan mungkin dihasilkan dari file yang dilacak menggunakan mekanisme templating.

Namun, pengguna belajar tentang bit asumsi-tidak berubah dan lewati-worktree dan mencoba menggunakannya untuk melakukan hal ini.

Ini bermasalah, karena ketika bit-bit ini diatur, banyak operasi berperilaku seperti yang diharapkan pengguna, tetapi mereka biasanya tidak membantu ketika git checkoutperlu mengganti file.

Tidak ada perilaku yang masuk akal dalam kasus ini, karena kadang-kadang data berharga, seperti file konfigurasi tertentu, dan terkadang itu adalah data yang tidak relevan yang dengan senang hati akan dibuang oleh pengguna.

Karena ini bukan konfigurasi yang didukung dan pengguna cenderung menyalahgunakan fitur yang ada untuk tujuan yang tidak diinginkan, menyebabkan kesedihan dan kebingungan umum , mari mendokumentasikan perilaku yang ada dan perangkap dalam dokumentasi untuk git update-indexsehingga pengguna tahu mereka harus mencari solusi alternatif.

Selain itu, mari berikan solusi yang disarankan untuk menangani kasus umum file konfigurasi, karena ada pendekatan terkenal yang berhasil digunakan di banyak lingkungan.

The git update-indexhalaman manual sekarang termasuk:

Pengguna sering mencoba menggunakan bit assume-unchangeddan skip-worktreememberi tahu Git untuk mengabaikan perubahan pada file yang dilacak. Ini tidak berfungsi seperti yang diharapkan, karena Git masih dapat memeriksa file pohon kerja terhadap indeks saat melakukan operasi tertentu. Secara umum, Git tidak menyediakan cara untuk mengabaikan perubahan pada file yang dilacak, sehingga solusi alternatif disarankan.

Sebagai contoh, jika file yang ingin Anda ubah adalah semacam file config, repositori dapat menyertakan contoh file config yang kemudian dapat disalin ke nama yang diabaikan dan diubah. Repositori bahkan dapat menyertakan skrip untuk memperlakukan file sampel sebagai templat, memodifikasi dan menyalinnya secara otomatis.

Bagian terakhir itulah yang saya jelaskan driver filter konten khas berdasarkan skrip smudge / clean .

VONC
sumber
7
Jika Anda memiliki skip-worktree pada file dan perubahan hulu, Anda mendapatkan "silakan komit atau simpanan" ketika Anda mencoba untuk menarik, meskipun status git tidak melaporkan file seperti yang diubah. Bagaimana Anda bisa menghindari ini, sehingga perubahan lokal dapat bertahan saat orang-orang berkeliaran dengan pengaturan produksi pada asal?
GreenAsJade
3
Ya, saya dapat mengonfirmasi bahwa Anda melakukannya. Ini berarti masih sangat sulit untuk memiliki file lokal yang ingin Anda pertahankan secara berbeda dari aslinya.
GreenAsJade
1
@GreenAsJade dari yang tampak kuno. Apakah Anda bisa mengujinya dengan 2.2.x?
VonC
1
@VonC, Tautan ke "Komentar Junio" tidak ada dalam riwayat revisi. Apakah ini yang Anda maksud?
Michael - Di mana Clay Shirky
1
@Michael Tangkapan yang bagus, terima kasih. Saya telah mengembalikan tautan itu ke jawabannya.
VonC