Tidak terlalu terkait dengan jawaban ini, tetapi saya akan membuang git pull
, yang hanya git fetch
diikuti 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 , -X
opsi diteruskan ke strategi penggabungan, dan baik recursive
strategi default maupun resolve
strategi alternatif mengambil -X ours
atau -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 diff
keluaran, 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 color
ke colour
baris 17 dan berubah fred
ke barney
baris 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 ours
dan -X theirs
pilihan 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
.
-X
Namun, 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 i
sebagai loop counter. Jika kita menggabungkan dua perubahan tersebut, kode yang dihasilkan tidak lagi dapat dikompilasi. The -X
pilihan 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-commit
ke git merge
perintah. 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 -X
argumennya.
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/demo
ke lokal demo
(penggunaan Anda git pull
yang, jika Git Anda sangat tua, akan gagal diperbarui origin/demo
tetapi akan menghasilkan hasil akhir yang sama). Yang kedua adalah origin/master
memasukkan master
.
Tidak jelas bagi saya siapa yang memperbarui demo
dan / atau master
. Jika Anda menulis kode Anda sendiri di demo
cabang Anda sendiri , dan orang lain menulis kode dan mendorongnya ke demo
cabang 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 demo
cabang. 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 demo
untuk mencocokkan yang diperbarui origin/demo
jika 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 demo
seluruhnya:
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 demo
komit cabang, ini tidak membantu; Anda mungkin juga mempertahankan penggabungan yang ada (tetapi mungkin menambahkan --ff-only
tergantung 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-only
mungkin 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).
git push -f origin master