Bisakah "git pull" secara otomatis menyimpan dan memunculkan perubahan yang tertunda?

122

Saya tahu bagaimana menyelesaikan ini:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
    foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

Tetapi tidak ada cara untuk membiarkan git pullmelakukan stashdan poptari bagi saya?

Jika perintah ini memiliki nama yang berbeda, tidak apa-apa.

Membuat alias shell untuk git stash; git pull; git stash popadalah solusi, tetapi saya mencari solusi yang lebih baik.

guettli
sumber
bagaimana dengan alias git ?
Яois
20
Menjalankan secara git stash; git pull; git stash popterprogram berbahaya, karena jika tidak ada yang git stashdisimpan , akan menjadi no-op, tetapi git stash popakan memunculkan simpanan terakhir (jika ada), yang hampir pasti bukan yang Anda inginkan. Pengguna torek memiliki posting yang bagus tentang ini di Stack Overflow, tetapi saya tidak dapat menemukannya ...
jub0bs
2
@Jubobs yang satu ini? stackoverflow.com/a/20412685/6309 Atau yang ini? stackoverflow.com/a/20480591/6309
VonC
1
@guettli Saya tidak menyiratkan bahwa pertanyaan Anda adalah duplikat, saya hanya menjawab komentar Jubobs.
VonC
2
Sebagai selangkah lebih maju, operasi akan berhasil hanya jika simpanan dapat diterapkan dengan rapi setelah ditarik. Jika ada konflik, maka seluruh operasi gagal secara atomik sehingga struktur pohon tidak berubah. Inilah yang ingin saya lakukan: menarik perubahan dengan perubahan lokal saya digabungkan, atau gagal karena kesalahan dan biarkan saya memutuskan secara manual apa yang harus dilakukan selanjutnya. Apakah 'transaksi' git semacam ini mungkin?
Ed Avis

Jawaban:

185

Untuk Git 2.6+ (dirilis 28 Sept 2015)

Itu hanya git config pengaturan yang menarik adalah:

rebase.autoStash

(dengan Git 2.27, Q2 2020, Anda sekarang juga punya merge.autostash, lihat di bawah)

Jika disetel ke true, secara otomatis membuat simpanan sementara sebelum operasi dimulai, dan menerapkannya setelah operasi berakhir.
Ini berarti Anda dapat menjalankan rebase pada pohon kerja yang kotor.

Namun, gunakan dengan hati-hati: aplikasi simpanan terakhir setelah rebase berhasil dapat mengakibatkan konflik non-sepele. Default-nya adalah false.

gabungkan dengan:

pull.rebase

Jika true, rebase cabang di atas cabang yang diambil, alih-alih menggabungkan cabang default dari remote default saat "git pull" dijalankan.

git config pull.rebase true
git config rebase.autoStash true

Itu akan cukup bagi orang sederhana git pulluntuk bekerja bahkan di pohon yang kotor.
Tidak ada alias diperlukan dalam kasus itu.


Lihat commit 53c76dc (04 Jul 2015) oleh Kevin Daudt ( Ikke) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit e69b408 , 17 Agustus 2015)

pull: biarkan pohon kotor saat rebase.autostashdiaktifkan

rebase belajar untuk menyimpan perubahan ketika menemukan pohon kerja kotor, tetapi git pull --rebasetidak.

Hanya verifikasi jika pohon kerja kotor saat rebase.autostashtidak diaktifkan.


Catatan: jika Anda ingin menarik tanpa autostash (meskipun rebase.autoStash truetelah disetel), Anda memiliki sejak git 2.9 (Juni 2016):

 pull --rebase --no-autostash

Lihat commit 450dd1d , commit 1662297 , commit 44a59ff , commit 5c82bcd , commit 6ddc97c , commit eff960b , commit efa195d (02 Apr 2016), dan commit f66398e , commit c48d73b (21 Mar 2016) oleh Mehul Jain ( mehul2029) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit 7c137bb , 13 Apr 2016)

Commit f66398e khususnya mencakup:

pull --rebase: tambahkan --[no-]autostashbendera

