Git bergabung dengan force overwrite

101

Saya memiliki cabang yang disebut demoyang perlu saya gabungkan dengan mastercabang. Saya bisa mendapatkan hasil yang diinginkan dengan perintah berikut:

git pull origin demo
git checkout master
git pull origin master
git merge demo
git push origin master

Satu-satunya kekhawatiran saya adalah, jika ada masalah penggabungan , saya ingin memberi tahu gituntuk menimpa perubahan di mastercabang tanpa memberi saya perintah penggabungan. Jadi pada dasarnya perubahan di democabang harus secara otomatis menimpa perubahan di mastercabang.

Saya melihat sekeliling ada beberapa opsi tetapi saya tidak ingin mengambil risiko dengan penggabungan.

OpenStack
sumber
git push -f origin master
MD XF
4
@MDXF: Mungkin saya salah tetapi bukankah seharusnya saya menggunakan -fopsi dengan mergeperintah dan bukan dengan pushperintah
OpenStack
Anda dapat mencoba keduanya dan melihat mana yang berhasil untuk Anda
MD XF
Lihat tautan di bawah ini untuk solusi penimpaan paksa: stackoverflow.com/a/42454737/984471
Manohar Reddy Poreddy

Jawaban:

102

Tidak terlalu terkait dengan jawaban ini, tetapi saya akan membuang git pull, yang hanya git fetchdiikuti oleh git merge. Anda melakukan tiga penggabungan, yang akan membuat Git Anda menjalankan tiga operasi pengambilan, dan Anda hanya memerlukan satu pengambilan. Karenanya:

git fetch origin   # update all our origin/* remote-tracking branches

git checkout demo         # if needed -- your example assumes you're on it
git merge origin/demo     # if needed -- see below

git checkout master
git merge origin/master

git merge -X theirs demo   # but see below

git push origin master     # again, see below

Mengontrol penggabungan tersulit

Bagian yang paling menarik di sini adalah git merge -X theirs. Seperti yang dicatat root545 , -Xopsi diteruskan ke strategi penggabungan, dan baik recursivestrategi default maupun resolvestrategi alternatif mengambil -X oursatau -X theirs(satu atau yang lain, tetapi tidak keduanya). Namun, untuk memahami apa yang mereka lakukan, Anda perlu tahu bagaimana Git menemukan, dan memperlakukan, menggabungkan konflik .

Konflik penggabungan dapat terjadi dalam beberapa file 1 ketika versi dasar berbeda dari versi saat ini (juga disebut lokal, HEAD, atau --ours) dan versi lain (juga disebut jarak jauh atau --theirs) dari file yang sama. Artinya, penggabungan telah mengidentifikasi tiga revisi (tiga komit): basis, milik kita, dan milik mereka. Versi "base" adalah dari gabungan dasar antara komit kita dan komit mereka, seperti yang ditemukan di grafik komit (untuk lebih banyak lagi tentang ini, lihat posting StackOverflow lainnya). Git kemudian menemukan dua rangkaian perubahan: "apa yang kami lakukan" dan "apa yang mereka lakukan". Perubahan ini (secara umum) ditemukan baris demi baris, murni tekstualdasar. Git tidak benar-benar memahami isi file; itu hanya membandingkan setiap baris teks.

Perubahan ini adalah apa yang Anda lihat dalam git diffkeluaran, dan seperti biasa, mereka juga memiliki konteks . Mungkin saja hal-hal yang kita ubah berada pada baris yang berbeda dari hal-hal yang diubah, sehingga perubahan tersebut tampak seperti tidak akan bertabrakan, tetapi konteksnya juga telah berubah (misalnya, karena perubahan kita dekat dengan bagian atas atau bawah file, sehingga file tersebut habis dalam versi kami, tetapi dalam versi mereka, mereka juga menambahkan lebih banyak teks di bagian atas atau bawah).

Jika perubahan terjadi di baris yang berbeda — misalnya, kami mengubah colorke colourbaris 17 dan berubah fredke barneybaris 71 - maka tidak ada konflik: Git hanya mengambil kedua perubahan tersebut. Jika perubahan terjadi pada baris yang sama, tetapi merupakan perubahan yang identik , Git akan mengambil satu salinan dari perubahan tersebut. Hanya jika perubahan berada pada baris yang sama, tetapi merupakan perubahan yang berbeda, atau kasus khusus dari konteks yang mengganggu, Anda mendapatkan konflik modifikasi / modifikasi.

The -X oursdan -X theirspilihan memberitahu Git bagaimana menyelesaikan konflik ini, dengan memilih hanya salah satu dari dua perubahan: kita, atau mereka. Karena Anda mengatakan Anda menggabungkan demo(milik mereka) ke master(milik kami) dan menginginkan perubahan dari demo, Anda pasti menginginkannya -X theirs.

