Ringkasan
Secara default, git pullmembuat komit gabungan yang menambahkan kebisingan dan kompleksitas ke riwayat kode. Selain itu, pullmembuatnya mudah untuk tidak memikirkan bagaimana perubahan Anda mungkin dipengaruhi oleh perubahan yang masuk.
The git pullperintah aman asalkan hanya melakukan penggabungan cepat-maju. Jika git pulldikonfigurasi untuk hanya melakukan penggabungan maju-cepat dan ketika penggabungan maju-cepat tidak memungkinkan, maka Git akan keluar dengan kesalahan. Ini akan memberi Anda kesempatan untuk mempelajari komit yang masuk, berpikir tentang bagaimana mereka dapat mempengaruhi komit lokal Anda, dan memutuskan tindakan terbaik (gabung, rebase, atur ulang, dll.).
Dengan Git 2.0 dan yang lebih baru, Anda dapat menjalankan:
git config --global pull.ff only
untuk mengubah perilaku default menjadi hanya maju cepat. Dengan versi Git antara 1.6.6 dan 1.9.x Anda harus terbiasa mengetik:
git pull --ff-only
Namun, dengan semua versi Git, saya sarankan mengonfigurasi git upalias seperti ini:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
dan menggunakan git upbukan git pull. Saya lebih suka alias ini daripada git pull --ff-onlykarena:
- ini bekerja dengan semua versi Git (non-kuno),
- itu mengambil semua cabang hulu (bukan hanya cabang yang sedang Anda kerjakan), dan
- membersihkan
origin/*cabang - cabang lama yang tidak lagi ada di hulu.
Masalah dengan git pull
git pulltidak buruk jika digunakan dengan benar. Beberapa perubahan terbaru pada Git telah membuatnya lebih mudah untuk digunakan git pulldengan benar, tetapi sayangnya perilaku default dari suatu dataran git pullmemiliki beberapa masalah:
- itu memperkenalkan nonlinier yang tidak perlu dalam sejarah
- itu membuatnya mudah untuk secara tidak sengaja memperkenalkan kembali komitmen yang sengaja diubah kembali ke hulu
- itu mengubah direktori kerja Anda dengan cara yang tidak terduga
- menjeda apa yang Anda lakukan untuk meninjau pekerjaan orang lain itu menyebalkan
git pull
- membuatnya sulit untuk rebase dengan benar ke cabang jarak jauh
- itu tidak membersihkan cabang yang dihapus di repo jarak jauh
Masalah-masalah ini dijelaskan secara lebih rinci di bawah ini.
Sejarah Nonlinier
Secara default, git pullperintah ini setara dengan menjalankan git fetchdiikuti oleh git merge @{u}. Jika ada komit yang tidak di-cush dalam repositori lokal, bagian gabungan dari git pullmembuat komit gabungan.
Tidak ada yang secara inheren buruk tentang gabungan yang dilakukan, tetapi mereka bisa berbahaya dan harus diperlakukan dengan hormat:
- Komitmen gabungan secara inheren sulit untuk diperiksa. Untuk memahami apa yang dilakukan penggabungan, Anda harus memahami perbedaan untuk semua orang tua. Perbedaan konvensional tidak memberikan informasi multi-dimensi ini dengan baik. Sebaliknya, serangkaian komitmen normal mudah ditinjau.
- Menggabungkan resolusi konflik itu rumit, dan kesalahan sering kali tidak terdeteksi untuk waktu yang lama karena menggabungkan komitmen sulit untuk ditinjau.
- Penggabungan dapat secara diam-diam menggantikan efek dari komitmen reguler. Kode tidak lagi merupakan jumlah dari komitmen tambahan, yang mengarah pada kesalahpahaman tentang apa yang sebenarnya berubah.
- Komitmen gabungan dapat mengganggu beberapa skema integrasi berkelanjutan (mis., Buat otomatis hanya jalur orang tua pertama di bawah konvensi yang diasumsikan bahwa orang tua kedua menunjukkan pekerjaan tidak lengkap yang sedang berlangsung).
Tentu saja ada waktu dan tempat untuk penggabungan, tetapi memahami kapan penggabungan harus dan tidak boleh digunakan dapat meningkatkan kegunaan repositori Anda.
Perhatikan bahwa tujuan Git adalah membuatnya mudah untuk berbagi dan mengonsumsi evolusi basis kode, bukan untuk mencatat sejarah dengan tepat seperti saat dibuka. (Jika Anda tidak setuju, pertimbangkan rebaseperintah dan mengapa itu dibuat.) Penggabungan yang dilakukan oleh git pulltidak menyampaikan semantik yang bermanfaat kepada orang lain — mereka hanya mengatakan bahwa ada orang lain yang mendorong ke repositori sebelum Anda selesai dengan perubahan Anda. Mengapa penggabungan tersebut dilakukan jika tidak berarti bagi orang lain dan bisa berbahaya?
Dimungkinkan untuk mengonfigurasi git pullrebase alih-alih bergabung, tetapi ini juga memiliki masalah (dibahas nanti). Sebagai gantinya, git pullharus dikonfigurasi untuk hanya melakukan penggabungan maju-cepat.
Reintroduksi Komitmen Rebased-out
Misalkan seseorang me-rebet cabang dan memaksa mendorongnya. Ini umumnya tidak boleh terjadi, tetapi kadang-kadang diperlukan (misalnya, untuk menghapus file log 50GiB yang sengaja dikomit dan didorong). Penggabungan yang dilakukan oleh git pullakan menggabungkan versi baru dari cabang hulu ke versi lama yang masih ada di repositori lokal Anda. Jika Anda mendorong hasilnya, garpu dan garpu nada akan mulai menghampiri Anda.
Beberapa mungkin berpendapat bahwa masalah sebenarnya adalah pembaruan paksa. Ya, pada umumnya disarankan untuk menghindari dorongan kekuatan kapan pun memungkinkan, tetapi kadang-kadang tidak dapat dihindari. Pengembang harus siap menghadapi pembaruan kekuatan, karena hal itu kadang-kadang terjadi. Ini berarti tidak secara membuta menggabungkan komitmen lama dengan yang biasa git pull.
Modifikasi Direktori Kerja Kejutan
Tidak ada cara untuk memprediksi seperti apa direktori atau indeks kerja sampai git pullselesai. Mungkin ada gabungan konflik yang harus Anda selesaikan sebelum Anda bisa melakukan hal lain, itu mungkin memperkenalkan file log 50GiB di direktori kerja Anda karena seseorang secara tidak sengaja mendorongnya, itu mungkin mengubah nama direktori yang sedang Anda kerjakan, dll.
git remote update -p(atau git fetch --all -p) memungkinkan Anda untuk melihat komitmen orang lain sebelum Anda memutuskan untuk bergabung atau rebase, memungkinkan Anda untuk membuat rencana sebelum mengambil tindakan.
Kesulitan Meninjau Komitmen Orang Lain
Misalkan Anda berada di tengah-tengah membuat beberapa perubahan dan orang lain ingin Anda meninjau beberapa komitmen yang baru saja mereka dorong. git pullOperasi gabungan (atau rebase) memodifikasi direktori dan indeks kerja, yang berarti direktori dan indeks kerja Anda harus bersih.
Anda bisa menggunakan git stashdan kemudian git pull, tetapi apa yang Anda lakukan ketika Anda selesai meninjau? Untuk kembali ke tempat Anda sebelumnya, Anda harus membatalkan gabungan yang dibuat oleh git pulldan menerapkan simpanan.
git remote update -p(atau git fetch --all -p) tidak mengubah direktori atau indeks kerja, jadi aman untuk dijalankan kapan saja — bahkan jika Anda telah melakukan dan / atau mengubah unstaged. Anda dapat menjeda apa yang Anda lakukan dan meninjau komit orang lain tanpa khawatir tentang menyembunyikan atau menyelesaikan komit yang sedang Anda kerjakan. git pulltidak memberi Anda fleksibilitas itu.
Rebasing ke Cabang Remote
Pola penggunaan Git yang umum adalah melakukan git pulluntuk membawa perubahan terbaru diikuti oleh git rebase @{u}untuk menghilangkan komit gabungan yang git pulldiperkenalkan. Ini cukup umum bahwa Git memiliki beberapa pilihan konfigurasi untuk mengurangi kedua langkah ini untuk satu langkah dengan mengatakan git pulluntuk melakukan rebase bukannya gabungan (lihat branch.<branch>.rebase, branch.autosetuprebasedan pull.rebasepilihan).
Sayangnya, jika Anda memiliki komit gabungan yang tidak dicuri yang ingin Anda pertahankan (mis., Komit yang menggabungkan cabang fitur yang didorong ke dalamnya master), baik tarikan rebase ( git pulldengan branch.<branch>.rebaseset ke true) maupun tarikan gabungan ( git pullperilaku default ) diikuti oleh rebase akan bekerja. Ini karena git rebasemenghilangkan gabungan (itu linierkan DAG) tanpa --preserve-mergesopsi. Operasi rebase-pull tidak dapat dikonfigurasikan untuk mempertahankan penggabungan, dan tarikan gabungan diikuti oleh git rebase -p @{u}tidak akan menghilangkan gabungan yang disebabkan oleh tarikan gabungan. Pembaruan: Git v1.8.5 ditambahkan git pull --rebase=preservedan git config pull.rebase preserve. Penyebab ini git pullharus dilakukan git rebase --preserve-mergessetelah mengambil komitmen hulu. (Terima kasih kepada funkaster untuk informasi terkini!)
Membersihkan Cabang yang Dihapus
git pulltidak memangkas cabang pelacakan jarak jauh yang terkait dengan cabang yang dihapus dari repositori jarak jauh. Misalnya, jika seseorang menghapus cabang foodari repo jarak jauh, Anda masih akan melihat origin/foo.
Hal ini menyebabkan pengguna secara tidak sengaja menghidupkan kembali cabang yang mati karena mereka pikir mereka masih aktif.
Alternatif yang Lebih Baik: Gunakan git upsebagai gantigit pull
Alih-alih git pull, saya sarankan membuat dan menggunakan git upalias berikut :
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
Alias ini mengunduh semua komit terbaru dari semua cabang hulu (memangkas cabang yang mati) dan mencoba memajukan cepat cabang lokal ke komit terbaru di cabang hulu. Jika berhasil, maka tidak ada komitmen lokal, sehingga tidak ada risiko menggabungkan konflik. Percepat-maju akan gagal jika ada komitmen lokal (tidak dicuci), memberi Anda kesempatan untuk meninjau komitmen hulu sebelum mengambil tindakan.
Ini masih memodifikasi direktori kerja Anda dengan cara yang tidak dapat diprediksi, tetapi hanya jika Anda tidak memiliki perubahan lokal. Tidak seperti itu git pull, git uptidak akan pernah menjatuhkan Anda ke prompt yang mengharapkan Anda untuk memperbaiki konflik gabungan.
Pilihan lain: git pull --ff-only --all -p
Berikut ini adalah alternatif dari git upalias di atas :
git config --global alias.up 'pull --ff-only --all -p'
Versi ini git upmemiliki perilaku yang sama dengan git upalias sebelumnya , kecuali:
- pesan kesalahannya sedikit lebih samar jika cabang lokal Anda tidak dikonfigurasikan dengan cabang upstream
- itu bergantung pada fitur tidak berdokumen (
-pargumen, yang diteruskan ke fetch) yang dapat berubah di versi Git yang akan datang
Jika Anda menjalankan Git 2.0 atau lebih baru
Dengan Git 2.0 dan yang lebih baru, Anda dapat mengonfigurasi git pulluntuk hanya melakukan penggabungan maju-cepat secara default:
git config --global pull.ff only
Ini menyebabkan git pulluntuk bertindak seperti git pull --ff-only, tetapi masih tidak mengambil semua komitmen upstream atau membersihkan origin/*cabang lama jadi saya masih lebih suka git up.