Bagaimana cara melihat pratinjau gabungan di git?

397

Saya memiliki cabang git (garis utama, misalnya) dan saya ingin menggabungkan cabang pengembangan lain. Atau saya?

Untuk memutuskan apakah saya benar-benar ingin menggabungkan cabang ini, saya ingin melihat semacam pratinjau tentang apa yang akan dilakukan penggabungan. Lebih disukai dengan kemampuan melihat daftar commit yang sedang diterapkan.

Sejauh ini, yang terbaik yang bisa saya lakukan adalah merge --no-ff --no-commit, dan kemudian diff HEAD.

Glenjamin
sumber
17
Saya hanya git mergedan git reset --keep HEAD@{1}jika saya tidak suka hasilnya.
Jan Hudec
3
Perhatikan bahwa melihat daftar commit dengan diff mereka tidak serta merta menceritakan keseluruhan cerita - jika penggabungan bersifat non-sepele, dan terutama jika ada konflik, hasil aktual dari penggabungan tersebut mungkin sedikit menarik.
Cascabel
2
Metode asli Anda melakukan hal itu. Inti dari komentar saya adalah bahwa meskipun melihat perbedaan individu semuanya baik dan bagus, jika Anda memiliki penggabungan yang kompleks, Anda mungkin berakhir dengan hasil yang mengejutkan bahkan jika semua komitmen yang digabung secara independen baik.
Cascabel
2
@ Jan: Untuk beberapa alasan, git reset --keep HEAD@{1}mengembalikan fatal: Cannot do a keep reset in the middle of a merge.Bantuan?
moey
3
Mengapa tidak ada --previewopsi di git-merge?
Gaui

Jawaban:

285

Saya telah menemukan bahwa solusi yang paling berhasil bagi saya adalah hanya melakukan penggabungan dan membatalkannya jika ada konflik . Sintaksis ini terasa bersih dan sederhana bagi saya. Ini adalah Strategi 2 di bawah ini.

Namun, jika Anda ingin memastikan Anda tidak mengacaukan cabang Anda saat ini, atau Anda hanya tidak siap untuk bergabung terlepas dari adanya konflik, cukup buat cabang pembantu baru darinya dan gabungkan bahwa:

Strategi 1: Cara aman - menggabungkan cabang sementara:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

Dengan begitu Anda bisa membuang cabang sementara jika Anda hanya ingin melihat apa konfliknya. Anda tidak perlu repot-repot "membatalkan" penggabungan, dan Anda dapat kembali ke pekerjaan Anda - cukup checkout 'mybranch' lagi dan Anda tidak akan memiliki kode gabungan atau menggabungkan konflik di cabang Anda.

Ini pada dasarnya adalah dry-run.

Strategi 2: Ketika Anda benar-benar ingin bergabung, tetapi hanya jika tidak ada konflik

git checkout mybranch
git merge some-other-branch

Jika git melaporkan konflik (dan HANYA JIKA ADA konflik), Anda dapat melakukannya:

git merge --abort

Jika penggabungan berhasil, Anda tidak dapat membatalkannya (hanya mengatur ulang).

Jika Anda belum siap untuk bergabung, gunakan cara yang lebih aman di atas.

[EDIT: 2016-Nov - Saya bertukar strategi 1 untuk 2, karena tampaknya kebanyakan orang mencari "jalan yang aman". Strategi 2 sekarang lebih merupakan catatan bahwa Anda bisa membatalkan penggabungan jika penggabungan memiliki konflik yang tidak siap untuk Anda tangani. Perlu diingat jika membaca komentar!]