Jika rebase.autoStashvariabel konfigurasi disetel, tidak ada cara untuk menimpanya untuk " git pull --rebase" dari baris perintah.

Ajarkan " git pull --rebase" tanda --[no-]autostashbaris perintah yang menggantikan nilai saat ini rebase.autoStash, jika disetel. Saat " git rebase" memahami --[no-]autostashopsi, ini hanya masalah meneruskan opsi ke " git rebase" saat " " yang mendasari git pull --rebasedipanggil.


Peringatan: sebelum Git 2.14 (Q3 2017), " git pull --rebase --autostash" tidak disimpan otomatis saat riwayat lokal maju cepat ke upstream.

Lihat commit f15e7cf (01 Jun 2017) oleh Tyler Brazier ( tylerbrazier) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit 35898ea , 05 Jun 2017)

pull: ff --rebase --autostashbekerja di repo kotor

Ketika git pull --rebase --autostashdalam repositori kotor menghasilkan percepatan-maju, tidak ada yang di-autostash dan penarikan gagal.
Ini karena pintasan untuk menghindari menjalankan rebase ketika kita dapat mempercepat maju, tetapi autostash diabaikan pada jalur kode itu.


Pembaruan: Mariusz Pawelski bertanya di komentar sebuah pertanyaan menarik:

Jadi semua orang menulis tentang autostashkapan Anda melakukan rebase (atau pull --rebase).

Tetapi tidak ada yang mengambil tentang autostashing ketika Anda melakukan penarikan normal dengan penggabungan .
Jadi tidak ada saklar otomatis untuk itu? Atau saya melewatkan sesuatu? Saya lebih suka melakukan git pull --rebasetetapi OP bertanya tentang " standar " git pull

Menjawab:

The thread asli membahas fitur autostash ini, dilaksanakan awalnya baik untuk git pull(penggabungan) dan git pull --rebase.

Tapi ... Junio ​​C Hamano (pengelola Git) mencatat bahwa:

Jika pull-mergeada sesuatu yang akan menyebabkan "gangguan" yang memicu topik ini, menurut definisi, perubahan lokal tumpang tindih dengan penggabungan, dan "sembulan simpanan" internal ini akan menyentuh jalur yang disentuh penggabungan dan kemungkinan tidak akan menghasilkan "Dihapus "tetapi biarkan konflik lebih lanjut diselesaikan.

Saya menduga pull.autostashkonfigurasi itu bukan tambahan yang baik karena mendorong alur kerja yang buruk dan menimbulkan rasa sakit.
Dalam kasus sederhana ini mungkin tidak merugikan, tetapi ketika perubahan lokal kompleks, itu akan sangat merugikan daripada tidak memilikinya, dan konfigurasi merampas insentif untuk memilih.

Persamaannya agak berbeda untuk "pull-rebase", karena "rebase" memaksa Anda untuk memulai dari pohon kerja yang bersih, jadi gangguan "download dan kemudian hentikan" terasa lebih besar. Saya memiliki kecurigaan bahwa pelonggaran itu mungkin perbaikan yang lebih produktif untuk masalah yang sebenarnya.

Jadi, berkenaan dengan pull-merge klasik, lebih baik untuk:

dorong pengguna untuk memikirkan tentang sifat WIP yang dia miliki di pohon kerja sebelum menjalankan " git pull" .
Apakah itu binatang yang terlalu kompleks yang dapat mengganggu apa yang orang lain lakukan, atau apakah itu perubahan sepele yang dapat dia sembunyikan dan keluarkan kembali?

Jika yang pertama, dia akan jauh lebih baik melakukan " checkout -b", terus bekerja sampai perubahan lokal menjadi lebih baik dan "berkomitmen", sebelum menarik ke cabang asli.

Jika yang terakhir, dia lebih baik melakukan:

  • " git pull",
  • setelah menemukan konflik, lari
    • git stash,
    • git merge FETCH_HEAD dan
    • git stash pop

Yang sedang berkata, dengan Git 2.27 (Kuartal 2 2020), " git pull" belajar memperingatkan ketika tidak pull.rebaseada konfigurasi, dan juga --[no-]rebasetidak --ff-onlydiberikan (yang akan menghasilkan penggabungan).

