Alat sederhana untuk 'menerima milik mereka' atau 'menerima milik saya' pada seluruh file menggunakan git

399

Saya tidak ingin alat penggabungan visual, dan saya juga tidak ingin harus vi file yang konflik dan secara manual memilih antara KEPALA (milik saya) dan perubahan yang diimpor (milik mereka). Sebagian besar waktu saya ingin semua perubahan mereka atau semua milik saya. Biasanya ini adalah karena perubahan saya membuatnya naik turun dan kembali kepada saya melalui tarikan, tetapi mungkin sedikit dimodifikasi di berbagai tempat.

Apakah ada alat baris perintah yang akan menghilangkan penanda konflik dan memilih semua cara berdasarkan pilihan saya? Atau satu set perintah git yang bisa saya alias buat sendiri masing-masing.

# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"

Melakukan ini agak menyebalkan. Untuk 'menerima milikku' saya sudah mencoba:

randy@sabotage ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.

randy@sabotage ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

andy@sabotage ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

Bagaimana saya bisa menyingkirkan spidol perubahan ini?

Dapat saya lakukan:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

Tapi ini agaknya berputar, pasti ada cara yang lebih baik. Dan pada titik ini, saya tidak yakin apakah git bahkan berpikir penggabungan terjadi, jadi saya tidak berpikir ini bahkan berfungsi.

Sebaliknya, melakukan 'menerima milik mereka' sama berantakannya. Satu-satunya cara saya bisa mengetahuinya adalah melakukan:

git show test-branch:Makefile > Makefile; git add Makefile;

Ini juga memberi saya pesan komit kacau, yang memiliki Konflik: Makefile di dalamnya dua kali.

Dapatkah seseorang tolong tunjukkan bagaimana melakukan dua tindakan di atas dengan cara yang lebih sederhana? Terima kasih

nosatalian
sumber
4
Saya harus memberikannya kepada Anda sebagai pengguna baris perintah + git tiga tahun saya merasa ini sangat sulit dilakukan dari memori. Ini benar-benar harus dibangun secara default.
Mauvis Ledford

Jawaban:

602

Solusinya sangat sederhana. git checkout <filename>mencoba memeriksa file dari indeks , dan karena itu gagal saat digabung.

Yang perlu Anda lakukan adalah (yaitu checkout komit ):

Untuk checkout versi Anda sendiri, Anda dapat menggunakan salah satu dari:

git checkout HEAD -- <filename>

atau

git checkout --ours -- <filename>

atau

git show :2:<filename> > <filename> # (stage 2 is ours)

Untuk checkout versi lain, Anda dapat menggunakan salah satu dari:

git checkout test-branch -- <filename>

atau

git checkout --theirs -- <filename>

atau

git show :3:<filename> > <filename> # (stage 3 is theirs)

Anda juga perlu menjalankan 'tambah' untuk menandainya sebagai terselesaikan:

git add <filename>
Jakub Narębski
sumber
31
Saya merasa agak aneh --oursdan itu --theirsberarti kebalikan dari apa yang saya pikir secara intuitif ketika mencoba perintah ini ...
Joshua Muheim
6
Hati-hati saat menggunakan git show- ini melompati normalisasi baris baru.
Kronik
2
Ini bagus untuk beberapa file, tetapi ketika Anda memiliki banyak file dalam konflik (karena tanggal dalam komentar berubah!), Bagaimana Anda melakukannya?
JhovaniC
4
@Santhos: --digunakan oleh Git untuk memisahkan revisi (nama cabang dll.) Dari nama path (nama file, direktori). Penting jika Git tidak dapat memutuskan apakah nama adalah nama cabang atau nama file. Ini mengikuti konvensi POSIX (atau GNU) tentang penggunaan tanda hubung ganda untuk memisahkan opsi dari argumen (nama file).
Jakub Narębski
3
@Sammaron @ Yosua Muheim; tanda theirs/ oursdapat ditukar jika Anda menyelesaikan konflik dalam konteks operasi rebase. Karena rebase bekerja dengan memeriksa cabang target kemudian memetik ceri melakukan dari cabang "Anda" ke target, perubahan yang masuk ("milik mereka") adalah dari cabang "Anda", dan cabang saat ini adalah cabang target ("milik kita" ).
RJFalconer
93

Coba ini:

Untuk menerima perubahan mereka: git merge --strategy-option theirs

Untuk menerima milik Anda: git merge --strategy-option ours

Siva Mandadi
sumber
5
Perhatikan bahwa ini akan menjaga perubahan Anda untuk SEMUA file yang bentrok, sehingga bisa berbahaya jika terjadi konflik yang tidak terduga.
John
3
Dan Anda bisa menggunakan ini untuk perintah gabungan-y lainnya seperti cherry-pick dan rebase.
idbrii
50

Berdasarkan jawaban Jakub Anda dapat mengkonfigurasi alias git berikut untuk kenyamanan:

accept-ours = "!f() { git checkout --ours -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
accept-theirs = "!f() { git checkout --theirs -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"

Mereka secara opsional mengambil satu atau beberapa jalur file untuk diselesaikan dan default untuk menyelesaikan semuanya di bawah direktori saat ini jika tidak ada yang diberikan.

Tambahkan mereka ke [alias]bagian Anda ~/.gitconfigatau jalankan