Kasapo
sumber
2
+1 untuk strategi 2. Cabang sementara yang menunjukkan dengan tepat apa yang akan masuk saat penggabungan. Strategi 1 adalah apa yang saya coba hindari untuk kasus khusus ini.
Gordolio
2
Saya menyarankan mengubah strategi di sekitar sehingga yang lebih aman adalah yang pertama (pelatihan psikis saya datang - kebanyakan orang akan menganggap pilihan terbaik akan menjadi yang pertama, meskipun penggunaan kata "aman" yang lebih jelas) tetapi, selain itu, sangat baik pekerjaan.
paxdiablo
6
Anda dapat melakukan a git merge --no-ff --no-commitjika Anda tidak ingin melakukan perubahan secara langsung. Ini menghilangkan "kebutuhan" untuk cabang yang berbeda membuatnya sedikit lebih mudah untuk meninjau perubahan, imo.
Gerard van Helden
dan jika Anda memutuskan tidak ingin bergabung sama sekali dan bahkan lebih suka menulis beberapa kode lagi kemudian komit ke cabang Anda sehingga Anda dapat menggunakan HANYA cabang Anda pada server uji, tidakkah Anda masih harus mengembalikannya git merge --no-ff --no-commit? Saya kira Anda masih bisa melakukan git merge --abortsetelah itu jika Anda tidak suka apa yang Anda lihat? Bahkan jika penggabungan tidak menghasilkan konflik?
Kasapo
Kebanyakan orang suka menyalin dan menempel dan tidak terlalu banyak berpikir. Oleh karena itu, untuk Strategi 1, mungkin juga tambahkan cara membatalkan penggabungan di cabang lokal sementara git reset --hard HEADdan kemudian checkout cabang yang berbeda git checkout <different branch name>dan menghapus cabang sementara git delete -b <name of temporary branch>.
user3613932
402
  • git log ..otherbranch
    • daftar perubahan yang akan digabung ke cabang saat ini.
  • git diff ...otherbranch
    • berbeda dari nenek moyang yang sama (pangkalan gabungan) ke kepala dari apa yang akan digabung. Perhatikan tiga titik , yang memiliki arti khusus dibandingkan dengan dua titik (lihat di bawah).
  • gitk ...otherbranch
    • representasi grafis dari cabang-cabang sejak mereka bergabung terakhir kali.

String kosong menyiratkan HEAD, jadi itu sebabnya ..otherbranchalih-alih HEAD..otherbranch.

Dua vs tiga titik memiliki arti yang sedikit berbeda untuk diff daripada untuk perintah yang berisi daftar revisi (log, gitk dll.). Untuk log dan lainnya dua titik ( a..b) berarti semua yang ada btetapi tidak adan tiga titik ( a...b) berarti semua yang ada hanya dalam satu aatau b. Tetapi diff bekerja dengan dua revisi dan di sana kasus sederhana diwakili oleh dua titik ( a..b) adalah perbedaan sederhana dari ake bdan tiga titik ( a...b) perbedaan rata-rata antara leluhur yang sama dan b( git diff $(git merge-base a b)..b).

Jan Hudec
sumber
7
Titik ketiga adalah bagian yang saya lewatkan, terima kasih! Pendekatan log juga berfungsi dengan baik, log -p --reverse ..otherbranch sepertinya cara yang baik untuk melihat apa yang akan digabungkan.
Glenjamin
1
Saya hilang git checkout mastersebelum saya mencoba ini. Saya bertanya-tanya mengapa dikatakan semua perubahan saya akan dituliskan secara berlebihan ...
Droogans
5
git show ..otherbranchakan menampilkan daftar perubahan dan perbedaan yang akan digabung ke cabang saat ini.
Gaui
4
Ini tidak sepenuhnya akurat, terutama untuk pilihan ceri.
void.pointer
2
@ void.pointer, git tidak memperlakukan cherry-picks khususnya dalam penggabungan normal sehingga tidak ada di sini juga. Strategi gabungan dapat ditulis yang akan, tetapi sejauh yang saya tahu, tidak pernah ada.
Jan Hudec
19

Jika Anda seperti saya, Anda mencari yang setara dengan svn update -n. Berikut ini adalah triknya. Perhatikan bahwa pastikan untuk melakukan yang git fetchpertama sehingga repo lokal Anda memiliki pembaruan yang sesuai untuk dibandingkan.

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

atau jika Anda ingin diff dari kepala Anda ke remote:

$ git fetch origin
$ git diff origin/master

IMO solusi ini jauh lebih mudah dan lebih sedikit kesalahan rawan (dan karenanya jauh lebih sedikit berisiko) daripada solusi teratas yang mengusulkan "menggabungkan kemudian membatalkan".

Djschny
sumber
1
seharusnya $ git checkout target-branchdan kemudian $ git diff --name-status ...branch-to-be-merged(tiga titik sangat penting jadi ketik mereka seperti apa adanya)
Lu55
Satu hal yang hilang: ini tidak menunjukkan kepada Anda file mana yang akan memiliki konflik - mereka memiliki penanda "M" yang sama dengan file yang telah dimodifikasi pada cabang tetapi dapat digabung tanpa konflik.
peterflynn
Mungkin hal-hal berbeda di 2012, tetapi hari ini membatalkan penggabungan tampaknya cukup dapat diandalkan, jadi saya tidak berpikir adil untuk menggambarkan ini sebagai "lebih mudah dan lebih sedikit kesalahan rawan" sekarang.
David Z
8

