Kapan "w20> tarik" berbahaya?

Saya memiliki seorang kolega yang mengklaim bahwa git pull buruk dan menjadi marah setiap kali seseorang menggunakannya.

Perintah git pull adalah cara kanonik untuk memperbarui repositori lokal. Apakah masalah git pull ? Masalah apa yang diciptakannya? Apakah ada cara yang lebih baik untuk memperbarui repositori git?

396
10 марта '13 в 1:23 2013-03-10 01:23 Richard Hansen bertanya pada 10 Maret '13 pada 1:23 2013-03-10 01:23
@ 4 balasan

Ringkasan

Secara default, git pull menciptakan komit gabungan, yang menambahkan noise dan kerumitan pada sejarah kode. Selain itu, pull membuatnya mudah untuk tidak memikirkan bagaimana perubahan Anda dapat dipengaruhi oleh perubahan yang masuk.

Perintah git pull aman selama hanya melakukan penggabungan cepat. Jika git pull hanya dikonfigurasi untuk penggabungan yang dipercepat dan ketika penggabungan yang dipercepat tidak dimungkinkan, Git akan keluar dengan kesalahan. Ini akan memberi Anda kesempatan untuk memeriksa komitmen yang masuk, pikirkan tentang bagaimana hal itu dapat memengaruhi komitmen lokal Anda, dan pilih tindakan terbaik (gabung, pindah, atur u>

Dengan Git 2.0 dan yang lebih baru, Anda dapat menjalankan:

 git config --global pull.ff only 

ubah perilaku default hanya untuk memajukan. Di versi Git antara 1.6.6 dan 1.9.x, Anda harus mengetikkan kebiasaan:

 git pull --ff-only 

Namun, di semua versi Git, saya sarankan git up alias git up sebagai berikut:

 git config --global alias.up '!git remote update -p; git merge --ff-only @{u}' 

dan menggunakan git up bukan git pull . Saya lebih suka ini alias git pull --ff-only karena:

  • ini bekerja dengan semua versi git (bukan kuno),
  • ia memilih semua cabang hulu (bukan hanya cabang yang sedang Anda kerjakan), dan
  • membersihkan cabang origin/* lama yang tidak lagi ada di hulu.

git pull masalah

git pull tidak buruk jika digunakan dengan benar. Beberapa perubahan terbaru pada Git telah menyederhanakan penggunaan git pull tepat, tetapi sayangnya, perilaku git pull biasa memiliki beberapa masalah secara default:

  • ini memperkenalkan non-linearitas yang tidak perlu ke dalam cerita.
  • ini membuatnya mudah untuk secara tidak sengaja memasukkan komitmen yang sengaja dipindahkan ke hulu
  • itu mengubah direktori kerja Anda dengan cara yang tidak terduga.
  • berhenti sejenak dalam apa yang Anda lakukan untuk melihat pekerjaan orang lain, git pull mengganggu
  • ini membuatnya sulit untuk reboot dengan benar ke cabang jauh
  • tidak menghapus cabang yang dihapus di repo jarak jauh

Masalah-masalah ini dijelaskan secara lebih rinci di bawah ini.

Cerita nonlinier

Secara default, perintah git pull setara dengan git fetch diikuti oleh git merge @{u} . Jika ada komit yang tidak terpapar di repositori lokal, bagian git pull menciptakan komit gabungan.

Tidak ada yang salah dengan komitmen gabungan, tetapi mereka bisa berbahaya dan harus diperlakukan dengan hormat:

  • Komitmen gabungan pada dasarnya sulit dipelajari. Untuk memahami apa yang dilakukan merger, Anda perlu memahami perbedaan antara semua orang tua. Perbedaan reguler tidak menyampaikan informasi multidimensi ini. Sebaliknya, serangkaian komitmen normal mudah dilihat.
  • Konflik konflik gabungan sulit, dan kesalahan sering kali tidak diperhatikan untuk waktu yang lama karena komitmen gabungan sulit dilihat.
  • Merger dapat dengan mulus menggantikan efek dari komitmen reguler. Kode tidak lagi merupakan jumlah dari komitmen tambahan, yang mengarah pada kesalahpahaman tentang apa yang sebenarnya telah berubah.
  • Komitmen gabungan dapat memecah beberapa skema integrasi berkelanjutan (misalnya, secara otomatis hanya merakit jalur pertama -p berdasarkan perjanjian yang diasumsikan, yang menurutnya orang tua kedua menunjuk untuk bekerja dalam proses yang sedang ber>

Tentu saja, ada waktu dan tempat untuk merger, tetapi pemahaman tentang kapan merger harus dan tidak boleh digunakan dapat meningkatkan kegunaan repositori Anda.

Perhatikan bahwa tujuan dari Git adalah menyederhanakan berbagi dan penggunaan evolusi basis kode, dan tidak untuk secara akurat merekam cerita persis seperti yang digunakan. (Jika Anda tidak setuju, pertimbangkan perintah rebase dan mengapa itu dibuat.) Penggabungan yang dilakukan oleh git pull jangan mentransfer semantik yang bermanfaat ke orang lain - mereka hanya mengatakan bahwa orang lain melakukan transfer ke repositori sebelum Anda melakukan perubahan. Mengapa penggabungan ini dilakukan jika tidak ada artinya bagi orang lain dan bisa berbahaya?

Anda dapat mengonfigurasi git pull untuk pindah alih-alih menggabungkan, tetapi ini juga memiliki masalah (akan dibahas nanti). Sebagai gantinya, git pull hanya dapat dikonfigurasi untuk penggabungan yang dipercepat.

Reintroduksi komite yang dipindahkan

Misalkan seseorang melempar dahan dan mendorongnya dengan paksa. Ini biasanya tidak boleh terjadi, tetapi kadang-kadang diperlukan (misalnya, menghapus file log 50 GB yang tidak sengaja diproses dan dikirim). Penggabungan yang dilakukan oleh git pull akan menggabungkan versi baru dari cabang hulu dengan versi lama yang masih ada di repositori lokal Anda. Jika Anda menekan hasilnya, garpu dan obor akan mulai muncul di jalan Anda.

Beberapa orang mungkin berpendapat bahwa masalah sebenarnya adalah upgrade yang dipaksakan. Ya, biasanya disarankan untuk menghindari dorongan daya jika memungkinkan, tetapi kadang-kadang itu tidak bisa dihindari. Pengembang harus siap menghadapi pembaruan yang dipaksakan, karena terkadang terjadi. Ini berarti Anda tidak dapat secara buta menggabungkan komit lama menggunakan git pull normal.

Perubahan pada Direktori Pekerjaan Kejutan

Tidak ada cara untuk memprediksi seperti apa direktori atau indeks kerja sampai git pull dijalankan. Mungkin ada gabungan konflik yang perlu Anda selesaikan sebelum Anda bisa melakukan apa pun, ini dapat mengakibatkan file log 50 GB muncul di direktori kerja Anda, karena seseorang secara tidak sengaja mengkliknya, itu dapat mengubah nama direktori di mana Anda bekerja, dll.

git remote update -p (atau git fetch --all -p ) memungkinkan Anda untuk melihat komitmen orang lain sebelum Anda memutuskan untuk bergabung atau pindah, yang memungkinkan Anda untuk merumuskan rencana sebelum mengambil tindakan.

Kesulitan dalam memperlakukan orang lain

Misalkan Anda sedang dalam proses membuat beberapa perubahan, dan orang lain ingin Anda melihat beberapa komitmen yang baru saja diklik. Operasi git pull merge (atau rebase) mengubah direktori dan indeks kerja, yang berarti bahwa direktori dan indeks kerja Anda harus bersih.

Anda dapat menggunakan git stash dan kemudian git pull , tetapi apa yang akan Anda lakukan ketika Anda menyelesaikan ulasan? Untuk kembali ke tempat Anda sebelumnya, Anda harus membatalkan penggabungan yang dibuat oleh git pull dan menerapkan cache.

git remote update -p (atau git fetch --all -p ) tidak mengubah direktori atau indeks yang berfungsi, sehingga Anda dapat menjalankannya dengan aman kapan saja, bahkan jika Anda membuat dan / atau tidak membuat perubahan. Anda dapat menjeda apa yang sedang Anda lakukan dan melihat komit orang lain tanpa khawatir tentang menyimpan atau menyelesaikan komit yang sedang Anda kerjakan. git pull tidak memberi Anda fleksibilitas itu.

Pindah ke cabang jarak jauh

Pola penggunaan Git yang biasa adalah membuat git pull untuk membuat perubahan terbaru, diikuti oleh git rebase @{u} untuk mengecualikan komit gabungan yang dimasukkan oleh git pull . Cukup sering Git memiliki beberapa opsi konfigurasi untuk mengurangi dua >git pull untuk pindah alih-alih menggabungkan (lihat branch.<branch>.rebase , branch.autosetuprebase dan pull.rebase ).

Sayangnya, jika Anda memiliki komit gabungan yang tidak dimuat yang ingin Anda simpan (misalnya, komit yang menggabungkan cabang diperluas dari suatu objek menjadi master ), tidak ada relokasi -p ull ( git pull dengan branch.<branch>.rebase disetel ke true ) juga a gabungan ul-p (perilaku default git pull ) diikuti oleh rebase tidak akan bekerja. Ini karena git rebase menghi>--preserve-merges . Operasi zero rebase -p tidak dapat dikonfigurasikan untuk menyimpan penggabungan, dan setelah penggabungan -p diikuti oleh git rebase -p @{u} , merger yang disebabkan oleh gabungan -p tidak akan dihi>Pembaruan: Git v1.8.5 menambahkan git pull --rebase=preserve dan git config pull.rebase preserve . Hal ini menyebabkan git pull melakukan git rebase --preserve-merges setelah mengambil komitmen upstream. (Terima kasih kepada fancaster untuk head-up!)

Menghapus cabang yang dihapus

git pull tidak menghapus cabang pelacakan jarak jauh yang terkait dengan cabang yang dihapus dari repositori jarak jauh. Misalnya, jika seseorang menghapus cabang foo dari repositori jarak jauh, Anda masih akan melihat origin/foo .

Ini mengarah pada fakta bahwa pengguna secara tidak sengaja menghidupkan kembali cabang mati, karena mereka percaya bahwa mereka masih aktif.

Alternatif terbaik: gunakan git up bukan git pull

Alih-alih git pull saya sarankan membuat dan menggunakan alias git up berikut:

 git config --global alias.up '!git remote update -p; git merge --ff-only @{u}' 

Alias ​​ini memuat semua komit terbaru dari semua cabang hulu (pemangkasan cabang mati) dan mencoba untuk memundurkan cabang lokal ke komit terakhir di cabang hulu. Jika komitmen lokal berhasil, tidak ada risiko konflik gabungan. Maju cepat akan gagal jika ada komitmen lokal (tidak didorong), yang akan memberi Anda kesempatan untuk meninjau komitmen hulu sebelum melakukan tindakan.

Itu masih mengubah direktori kerja Anda dengan cara yang tidak terduga, tetapi hanya jika Anda tidak memiliki perubahan lokal. Tidak seperti git pull , git up tidak akan pernah memberi Anda petunjuk mengharapkan Anda untuk memperbaiki konflik gabungan.

Atau: git pull --ff-only --all -p

Berikut ini adalah alias git up alternatif:

 git config --global alias.up 'pull --ff-only --all -p' 

Versi git up memiliki perilaku yang sama dengan alias git up sebelumnya, kecuali untuk:

  • pesan kesalahannya sedikit lebih misterius jika cabang lokal Anda tidak dikonfigurasikan dengan cabang naik
  • itu bergantung pada fitur tidak berdokumen (argumen -p yang diteruskan ke fetch ), yang dapat berubah di versi Git yang akan datang

Jika Anda menggunakan Git 2.0 atau lebih baru

Di Git 2.0 dan yang lebih baru, Anda bisa mengonfigurasi git pull sehingga hanya penggabungan yang dipercepat yang dilakukan secara default:

 git config --global pull.ff only 

Ini mengarah ke git pull bertindak seperti git pull --ff-only , tetapi masih tidak mengekstrak semua commit upstream dan tidak git pull --ff-only old origin/* jadi saya masih lebih suka git up .

535
10 марта '13 в 1:23 2013-03-10 01:23 Jawaban yang diberikan oleh Richard Hansen pada 10 Maret13 di 1:23 2013-03-10 01:23

Jawaban saya, ditarik dari diskusi yang berasal dari HackerNews:

Saya tergoda untuk hanya menjawab pertanyaan dengan menggunakan hukum judul Betteridge: mengapa git pull dianggap berbahaya? Bukan itu.

  • Nonlinier tidak secara internal buruk. Jika mereka mewakili kisah nyata, mereka baik-baik saja.
  • Reintroduksi yang tidak disengaja dari komitmen yang diubah kembali ke hulu adalah hasil dari penulisan u>
  • Mengubah direktori kerja - hasil yang diharapkan; Utilitas yang dapat diperdebatkan, yaitu dalam kondisi perilaku Hg / monoton / Darcs / other_dvcs_predating_git, tetapi sekali lagi, tidak pada dasarnya buruk.
  • Penggabungan membutuhkan penangguhan pertimbangan pekerjaan pengguna lain, serta perilaku yang diharapkan saat melakukan stretching git. Jika Anda tidak ingin bergabung, Anda harus menggunakan git fetch. Sekali lagi, ini adalah keistimewaan git dibandingkan dengan DVD populer sebelumnya, tetapi ini adalah perilaku yang diharapkan, tidak buruk secara internal.
  • Menyulitkan untuk menginstal u>
  • Tidak membersihkan cabang itu bagus. Setiap repo tahu apa yang diinginkannya. git tidak memiliki konsep master-slave.
194
12 марта '14 в 18:15 2014-03-12 18:15 jawabannya diberikan oleh Sérgio Carvalho pada 12 Maret '14 pukul 18:15 2014-03-12 18:15

Ini tidak dianggap berbahaya jika Anda menggunakan Git dengan benar. Saya melihat bagaimana ini berdampak negatif pada use case Anda, tetapi Anda dapat menghindari masalah hanya dengan mengubah keseluruhan cerita.

26
12 марта '14 в 18:43 2014-03-12 18:43 jawabannya diberikan oleh Hunt Burdick pada 12 Maret '14 pukul 18:43 2014-03-12 18:43

Persyaratan Respons yang Diterima

Operasi rebase-pull tidak dapat dikonfigurasikan untuk menyimpan gabungan

tetapi dengan Git 1.8.5 , yang menerbitkan jawaban ini, Anda dapat membuatnya

 git pull --rebase=preserve 

atau

 git config --global pull.rebase preserve 

atau

 git config branch.<name>.rebase preserve 

kata dokumen

Saat preserve, juga meneruskan --preserve-merges ke 'git rebase', sehingga penggabungan yang dilakukan secara lokal tidak akan dihaluskan dengan menjalankan 'git pull'.

Dalam diskusi sebelumnya ini ada informasi dan diagram yang lebih terperinci: Git pull --rebase - preserve-merge . Ini juga menjelaskan mengapa git pull --rebase=preserve tidak cocok dengan git pull --rebase --preserve-merges , yang tidak demikian.

Diskusi sebelumnya yang lain ini menjelaskan apa yang sebenarnya diterapkan oleh opsi penghematan-penggabungan-tabungan, dan betapa lebih sulitnya daripada rebase biasa: Apa yang sebenarnya dilakukan git "penggabung-pelestarian-penggabungan" (dan mengapa?)

17
12 марта '14 в 19:38 2014-03-12 19:38 jawabannya diberikan oleh Marc Liyanage pada 12 Maret '14 pukul 19:38 2014-03-12 19:38

Pertanyaan lain tentang tag atau Ajukan Pertanyaan