Git'te bir birleştirmeyi nasıl önizleyebilirim?


397

Git şubesi var (örneğin ana hat) ve başka bir geliştirme dalında birleştirmek istiyorum. Yoksa ben mi?

Bu dalı gerçekten birleştirmek isteyip istemediğime karar vermek için, birleştirmenin ne yapacağının bir tür önizlemesini görmek istiyorum. Tercihen uygulanan taahhütlerin listesini görme yeteneği ile.

Şimdiye kadar, gelebileceğim en iyi şey merge --no-ff --no-commitve sonra diff HEAD.


17
Sadece git mergeve git reset --keep HEAD@{1}sonucu beğenmezsem.
Jan Hudec

3
Farkları ile taahhütlerin listesini görmek mutlaka tüm hikayeyi anlatmaz - birleştirme önemsizse ve özellikle çatışmalar varsa, birleştirme işleminin gerçek sonucu biraz ilginç olabilir.
Cascabel

2
Orijinal yönteminiz tam olarak bunu yapar. Benim yorumum, bireysel diffs'ye bakmak iyi ve iyi olsa da, karmaşık bir birleşiminiz varsa, birleştirilmiş tüm taahhütler bağımsız olarak iyi olsa bile şaşırtıcı sonuçlarla sonuçlanabilmenizdir.
Cascabel

2
@Jan: Bazı nedenlerle Yardım git reset --keep HEAD@{1}döndü fatal: Cannot do a keep reset in the middle of a merge.?
moey

3
Neden --previewgit-merge'de bir seçenek yok?
Gaui

Yanıtlar:


283

Benim için en iyi çözümün sadece birleştirme yapmak ve çatışmalar varsa iptal etmek olduğunu buldum . Bu sözdizimi benim için temiz ve basit geliyor. Bu Strateji 2 aşağıdaki .

Bununla birlikte, mevcut dalınızı karıştırmamanızı sağlamak istiyorsanız veya çakışmaların varlığından bağımsız olarak birleştirmeye hazır değilseniz, yeni bir alt dal oluşturun ve aşağıdakileri birleştirin:

Strateji 1: Güvenli yol - geçici bir şubeyi birleştirin:

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

Bu şekilde, sadece çatışmaların ne olduğunu görmek istiyorsanız geçici şubeyi atabilirsiniz. Birleştirmeyi "durdurma" zahmetine girmenize gerek yoktur ve işinize geri dönebilirsiniz - 'mybranch' i tekrar kontrol edin ve şubenizde birleştirilmiş kod veya birleştirme çakışmaları olmayacaktır.

Bu temelde kuru bir çalışmadır.

Strateji 2: Kesinlikle birleşmek istediğinizde, ancak sadece çatışma yoksa

git checkout mybranch
git merge some-other-branch

Git çakışmaları bildirirse (ve SADECE çatışırsa ) şunları yapabilirsiniz:

git merge --abort

Birleştirme başarılı olursa, iptal edemezsiniz (yalnızca sıfırlama).

Birleşmeye hazır değilseniz, yukarıdaki daha güvenli yolu kullanın.