Sebagian besar jawaban di sini membutuhkan direktori kerja yang bersih dan beberapa langkah interaktif (buruk untuk skrip), atau tidak berfungsi untuk semua kasus, misalnya penggabungan sebelumnya yang telah membawa beberapa perubahan luar biasa ke cabang target Anda, atau cherry-picks yang melakukan sama.

Untuk benar-benar melihat apa yang akan berubah di mastercabang jika Anda bergabung developdengannya, sekarang:

git merge-tree $(git merge-base master develop) master develop

Karena ini perintah pemipaan, tidak menebak apa yang Anda maksud, Anda harus eksplisit. Itu juga tidak mewarnai keluaran atau menggunakan pager Anda, jadi perintah lengkapnya adalah:

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

- https://git.seveas.net/previewing-a-merge-result.html

(terima kasih kepada David Normington untuk tautannya)

PS:

Jika Anda mendapatkan gabungan konflik, mereka akan muncul dengan penanda konflik yang biasa di output, misalnya:

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

Pengguna @dreftymac membuat poin yang bagus: ini membuatnya tidak cocok untuk skrip, karena Anda tidak dapat dengan mudah menangkapnya dari kode status. Penanda konflik dapat sangat berbeda tergantung pada keadaan (dihapus vs dimodifikasi, dll), yang membuatnya sulit untuk dipahami juga. Waspadalah.

hraban
sumber
1
@hraban Ini sepertinya jawaban yang benar, namun ternyata masih ada satu elemen yang hilang. Pendekatan ini mengharuskan pengguna untuk "melihat" output untuk melihat apakah ada penanda konflik. Apakah Anda memiliki pendekatan yang hanya mengembalikan truejika ada konflik dan falsejika tidak ada konflik (misalnya, nilai boolean yang tidak memerlukan tes "bola mata" atau intervensi manusia).
dreftymac
1
@dreftymac tidak dapat menemukan apa pun untuk efek itu. Anda bisa menggunakan sesuatu seperti git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to mergetetapi itu sangat bagus; Saya mungkin lupa sebuah kasus. mungkin Anda ingin memeriksa penanda konflik, bukan? misalnya ini mungkin tidak menangkap konflik gaya "mereka dihapus, kami berubah". (Saya baru saja memeriksa dan itu bahkan tidak menunjukkan penanda konflik, jadi Anda perlu regex yang cermat untuk aman di sini)
hraban
1
Gunakan less -Runtuk menangani keluaran berwarna tanpa mengubah konfigurasi Anda.
Giacomo Alzetta
Terima kasih @GiacomoAlzetta, saya telah memperbaruinya.
hraban
6

Jika Anda sudah mengambil perubahan, favorit saya adalah:

git log ...@{u}

Itu perlu git 1.7.x Namun saya percaya. The @{u}notasi adalah "singkatan" untuk cabang hulu sehingga sedikit lebih fleksibel daripada git log ...origin/master.

Catatan: Jika Anda menggunakan zsh dan glog extended, Anda mungkin harus melakukan sesuatu seperti:

git log ...@\{u\}
Pablo Olmos de Aguilera C.
sumber
6

Menambahkan ke jawaban yang ada, alias dapat dibuat untuk menampilkan diff dan / atau log sebelum penggabungan. Banyak jawaban mengabaikan yang fetchharus dilakukan terlebih dahulu sebelum "melihat dulu" penggabungan; ini adalah alias yang menggabungkan dua langkah ini menjadi satu (meniru sesuatu yang mirip dengan mercurial hg incoming/outgoing )

Jadi, membangun " git log ..otherbranch", Anda dapat menambahkan yang berikut ke ~/.gitconfig:

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

Untuk simetri, alias berikut dapat digunakan untuk menunjukkan apa yang dilakukan dan akan didorong, sebelum mendorong:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

Dan kemudian Anda dapat menjalankan " git incoming" untuk menunjukkan banyak perubahan, atau " git incoming -p" untuk menampilkan tambalan (yaitu, "diff"), " git incoming --pretty=oneline", untuk ringkasan singkat, dll. Anda kemudian dapat (opsional) menjalankan " git pull" untuk sebenarnya bergabung. (Padahal, karena kamu sudah mengambil, penggabungan bisa dilakukan secara langsung.)

