Ringkasan
Secara default, git pull
membuat komit gabungan yang menambahkan kebisingan dan kompleksitas ke riwayat kode. Selain itu, pull
membuatnya mudah untuk tidak memikirkan bagaimana perubahan Anda mungkin dipengaruhi oleh perubahan yang masuk.
The git pull
perintah aman asalkan hanya melakukan penggabungan cepat-maju. Jika git pull
dikonfigurasi 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 up
alias seperti ini:
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
dan menggunakan git up
bukan git pull
. Saya lebih suka alias ini daripada git pull --ff-only
karena:
- 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 pull
tidak buruk jika digunakan dengan benar. Beberapa perubahan terbaru pada Git telah membuatnya lebih mudah untuk digunakan git pull
dengan benar, tetapi sayangnya perilaku default dari suatu dataran git pull
memiliki 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 pull
perintah ini setara dengan menjalankan git fetch
diikuti oleh git merge @{u}
. Jika ada komit yang tidak di-cush dalam repositori lokal, bagian gabungan dari git pull
membuat 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 rebase
perintah dan mengapa itu dibuat.) Penggabungan yang dilakukan oleh git pull
tidak 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 pull
rebase alih-alih bergabung, tetapi ini juga memiliki masalah (dibahas nanti). Sebagai gantinya, git pull
harus 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 pull
akan 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 pull
selesai. 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 pull
Operasi gabungan (atau rebase) memodifikasi direktori dan indeks kerja, yang berarti direktori dan indeks kerja Anda harus bersih.
Anda bisa menggunakan git stash
dan 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 pull
dan 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 pull
tidak memberi Anda fleksibilitas itu.
Rebasing ke Cabang Remote
Pola penggunaan Git yang umum adalah melakukan git pull
untuk membawa perubahan terbaru diikuti oleh git rebase @{u}
untuk menghilangkan komit gabungan yang git pull
diperkenalkan. Ini cukup umum bahwa Git memiliki beberapa pilihan konfigurasi untuk mengurangi kedua langkah ini untuk satu langkah dengan mengatakan git pull
untuk melakukan rebase bukannya gabungan (lihat branch.<branch>.rebase
, branch.autosetuprebase
dan pull.rebase
pilihan).
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 pull
dengan branch.<branch>.rebase
set ke true
) maupun tarikan gabungan ( git pull
perilaku default ) diikuti oleh rebase akan bekerja. Ini karena git rebase
menghilangkan gabungan (itu linierkan DAG) tanpa --preserve-merges
opsi. 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=preserve
dan git config pull.rebase preserve
. Penyebab ini git pull
harus dilakukan git rebase --preserve-merges
setelah mengambil komitmen hulu. (Terima kasih kepada funkaster untuk informasi terkini!)
Membersihkan Cabang yang Dihapus
git pull
tidak memangkas cabang pelacakan jarak jauh yang terkait dengan cabang yang dihapus dari repositori jarak jauh. Misalnya, jika seseorang menghapus cabang foo
dari 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 up
sebagai gantigit pull
Alih-alih git pull
, saya sarankan membuat dan menggunakan git up
alias 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 up
tidak 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 up
alias di atas :
git config --global alias.up 'pull --ff-only --all -p'
Versi ini git up
memiliki perilaku yang sama dengan git up
alias sebelumnya , kecuali:
- pesan kesalahannya sedikit lebih samar jika cabang lokal Anda tidak dikonfigurasikan dengan cabang upstream
- itu bergantung pada fitur tidak berdokumen (
-p
argumen, 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 pull
untuk hanya melakukan penggabungan maju-cepat secara default:
git config --global pull.ff only
Ini menyebabkan git pull
untuk 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
.