[DÜZENLEME: 2016-Kasım - Strateji 1'i 2 için değiştirdim, çünkü çoğu insan “güvenli yolu” arıyor gibi görünüyor. Strateji 2 artık, birleştirmenin ele almaya hazır olmadığınız çatışmalar varsa birleştirmeyi iptal edebileceğiniz bir nottur. Yorumları okuyorsanız unutmayın!]


2
Strateji için +1. 2. Birleştirme sırasında neler olacağını tam olarak gösteren geçici dal. Strateji 1, bu özel durum için kaçınmaya çalışıyorum.
Gordolio

2
Daha güvenli olanın ilk olması için stratejileri değiştirmenizi öneririm (benim psişik eğitimim geliyor - çoğu insan "daha güvenli" kelimesinin açık kullanımına rağmen en iyi seçeneğin ilk seçenek olacağını varsayar) ama bunun dışında mükemmel iş.
paxdiablo

6
Bir yapabileceğini git merge --no-ff --no-commitdoğrudan değişiklikleri işlemek istemiyorsanız. Bu, farklı bir dal için "ihtiyacı" ortadan kaldırır, imo, değişiklikleri gözden biraz daha kolay hale getirir.
Gerard van Helden

ve eğer birleştirmek istemediğinize karar verirseniz ve aslında biraz daha kod yazmayı ve sonra da şubenize bağlı kalmanızı sağlarsanız, SADECE şubenizi bir test sunucusuna dağıtabilirsiniz, yine de geri dönmeniz gerekmez git merge --no-ff --no-commitmi? git merge --abortGördüğünüzü beğenmediyseniz , bundan sonra hala yapabilirsiniz sanırım ? Birleştirme çatışma yaratmasa bile?
Kasapo

Çoğu insan kopyalayıp yapıştırmayı sever ve fazla düşünmez. Bu nedenle, Strateji 1 için, belki de geçici yerel şubedeki birleştirmeyi iptal etmeyi git reset --hard HEADve ardından farklı bir şubeyi kullanıma alma git checkout <different branch name>ve geçici şubeyi silme yöntemini de ekleyin.git delete -b <name of temporary branch> .
user3613932

401
  • git log ..otherbranch
    • geçerli dalda birleştirilecek değişikliklerin listesi.
  • git diff ...otherbranch
    • ortak atadan (birleştirme tabanı) birleştirilecek olanın başına farklılık gösterir. İki nokta ile karşılaştırıldığında özel bir anlamı olan üç noktayı not edin (aşağıya bakınız).
  • gitk ...otherbranch
    • Şubelerin son kez birleştirilmelerinden bu yana grafiksel gösterimi.

Boş dize ima HEADo yüzden sadece bu yüzden, ..otherbranchyerineHEAD..otherbranch .

İki ve üç nokta, diff için revizyonları listeleyen komutlara (log, gitk vb.) Göre biraz farklı anlamlara sahiptir. Günlük ve diğerleri için iki nokta ( a..b), içinde olan bama olmayan her şey anlamına gelir ave üç nokta ( a...b), aya da yalnızca birinde bulunan her şey anlamına gelir b. Fakat iki nokta ile temsil iki revizyonlar ve orada daha basit durumda (ile fark eserler a..b) basitten farktır aiçin bve üç nokta ( a...b) ortak atadan ve arasındaki ortalama fark b( git diff $(git merge-base a b)..b).


7
Üçüncü nokta, eksik olduğum kısımdı, teşekkürler! Günlük yaklaşımı da iyi çalışıyor, log -p --reverse ..otherbranch neyin birleştirileceğini görmek için iyi bir yol gibi görünüyor.
Glenjamin

1
Bunu denemeden git checkout masterönce kayboldum . Neden tüm değişikliklerinimin üzerine yazılacağını söylediğini merak ediyordum ...
Droogans

5
git show ..otherbranchgeçerli dalda birleştirilecek değişikliklerin ve farkların bir listesini gösterir.
Gaui

4
Bu, özellikle kiraz seçimleri için tamamen doğru değildir.
void.pointer

2
@ void.pointer, git özellikle kiraz birleşimlerini normal birleştirme ile tedavi etmez, bu yüzden burada da olmaz. Birleştirme stratejisi yazılabilirdi, ama bildiğim kadarıyla böyle değildi.
Jan Hudec

19

Eğer benim gibiyseniz, eşdeğerini arıyorsunuz svn update -n. Aşağıdaki hile yapmak gibi görünüyor. git fetchYerel repo'nuzun karşılaştırılacak uygun güncellemelere sahip olması için bir ilk yaptığınızdan emin olun .

$ 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

veya kafanızdan uzaktan kumandayla bir fark istiyorsanız:

$ git fetch origin
$ git diff origin/master

IMO bu çözüm "birleştirme sonra iptal" öneren üst çözüm çok daha kolay ve daha az hata eğilimli (ve bu nedenle çok daha az riskli).


1
olmalı $ git checkout target-branchve sonra $ git diff --name-status ...branch-to-be-merged(üç nokta önemlidir, bu yüzden onları olduğu gibi yazın)
Lu55

Bu eksik olan bir şey: hangi dosyaların bir çakışma olacağını göstermez - dalda değiştirilen ancak herhangi bir çakışma olmadan birleştirilebilen dosyalarla aynı "M" işaretçisine sahiptirler.
peterflynn

Belki 2012'de işler farklıydı, ancak bugünlerde bir birleştirmeyi iptal etmek oldukça güvenilir görünüyor, bu yüzden bunu şu anda "çok daha kolay ve daha az hataya eğilimli" olarak nitelendirmenin adil olduğunu düşünmüyorum.
David Z

8

Buradaki yanıtların çoğu ya temiz bir çalışma dizini ve birden çok etkileşimli adım gerektirir (komut dosyası oluşturma için kötüdür) ya da tüm durumlar için işe yaramaz, örneğin, halihazırda seçili değişikliklerin bazılarını hedef dalınıza getiren geçmiş birleştirme veya bunu yapan kiraz seçimleri aynı.

masterŞube ile birleştiyseniz , şubede nelerin değişeceğini gerçekten görmek için develop:

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

Bir sıhhi tesisat komutu olduğu için ne demek istediğinizi tahmin etmiyor, açık olmalısınız. Ayrıca çıktıyı renklendirmez veya çağrı cihazınızı kullanmaz, bu nedenle tam komut şöyledir:

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

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

(bağlantı için David Normington'a teşekkürler)

Not:

Birleştirme çakışmalarına maruz kalırsanız, çıktıdaki olağan çakışma belirteçleriyle görünürler, örneğin:

$ 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

User @dreftymac iyi bir noktaya işaret eder: bunu komut dosyası için uygun değildir, çünkü bunu durum kodundan kolayca yakalayamazsınız. Çatışma belirteçleri duruma bağlı olarak oldukça farklı olabilir (silindi vs değiştirildi vs), bu da grep'i zorlaştırır. Dikkat.


1
@hraban Bu doğru cevaba benziyor, ancak görünüşe göre bir eksik öğe var. Bu yaklaşım, kullanıcının çakışma belirteçlerinin mevcut olup olmadığını görmek için çıktıyı "göz küresi" yapmasını gerektirir. trueÇatışmalar falsevarsa ve çatışma yoksa (örneğin, "göz küresi" testi veya herhangi bir insan müdahalesi gerektirmeyen bir boole değeri) geri dönen bir yaklaşımınız var mı?
dreftymac

1
@dreftymac bu etki için hiçbir şey bulamaz. gibi bir şey kullanabilirsiniz git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to mergeama bu şık; Muhtemelen bir vakayı unutuyorum. belki de bunun yerine çakışma belirteçlerini kontrol etmek istersiniz? örneğin bu muhtemelen "onların silinmiş, bizimki değişti" stil çatışmalarını yakalamaz. (Sadece kontrol ettim ve bu bile çatışma işaretleri göstermiyor, bu yüzden burada güvende olmak için titiz bir
regex'e

1
less -RYapılandırmanızı değiştirmeden renkli çıktıyı işlemek için kullanın .
Giacomo Alzetta

Teşekkürler @GiacomoAlzetta, güncelledim.
hraban

6

Değişiklikleri zaten getirdiyseniz, favorim:

git log ...@{u}

Buna rağmen git 1.7.x gerekiyor. @{u}Daha çok yönlü biraz bu yüzden notasyonu memba dalı için bir "stenografi" dir git log ...origin/master.

Not: zsh ve genişletilmiş glog şeyi kullanıyorsanız, büyük olasılıkla aşağıdaki gibi bir şey yapmanız gerekir:

git log ...@\{u\}

6

Mevcut yanıtlara ek olarak, birleştirme işleminden önce fark ve / veya günlüğü göstermek için bir takma ad oluşturulabilir. Birçok cevap fetchbirleştirme "önizleme" önce ilk yapılmasını atlamak ; bu bir içine bu iki adımı birleştiren bir takma addır (cıva yıllardan benzer taklit şey hg incoming/ outgoing)

Böylece, " git log ..otherbranch" üzerine inşa etmek için aşağıdakileri ekleyebilirsiniz ~/.gitconfig:

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

Simetri için, itme işleminden önce neyin taahhüt edildiğini ve itileceğini göstermek için aşağıdaki takma ad kullanılabilir:

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

Ve sonra git incomingçok sayıda değişiklik git incoming -pgöstermek için " " ya da git incoming --pretty=onelinekısa bir özet için " " yamayı (ör. "Fark"), " ", " " çalıştırabilirsiniz. Sonra (isteğe bağlı olarak) çalışabilirsiniz "git pull " " aslında birleşir. (Yine de, zaten getirdiğiniz için birleştirme doğrudan yapılabilir.)

Aynı şekilde, " git outgoing" koşacak olsaydınız neyin itileceğini gösterir " git push".


3

git log currentbranch..otherbranchbirleştirme yaparsanız geçerli şubeye gidecek olan taahhütlerin listesini verir. Taahhütler hakkında ayrıntılar veren günlük için kullanılan argümanlar size daha fazla bilgi verecektir.

git diff currentbranch otherbranchbir olacak iki taahhüt arasındaki farkı verecektir. Bu, birleştirilecek her şeyi size veren bir fark olacaktır.

Bunlar yardımcı olur mu?


2
Aslında yanlış. currentbranch ilegit log otherbranch..currentbranch ilgili taahhütlerin bir listesini verir . Bu git diff otherbranch currentbranch, birleştirilecek sürümden geçerli ipucuna fark verir, bu da olabildiğince işe yaramaz, çünkü istediğiniz şey birleştirme tabanından birleştirme kafasına farklılık gösterir.
Jan Hudec

Teşekkürler. Ağaçların isimlerini değiştirdim.
Noufal Ibrahim

3

Çekme İsteği - Zaten gönderilen fikirlerin çoğunu kullandım, ancak sık sık kullandığım (özellikle başka bir geliştiriciden), bir birleşimdeki tüm değişiklikleri gözden geçirmeden önce gözden geçirmenin kullanışlı bir yolunu veren bir Çekme İsteği yapıyor. yer. GitHub'ın git olmadığını biliyorum ama kesinlikle kullanışlı.


2

Birleşmeyi bir atmak tarzında yapmaktan (Kasapo'nun cevabına bakın) kısa bir süre sonra, bunu görmenin güvenilir bir yolu yok gibi görünüyor.

Bunu söyledikten sonra, marjinal olarak yaklaşan bir yöntem var:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

Bu, hangi taahhütlerin birleştirmeye gireceğini açık bir şekilde gösterir. Farkları görmek için ekleyin -p. Herhangi ekleyebilir, dosya adlarını görmek için --raw, --stat, --name-only, --name-status.

git diff TARGET_BRANCH...SOURCE_BRANCHYaklaşımdaki sorun (bkz.


1

Belki bu sana yardımcı olabilir? git-diff-tree - İki ağaç nesnesi aracılığıyla bulunan lekelerin içeriğini ve modunu karşılaştırır


1

Git birleştirme komutunu çakışan dosyaları incelemek için öncü olarak kullanmak istemiyorum. Birleştirme yapmak istemiyorum, birleştirmeden önce olası sorunları tanımlamak istiyorum - otomatik birleştirmenin benden gizleyebileceği sorunlar. Aradığım çözüm, git, bazı ortak atalara göre gelecekte birleştirilecek olan her iki dalda değiştirilen dosyaların bir listesini nasıl tükürmek. Bu listeye sahip olduğumda, işleri daha fazla keşfetmek için diğer dosya karşılaştırma araçlarını kullanabilirim. Birden çok kez arama yaptım ve hala yerel bir git komutunda ne istediğimi bulamadım.

İşte benim geçici çözüm, orada başka birine yardımcı olması durumunda:

Bu senaryoda, son üretim sürümünden bu yana pek çok değişikliğe sahip KG adı verilen bir şubem var. Son üretim sürümümüz "15.20.1" olarak etiketlendi. KG şubesine birleştirmek istediğim new_stuff adında başka bir geliştirme dalı var. Hem KG hem de new_stuff, 15.20.1 etiketini (gitk tarafından bildirildiği gibi) takip ettiğini taahhüt eder.

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

İşte bu belirli dosyaları neden hedeflemekle ilgilendiğimi gösteren bazı tartışmalar:

Git birleşmesine nasıl güvenebilirim?

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.