Lihat commit d18c950 (10 Mar 2020) oleh Alex Henrie ( alexhenrie) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit 1c56d6f , 27 Mar 2020)

pull: memperingatkan jika pengguna tidak mengatakan apakah akan melakukan rebase atau menggabungkan

Ditandatangani oleh: Alex Henrie

Seringkali pengguna pemula Git lupa mengatakan " pull --rebase" dan berakhir dengan penggabungan yang tidak perlu dari upstream.

Apa yang biasanya mereka inginkan adalah " pull --rebase" dalam kasus yang lebih sederhana, atau " pull --ff-only" memperbarui salinan cabang integrasi utama, dan menyusun ulang pekerjaan mereka secara terpisah.
The pull.rebasevariabel konfigurasi ada untuk membantu mereka dalam kasus sederhana, tetapi tidak ada mekanisme untuk membuat para pengguna menyadari hal itu.

Keluarkan pesan peringatan jika tidak ada --[no-]rebaseopsi dari baris perintah dan tidak ada pull.rebasevariabel konfigurasi yang diberikan.
Ini akan merepotkan mereka yang tidak pernah ingin " pull --rebase", yang tidak pernah melakukan sesuatu yang istimewa, tetapi biaya ketidaknyamanan hanya dibayarkan sekali per pengguna, yang seharusnya merupakan biaya yang wajar untuk membantu sejumlah pengguna baru.


Dengan Git 2.27 (Kuartal 2 2020), " git merge" mempelajari opsi " --autostash", dan merge.autostashsetelan baru .

Lihat komit d9f15d3 , komit f8a1785 , komit a03b555 , komit 804fe31 , komit 12b6e13 , komit 0dd562e , komit 0816f1d , komit 9bb3dea , komit 4d4bc15 , komit b309a97 , komit f213f06 , komit 86ed00a , komit facca7f , komit be1bb60 , komit efcf6cf , komit c20de8b , komit bfa50c2 , commit 3442c3d , commit 5b2f6d9 (07 Apr 2020), commit 65c425a(04 Apr 2020), dan commit fd6852c , commit 805d9ea (21 Mar 2020) oleh Denton Liu ( Denton-L) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit bf10200 , 29 Apr 2020)

pull: lulus --autostash untuk bergabung

Ditandatangani oleh: Denton Liu

Sebelumnya, --autostashhanya bekerja dengan git pull --rebase.

Namun, di patch terakhir, gabungkan juga dipelajari --autostashsehingga tidak ada alasan mengapa kita harus memiliki batasan ini lagi.
Ajarkan tarik untuk lulus --autostashuntuk bergabung, seperti yang terjadi untuk rebase.

Dan:

rebase: gunakan apply_autostash()dari sequencer.c

Ditandatangani oleh: Denton Liu

The apply_autostash()fungsi dalam builtin/rebase.ccukup mirip dengan apply_autostash()fungsi dalam sequencer.cbahwa mereka hampir dipertukarkan, kecuali untuk jenis arg mereka menerima. Buat sequencer.cversi eksternal dan gunakan dalam rebase.