-XNamun, penerapan secara membabi buta berbahaya. Hanya karena perubahan kami tidak bertentangan baris demi baris tidak berarti perubahan kami tidak benar-benar bertentangan! Satu contoh klasik terjadi dalam bahasa dengan deklarasi variabel. Versi dasar mungkin mendeklarasikan variabel yang tidak digunakan:

int i;

Dalam versi kami, kami menghapus variabel yang tidak terpakai untuk membuat peringatan compiler pergi-dan mereka versi, mereka menambahkan satu lingkaran beberapa baris kemudian, menggunakan isebagai loop counter. Jika kita menggabungkan dua perubahan tersebut, kode yang dihasilkan tidak lagi dapat dikompilasi. The -Xpilihan adalah tidak membantu di sini karena perubahan berada pada baris yang berbeda .

Jika Anda memiliki rangkaian pengujian otomatis, hal terpenting yang harus dilakukan adalah menjalankan pengujian setelah penggabungan. Anda dapat melakukan ini setelah melakukan, dan memperbaikinya nanti jika diperlukan; atau Anda dapat melakukannya sebelum melakukan, dengan menambahkan --no-commitke git mergeperintah. Kami akan menyerahkan detail untuk semua ini ke postingan lainnya.


1 Anda juga bisa mendapatkan konflik sehubungan dengan operasi "file-wide", misalnya, mungkin kita memperbaiki ejaan kata dalam sebuah file (sehingga kita memiliki perubahan), dan mereka menghapus seluruh file (sehingga mereka memiliki menghapus). Git tidak akan menyelesaikan konflik ini dengan sendirinya, apa pun -Xargumennya.


Melakukan lebih sedikit penggabungan dan / atau penggabungan yang lebih cerdas dan / atau menggunakan rebase

Ada tiga penggabungan di kedua urutan perintah kami. Yang pertama adalah membawa origin/demoke lokal demo(penggunaan Anda git pullyang, jika Git Anda sangat tua, akan gagal diperbarui origin/demotetapi akan menghasilkan hasil akhir yang sama). Yang kedua adalah origin/mastermemasukkan master.

Tidak jelas bagi saya siapa yang memperbarui demodan / atau master. Jika Anda menulis kode Anda sendiri di democabang Anda sendiri , dan orang lain menulis kode dan mendorongnya ke democabang origin, maka penggabungan langkah pertama ini dapat menimbulkan konflik, atau menghasilkan penggabungan yang nyata. Lebih sering daripada tidak, lebih baik menggunakan rebase, daripada menggabungkan, untuk menggabungkan pekerjaan (memang, ini masalah selera dan pendapat). Jika demikian, Anda mungkin ingin menggunakannya git rebase. Di sisi lain, jika Anda tidak pernah melakukan komit Anda sendiri pada demo, Anda bahkan tidak perlu sebuah democabang. Atau, jika Anda ingin mengotomatiskan banyak hal ini, tetapi dapat memeriksa dengan cermat ketika ada commit yang dibuat oleh Anda dan orang lain, Anda mungkin ingin menggunakannya.git merge --ff-only origin/demo: ini akan mempercepat Anda demountuk mencocokkan yang diperbarui origin/demojika memungkinkan, dan langsung gagal jika tidak (pada titik mana Anda dapat memeriksa dua set perubahan, dan memilih penggabungan nyata atau rebase yang sesuai).

Logika yang sama berlaku untuk master, meskipun Anda melakukan merge pada master , sehingga Anda pasti membutuhkan master. Namun, lebih mungkin Anda ingin penggabungan gagal jika tidak dapat dilakukan sebagai fast-forward non-merge, jadi ini mungkin juga harus dilakukan git merge --ff-only origin/master.

Katakanlah Anda tidak pernah melakukan komitmen Anda sendiri demo. Dalam hal ini kita dapat membuang nama demoseluruhnya:

git fetch origin   # update origin/*

git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"

git merge -X theirs origin/demo || die "complex merge conflict"

git push origin master

Jika Anda sedang melakukan sendiri demokomit cabang, ini tidak membantu; Anda mungkin juga mempertahankan penggabungan yang ada (tetapi mungkin menambahkan --ff-onlytergantung pada perilaku apa yang Anda inginkan), atau beralih ke melakukan rebase. Perhatikan bahwa ketiga metode mungkin gagal: penggabungan mungkin gagal dengan konflik, penggabungan dengan --ff-onlymungkin tidak dapat maju cepat, dan rebase mungkin gagal dengan konflik (rebase bekerja dengan, pada dasarnya, melakukan pengambilan ceri , yang menggunakan penggabungan mesin dan karenanya bisa mendapatkan konflik gabungan).