git config --global alias.accept-ours '!f() { git checkout --ours -- "${@:-.}"; git add -u "${@:-.}"; }; f'
git config --global alias.accept-theirs '!f() { git checkout --theirs -- "${@:-.}"; git add -u "${@:-.}"; }; f'
kynan
sumber
1
Tidak bekerja untuk saya ... Apakah ini untuk bash atau shell lain?
user456584
Ini adalah alias git, tambahkan ke [alias]bagian dalam Anda ~.gitconfigatau gunakan git config --global accept-ours "...". Telah mengedit jawaban saya.
kynan
2
Anda tidak tahu berapa lama alias ini menyelamatkan saya. Jempolan!
Adam Parkin
1
@ hakre Pastikan Anda mengutip alias, jika tidak, shell Anda akan mencoba menafsirkannya. Atau cukup edit secara manual ~/.gitconfig.
kynan
1
Sintaks shell untuk nilai default:!f() { git checkout --ours -- "${@:-.}" git add -u "${@:-.}; }; f
jthill
17

Berdasarkan jawaban kynan, berikut adalah alias yang sama, dimodifikasi sehingga mereka dapat menangani spasi dan tanda hubung awal dalam nama file:

accept-ours = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --ours -- \"$@\"; git add -u -- \"$@\"; }; f"
accept-theirs = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --theirs -- \"$@\"; git add -u -- \"$@\"; }; f"
Dar
sumber
0

Situasi ideal untuk menyelesaikan konflik adalah ketika Anda tahu sebelumnya tentang cara mana Anda ingin menyelesaikannya dan dapat melewati -Xoursatau -Xtheirsmenggabungkan opsi strategi rekursif. Di luar ini, saya bisa melihat tiga scenarious:

  1. Anda hanya ingin menyimpan satu versi file (ini mungkin hanya boleh digunakan pada file biner yang tidak dapat digabungkan, karena file yang berkonflik dan tidak berkonflik mungkin tidak sinkron satu sama lain).
  2. Anda ingin memutuskan semua konflik dalam arah tertentu.
  3. Anda perlu menyelesaikan beberapa konflik secara manual dan kemudian menyelesaikan sisanya dalam arah tertentu.

Untuk mengatasi tiga skenario ini, Anda dapat menambahkan baris berikut ke .gitconfigfile Anda (atau yang setara):

[merge]
  conflictstyle = diff3
[mergetool.getours]
  cmd = git-checkout --ours ${MERGED}
  trustExitCode = true
[mergetool.mergeours]
  cmd = git-merge-file --ours ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keepours]
  cmd = sed -I '' -e '/^<<<<<<</d' -e '/^|||||||/,/^>>>>>>>/d' ${MERGED}
  trustExitCode = true
[mergetool.gettheirs]
  cmd = git-checkout --theirs ${MERGED}
  trustExitCode = true
[mergetool.mergetheirs]
  cmd = git-merge-file --theirs ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keeptheirs]
  cmd = sed -I '' -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' ${MERGED}
  trustExitCode = true

The get(ours|theirs)alat hanya terus versi masing dari file dan membuang semua perubahan dari versi lain (sehingga tidak ada penggabungan terjadi).

The merge(ours|theirs)alat re-melakukan penggabungan tiga jalan dari lokal, dasar, dan versi jarak jauh dari file, memilih untuk menyelesaikan konflik di arah tertentu. Ini memiliki beberapa peringatan, khususnya: ia mengabaikan opsi diff yang diteruskan ke perintah penggabungan (seperti algoritma dan penanganan spasi putih); apakah penggabungan bersih dari file asli (sehingga setiap perubahan manual ke file tersebut dibuang, yang bisa baik atau buruk); dan memiliki keuntungan yang tidak dapat dikacaukan oleh spidol berbeda yang seharusnya ada dalam file.

The keep(ours|theirs)alat hanya suntingan penanda diff dan bagian tertutup, mendeteksi mereka dengan ekspresi reguler. Ini memiliki keuntungan bahwa ia mempertahankan opsi-opsi diff dari perintah penggabungan dan memungkinkan Anda untuk menyelesaikan beberapa konflik dengan tangan dan kemudian secara otomatis menyelesaikan sisanya. Ini memiliki kelemahan bahwa jika ada penanda konflik lain dalam file itu bisa membingungkan.

Ini semua digunakan dengan menjalankan di git mergetool -t (get|merge|keep)(ours|theirs) [<filename>]mana jika <filename>tidak disediakan itu memproses semua file yang bertentangan.

Secara umum, dengan asumsi Anda tahu tidak ada penanda berbeda untuk membingungkan ekspresi reguler, keep*varian dari perintah adalah yang paling kuat. Jika Anda membiarkan mergetool.keepBackupopsi tidak disetel atau benar, maka setelah penggabungan, Anda dapat melakukan diff *.origfile terhadap hasil penggabungan untuk memeriksa apakah masuk akal. Sebagai contoh, saya menjalankan yang berikut setelah mergetoolhanya untuk memeriksa perubahan sebelum melakukan:

for f in `find . -name '*.orig'`; do vimdiff $f ${f%.orig}; done

Catatan : Jikamerge.conflictstyle tidak diff3maka /^|||||||/pola dalam sedaturan harusnya sebagai /^=======/gantinya.

Parakleta
sumber