Versi rebase diperkenalkan di 6defce2b02 ("builtin rebase: support --autostashoption", 04-09-2018, Git v2.20.0-rc0 - merge terdaftar di batch # 8 ) sebagai bagian dari konversi shell ke C.
Itu memilih untuk menduplikasi fungsi karena, pada saat itu, ada proyek lain yang sedang berjalan yang mengubah rebase interaktif dari shell ke C juga dan mereka tidak ingin berbenturan dengan mereka dengan sequencer.cversi refactoring apply_autostash().
Karena kedua upaya ini sudah lama dilakukan, sekarang kita bisa dengan bebas menggabungkan keduanya.

VonC
sumber
Mulai 2.4.2, ini belum diterapkan. Mungkin suatu hari nanti. rebase.autoStashberlaku hanya saat menggunakan rebase. pull.rebaseberlaku hanya saat menggunakan tarikan.
Randal Schwartz
"Itu akan cukup untuk sebuah tarikan sederhana untuk bekerja bahkan di pohon yang kotor." Seperti yang dikatakan Randal, ini belum benar. Tarikan master saat ini masih memilih die_on_unclean_work_tree.
Pradhan
1
@Pradhan Saya setuju. Implementasinya baru saja masuk master pagi ini dan harus siap untuk git 2.6. Saya telah mengedit jawabannya untuk memperjelasnya.
VonC
Saya telah mengonfirmasi bahwa autostash berfungsi dengan git 2.5.5.
Joshua Hoblitt
1
Jadi semua orang menulis tentang autostash saat Anda melakukannya rebase(atau pull --rebase). Tetapi tidak ada yang mengambil tentang autostashing ketika Anda melakukan normal pulldengan penggabungan. Jadi tidak ada saklar otomatis untuk itu? Atau saya melewatkan sesuatu? Saya lebih suka melakukan git pull --rebasetetapi OP bertanya tentang "standar"git pull
Mariusz Pawelski
41

Untuk menghemat beberapa detik bagi penjelajah yang akan datang, berikut ringkasannya (terima kasih kepada @VonC):

git pull --rebase --autostash
Vitaliy Ulantikov
sumber
6
Intinya adalah: setelah git config pull.rebase truedan git config rebase.autoStash true, yang Anda butuhkan hanyalah git pull. Cuma git pull. Tidak ada pilihan lain yang dibutuhkan.
VonC
3
Tampaknya Anda membutuhkan setidaknya Git 2.9 untuk --autostashopsi tersebut. The -c rebase.autoStash=truebekerja di Git 2,6 seterusnya.
ntc2
15

Seperti yang dinyatakan oleh komentar di atas, menyetel dua nilai konfigurasi saat ini tidak berfungsi git pull, karena konfigurasi autostash hanya berlaku untuk rebases sebenarnya. Perintah git ini melakukan apa yang Anda inginkan:

git fetch
git rebase --autostash FETCH_HEAD

Atau atur sebagai alias:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

Kemudian lakukan:

git pullr

Tentu saja alias ini bisa diganti namanya sesuai keinginan.

pengguna397114
sumber
7

Dengan Git 2.6+ Anda dapat menggunakan berikut ini:

alias gup='git -c rebase.autoStash=true pull --rebase'

Ini --rebasemembuat penggunaan git-pull rebasealih-alih merge, jadi pengaturan / opsi seperti--ff-only tidak akan berlaku.

Saya menggunakan alias untuk menarik --ff-onlysecara default ( git pull --ff-only), dan kemudian dapat menggunakan gup(dari atas) jika penggabungan maju cepat tidak memungkinkan atau ada perubahan yang disimpan.

kebiruan
sumber
Apa perbedaan utama antara git pull --ff-onlydangit pull pull --rebase --autostash
alper
0

Seperti yang telah Anda sebutkan, inilah cara melakukannya. Anda dapat menggunakannya dalam alias untuk menghemat pengetikan dan untuk menggunakan pintasan atau Anda dapat menggunakannya dalam satu baris (bisa juga alias)

git stash && git pull --rebase && git stash pop

Ini akan melakukan hal yang sama seperti yang Anda lakukan tetapi dalam satu baris (&&) dan Anda menetapkan sebagai alias bahkan akan lebih pendek.

Baris berikut akan menampilkan perubahan masuk / keluar sebelum Anda menarik / mendorong

git log ^master origin/master
git log master ^origin/master
CodeWizard
sumber
8
Pendekatan ini tidak aman: jika tidak ada yang perlu disimpan, perintah pertama tidak akan melakukan apa-apa, lalu stash popakan melepaskan beberapa item acak dari sebelumnya.
John Zwinck
Hanya untuk menjadi ekstra jelas: bahkan jika git stashtidak apa-apa simpanan masih "kembali" tidak ada errorcode sehingga && masih akan melanjutkan git pulldan git stash popdan pop setumpuk sebelumnya. Jadi lebih baik tidak menggunakan ini kecuali Anda sangat yakin itu akan menyimpan sesuatu!
MoonLite