torek
sumber
21

Saya mengalami masalah serupa, di mana saya perlu mengganti file apa pun yang mengalami perubahan / konflik dengan cabang yang berbeda secara efektif.

Solusi yang saya temukan adalah menggunakan git merge -s ours branch.

Perhatikan bahwa opsi ini -sdan tidak -X. -smenunjukkan penggunaan ourssebagai strategi penggabungan tingkat atas, -Xakan menerapkan oursopsi ke recursivestrategi penggabungan, yang bukan yang saya (atau kami) inginkan dalam kasus ini.

Langkah, di mana oldbranchcabang yang ingin Anda timpa newbranch.

  • git checkout newbranch periksa cabang yang ingin Anda pertahankan
  • git merge -s ours oldbranch bergabung di cabang lama, tetapi menyimpan semua file kami.
  • git checkout oldbranch memeriksa cabang yang ingin Anda timpa
  • get merge newbranch bergabung di cabang baru, menimpa cabang lama
Niall Mccormack
sumber
Catatan: tidak ada solusi lain di sini yang berhasil untuk saya, oleh karena itu saya memposting jawaban saya.
Niall Mccormack
1
Itu tidak berhasil untuk saya. Ini menyelesaikan konflik (memecahkan file yang konflik) tetapi file tersebut tidak digabungkan. Dan tidak bisa menggabungkan keduanya.
c-an
Jika ada yang terjebak di mana Anda diminta untuk "Silakan masukkan pesan komit untuk menjelaskan mengapa penggabungan ini diperlukan": Masukkan pesan Anda, lalu tekan tombol ESC pada keyboard Anda, ketik: wq dan tekan ENTER untuk keluar dari prompt.
topherPedersen
19

Pendekatan penggabungan ini akan menambahkan satu komit di atasnya masteryang menempel di apa pun yang ada di dalamnya feature, tanpa mengeluh tentang konflik atau omong kosong lainnya.

masukkan deskripsi gambar di sini

Sebelum Anda menyentuh apapun

git stash
git status # if anything shows up here, move it to your desktop

Sekarang persiapkan tuan

git checkout master
git pull # if there is a problem in this step, it is outside the scope of this answer

Dapatkan featuresemua berpakaian

git checkout feature
git merge --strategy=ours master

Pergi untuk membunuh

git checkout master
git merge --no-ff feature
William Entriken
sumber
1
git push to finish
Kochchy
git-scm.com/docs/git-merge#Documentation/git-merge.txt-ours. Ini berfungsi ketika komit tidak digabungkan dengan rapi. Tetapi pendekatan ini tidak akan selalu berhasil, mengutip sumbernya Changes from the other tree that do not conflict with our side are reflected in the merge result. Itu tidak berhasil untuk saya, karena saya telah menggabungkan komit dengan rapi di cabang saya yang sedang ditimpa. Apakah ada cara lain?
NiharGht
11

Anda dapat mencoba opsi "milik kami" di git merge,

git merge branch -X milik kita

Opsi ini memaksa kumpulan yang berkonflik untuk diselesaikan secara otomatis dengan menggunakan versi kami. Perubahan dari pohon lain yang tidak bertentangan dengan pihak kita tercermin pada hasil penggabungan. Untuk file biner, seluruh konten diambil dari pihak kami.

akar
sumber
3
Ini akan menjadi mundur, karena OP mengatakan dia ingin demoversinya lebih disukai meskipun dia bergabung master. Ada -X theirsjuga, tetapi tidak jelas apakah ini yang sebenarnya diinginkan OP.
Torek
Anda belum membaca seluruhnya. Catatan Anda menjelaskan apa yang oursdilakukan saat menggunakan di backend dengan -sopsi. Saat menggunakan oursdengan -X: Ini membuang semua yang pohon lain lakukan, menyatakan sejarah kita berisi semua yang terjadi di dalamnya. sumber
jimasun
2

Ketika saya mencoba menggunakan -X theirsdan sakelar perintah terkait lainnya, saya terus mendapatkan komit gabungan. Saya mungkin tidak memahaminya dengan benar. Salah satu alternatif yang mudah dipahami adalah menghapus cabang tersebut lalu melacaknya lagi.

git branch -D <branch-name>
git branch --track <branch-name> origin/<branch-name>

Ini sebenarnya bukan "penggabungan", tetapi inilah yang saya cari ketika saya menemukan pertanyaan ini. Dalam kasus saya, saya ingin menarik perubahan dari cabang jarak jauh yang didorong secara paksa.

Matt
sumber