Demikian juga, " git outgoing" menunjukkan apa yang akan didorong jika Anda menjalankan " git push".

michael
sumber
3

git log currentbranch..otherbranchakan memberi Anda daftar komit yang akan masuk ke cabang saat ini jika Anda melakukan penggabungan. Argumen biasa untuk mencatat yang memberikan rincian tentang komit akan memberi Anda lebih banyak informasi.

git diff currentbranch otherbranchakan memberi Anda perbedaan antara dua komit yang akan menjadi satu. Ini akan menjadi perbedaan yang memberi Anda segala sesuatu yang akan digabungkan.

Apakah ini membantu?

Noufal Ibrahim
sumber
2
Sebenarnya salah. git log otherbranch..currentbranchmemberikan daftar komitmen pada cabang saat ini . The git diff otherbranch currentbranchmemberi Anda diff dari versi to-be-merger ke ujung saat ini, yaitu sekitar sebagai tidak berguna karena dapat, karena apa yang Anda inginkan adalah diff dari dasar penggabungan ke kepala merge.
Jan Hudec
Terima kasih. Saya sudah mengganti nama treeishes.
Noufal Ibrahim
3

Permintaan Tarik - Saya telah menggunakan sebagian besar ide yang sudah dikirimkan tetapi salah satu yang juga sering saya gunakan adalah (terutama jika berasal dari pengembang lain) melakukan Permintaan Tarik yang memberikan cara praktis untuk meninjau semua perubahan dalam penggabungan sebelum dibutuhkan tempat. Saya tahu itu adalah GitHub bukan git tetapi tentu berguna.

G-Man
sumber
2

Singkatnya benar-benar melakukan penggabungan dengan cara membuang (lihat jawaban Kasapo), tampaknya tidak ada cara yang dapat diandalkan untuk melihat ini.

Karena itu, inilah metode yang hampir sama:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

Ini memberikan indikasi yang adil tentang komitmen yang akan membuatnya menjadi penggabungan. Untuk melihat perbedaan, tambahkan -p. Untuk melihat nama file, menambahkan dari --raw, --stat, --name-only, --name-status.

Masalah dengan git diff TARGET_BRANCH...SOURCE_BRANCHpendekatan (lihat jawaban Jan Hudec) adalah, Anda akan melihat perbedaan untuk perubahan yang sudah ada di cabang target Anda jika cabang sumber Anda berisi gabungan silang.

antak
sumber
1

Mungkin ini bisa membantu Anda? git-diff-tree - Membandingkan konten dan mode gumpalan yang ditemukan melalui dua objek pohon

Chugaister
sumber
1

Saya tidak ingin menggunakan perintah git merge sebagai prekursor untuk meninjau file yang saling bertentangan. Saya tidak ingin melakukan penggabungan, saya ingin mengidentifikasi potensi masalah sebelum bergabung - masalah yang mungkin disembunyikan auto-gabungan dari saya. Solusi yang saya cari adalah bagaimana cara meludah git daftar file yang telah diubah di kedua cabang yang akan digabung bersama di masa depan, relatif terhadap beberapa leluhur umum. Setelah saya memiliki daftar itu, saya dapat menggunakan alat perbandingan file lainnya untuk mencari tahu lebih lanjut. Saya telah mencari beberapa kali, dan saya masih belum menemukan apa yang saya inginkan dalam perintah git asli.

Ini solusi saya, kalau-kalau ini membantu orang lain di luar sana:

Dalam skenario ini saya memiliki cabang bernama QA yang memiliki banyak perubahan di dalamnya sejak rilis produksi terakhir. Rilis produksi terakhir kami ditandai dengan "15.20.1". Saya memiliki cabang pengembangan lain yang disebut new_stuff yang ingin saya gabungkan ke cabang QA. Baik QA dan new_stuff menunjuk untuk melakukan "follow" (seperti yang dilaporkan oleh gitk) pada tag 15.20.1.

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

Berikut adalah beberapa diskusi yang menjelaskan mengapa saya tertarik menargetkan file-file spesifik ini:

Bagaimana saya bisa mempercayai Git bergabung?

/software/199780/how-far-do-you-trust-automerge

Laura
sumber