Hangi durumlarda "git pull" zararlı olabilir?


409

Bunu iddia eden bir meslektaşım var git pullZararlı ve birisi her kullandığında üzülen .

git pullKomut yerel depoyu güncellemek için kurallı bir yol olarak görünmektedir. Kullanmak git pullsorun yaratıyor mu? Hangi sorunları yaratıyor? Git deposunu güncellemenin daha iyi bir yolu var mı?



8
Ya da sadece git pull --rebasebu stratejiyi yeni şubeler için varsayılan olarak ayarlayabilirsiniz git config branch.autosetuprebase
knoopx

4
knoopx bunu doğru yapar, uzaktan kumandayla yerel senkronize etmek için --rebasebayrak ekler git pullve daha sonra yerel değişikliklerinizi güncellenen yerelin üzerine tekrar oynatır. Sonra ittiğinizde yaptığınız tek şey yeni taahhütlerinizi uzaktan kumandanın sonuna eklemek. Gayet basit.
Heath Lilley

4
Teşekkürler @BenMcCormick. Bunu daha önce yapmıştım, ancak sorunun geçerliliği ile ilgili tartışma, sorunun altındaki bu yorumlarda yer alıyor gibi görünüyor. Ve bence kişisel fikrinizi sunmak için bir platform oluşturmak için bir soru sormak, SO'nun Soru-Cevap yapısının gerçekte ne olduğu değildir.
mcv

4
@RichardHansen, nokta sistemini aldatmanın bir yolu gibi görünüyor, özellikle de cevabınız tonda çok büyük bir fark ve kısa bir zaman boşluğu var. Soru-Cevap modelinizi kullanarak hepimiz soru sorabilir ve önceki bilgilerimizi kullanarak kendimize cevap verebiliriz. Bu noktada, bir blog yazısı yazmayı düşünmelisiniz, çünkü bu çok daha uygundur. Soru-Cevap özellikle başkalarının bilgisini arar. Bir blog yayını kendinizinkini gösterir.
Josh Brown

Yanıtlar:


546

özet

Varsayılan git pullolarak, kod geçmişine gürültü ve karmaşıklık katan birleştirme taahhütleri oluşturur. Ayrıca, pulldeğişikliklerinizin gelen değişikliklerden nasıl etkilenebileceğini düşünmemeyi kolaylaştırır.

git pullKomut kadar uzun sadece hızlı ileri birleştirmeyi gerçekleştirir olarak güvenlidir. Eğer git pullüzere yapılandırılmış sadece hızlı ileri birleştirmeleri yapmak ve ileri sarma birleştirme mümkün olmadığı durumlarda, o zaman Git bir hata ile çıkılacak. Bu, gelen taahhütleri incelemek, yerel taahhütlerinizi nasıl etkileyebileceklerini düşünmek ve en iyi eylem yoluna (birleştirme, yeniden pazarlama, sıfırlama vb.) Karar vermek için bir fırsat verecektir.

Git 2.0 ve daha yenisi ile şunları yapabilirsiniz:

git config --global pull.ff only

varsayılan davranışı yalnızca ileri sarmak için değiştirmek. 1.6.6 ve 1.9.x arasındaki Git sürümleri ile yazma alışkanlığı edinmeniz gerekir:

git pull --ff-only

Ancak, Git'in tüm sürümlerinde git upböyle bir takma ad yapılandırmanızı öneririz :

git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'

ve git upyerine kullanmak git pull. Bu takma adı tercih ederim git pull --ff-onlyçünkü:

  • Git'in tüm (eski olmayan) sürümleriyle çalışır,
  • tüm yukarı akış dallarını getirir (yalnızca üzerinde çalışmakta olduğunuz dal değil) ve
  • origin/*artık akış yukarı olmayan eski dalları temizler .

İle ilgili sorunlar git pull

git pulldoğru kullanılırsa fena değil. Git'te yapılan son değişikliklerin birçoğu git pulldüzgün kullanımını kolaylaştırdı , ancak maalesef bir ovanın varsayılan davranışının git pullbirkaç sorunu var:

  • tarihte gereksiz doğrusallıklara neden olur
  • yukarı doğru kasıtlı olarak yeniden yapılandırılan taahhütleri yanlışlıkla yeniden tanıtmayı kolaylaştırır
  • çalışma dizininizi öngörülemeyen şekillerde değiştirir
  • başkasının çalışmasını gözden geçirmek için yaptığınız işi duraklatmak git pull
  • uzak dalda doğru şekilde rebase yapmayı zorlaştırır
  • uzak depoda silinen şubeleri temizlemiyor

Bu sorunlar aşağıda daha ayrıntılı olarak açıklanmaktadır.

Doğrusal Olmayan Tarih

Varsayılan olarak, git pullkomut çalışmanın git fetchardından gelen ile eşdeğerdir git merge @{u}. Yerel depoda itilmemiş taahhütler varsa, birleştirme kısmı git pullbir birleştirme taahhüdü oluşturur.

Birleştirme taahhütlerinde doğal olarak kötü bir şey yoktur, ancak tehlikeli olabilirler ve saygıyla davranılmalıdırlar:

  • Birleştirme taahhütlerinin incelenmesi doğal olarak zordur. Birleşmenin ne yaptığını anlamak için, tüm ebeveynler arasındaki farklılıkları anlamalısınız. Geleneksel bir fark bu çok boyutlu bilgiyi iyi iletmez. Buna karşılık, bir dizi normal işlemin gözden geçirilmesi kolaydır.
  • Birleştirme çakışması çözümü zor ve birleştirme işlemlerinin incelenmesi zor olduğu için hatalar genellikle uzun bir süre algılanmaz.
  • Birleşme, düzenli taahhütlerin etkilerini sessizce geçersiz kılabilir. Kod artık artan taahhütlerin toplamı değildir ve gerçekte neyin değiştiği hakkında yanlış anlamalara yol açar.
  • Birleştirme taahhütleri bazı sürekli entegrasyon şemalarını bozabilir (örneğin, ikinci ebeveynlerin devam etmekte olan çalışmaları tamamlamadığına işaret ettiği varsayılan kural uyarınca sadece ilk ebeveyn yolunu otomatik olarak oluştur).

Tabii ki birleşme için bir zaman ve bir yer vardır, ancak birleşme ne zaman kullanılmalı ve kullanılmamalıdır anlaşılması deponuzun kullanışlılığını artırabilir.

Git'in amacının bir kod tabanının evrimini paylaşmayı ve tüketmeyi kolaylaştırmak olduğunu, geçmişi tam olarak açıldığı gibi kesin olarak kaydetmemek olduğunu unutmayın. (Eğer katılmıyorsanız, rebasekomutu ve neden yaratıldığını düşünün .) Tarafından oluşturulan birleştirme taahhütleri git pullbaşkalarına yararlı anlambilimleri aktarmaz - sadece siz değişikliklerinizi yapmadan önce bir başkasının depoya ittiğini söylerler. Bu birleştirme, başkaları için anlamlı değilse ve tehlikeli olabilirlerse neden taahhütte bulunurlar?

git pullBirleştirme yerine yeniden taban oluşturmak üzere yapılandırmak mümkündür , ancak bunun da sorunları vardır (daha sonra tartışılacaktır). Bunun yerine, git pullyalnızca hızlı ileri birleştirme yapacak şekilde yapılandırılmalıdır.

Geri Alınmış Komisyonların Yeniden Sunumu

Birisinin bir dalı yeniden bastığını ve onu zorladığını varsayalım. Bu genellikle olmamalıdır, ancak bazen gerekli olabilir (örneğin, yanlışlıkla taahhüt edilen ve itilen bir 50GiB günlük dosyasını kaldırmak). Tarafından yapılan git pullbirleştirme, yukarı akış dalının yeni sürümünü yerel deponuzda bulunan eski sürümle birleştirir. Sonucu zorlarsanız, zift çatalları ve el fenerleri yolunuza çıkmaya başlayacaktır.

Bazıları asıl sorunun zorlama güncellemeleri olduğunu iddia edebilir. Evet, genellikle mümkün olduğunda zorlamalardan kaçınmak önerilir, ancak bazen kaçınılmazdır. Geliştiriciler zorlayıcı güncellemelerle başa çıkmaya hazır olmalıdır, çünkü bazen olurlar. Bu, eski taahhütlerde sıradan bir yolla körü körüne birleşmemek anlamına gelir git pull.

Sürpriz Çalışma Dizini Değişiklikleri

Çalışma dizininin veya dizininin git pulltamamlanana kadar nasıl görüneceğini tahmin etmenin bir yolu yoktur . Başka bir şey yapmadan önce çözmeniz gereken birleştirme çakışmaları olabilir, birisi yanlışlıkla ittiği için çalışma dizininize 50GiB günlük dosyası ekleyebilir, içinde çalıştığınız bir dizini yeniden adlandırabilir, vb.

git remote update -p (veya git fetch --all -p ) birleştirmeye veya yeniden pazarlamaya karar vermeden önce başkalarının taahhütlerine bakmanıza olanak tanır ve harekete geçmeden önce bir plan oluşturmanıza olanak tanır.

Diğer İnsanların Taahhütlerini Gözden Geçirme Zorluğu

Bazı değişiklikler yapmanın ortasında olduğunuzu ve bir başkasının sadece ittikleri bazı taahhütleri gözden geçirmenizi istediğini varsayalım. git pulladlı birleştirme (veya rebase) işlemi, çalışma dizini ve dizini değiştirir, yani çalışma dizininizin ve dizininin temiz olması gerekir.

Kullanabilir git stashve sonra kullanabilirsiniz git pull, ancak incelemeyi bitirdiğinizde ne yaparsınız? Bulunduğunuz yere geri dönmek için, oluşturduğunuz birleştirmeyi geri almanız git pullve saklamayı uygulamanız gerekir.

git remote update -p(veya git fetch --all -p) çalışma dizinini veya dizinini değiştirmez, bu nedenle aşamalı ve / veya değişmemiş değişiklikleriniz olsa bile, herhangi bir zamanda çalıştırılması güvenlidir. Yaptığınız işi duraklatabilir ve üzerinde çalıştığınız taahhüdü saklamak veya bitirmek konusunda endişelenmeden başkasının taahhüdünü inceleyebilirsiniz.git pullsize bu esnekliği vermez.

Uzak bir Dalda Yeniden Oluşturma

Ortak bir Git kullanım modeli, git pullen son değişiklikleri getirmek için a yapmak ve bunu izleyen git rebase @{u}birleştirme taahhüdünü ortadan kaldırmak için a yapmaktır git pull. Bu Git anlatarak tek bir adımda için şu iki adımı azaltmak için bazı yapılandırma seçenekleri vardır bu ortak yeter git pullyerine birleştirme (bkz bir rebase gerçekleştirmek için branch.<branch>.rebase, branch.autosetuprebasevepull.rebase seçenekleri).

Bir unpushed birleştirme varsa maalesef korumak istediğiniz o taahhüt (örneğin bir içine itilmiş özellik dalı birleştirerek işlemek master), (bir Rebase-çekme ne git pullile branch.<branch>.rebasekarşı kümesi true), ne de bir birleştirme-çekme (varsayılan git pulla takiben davranış) rebase işe yarayacak. Çünkü seçenek git rebaseolmadan birleştirme (DAG doğrusallaştırır) ortadan kaldırır --preserve-merges. Rebase-pull işlemi, birleştirmeleri korumak için yapılandırılamaz ve bir birleştirme-çekmenin ardından birleştirme-çekmenin git rebase -p @{u}neden olduğu birleşmeyi ortadan kaldırmaz. Güncelleme: Git v1.8.5 eklendi git pull --rebase=preserveve git config pull.rebase preserve. Bunlar yukarı akış taahhütlerini getirdikten sonra git pullyapılmasına neden olur git rebase --preserve-merges. ( Funkaster'a teşekkürler -up !)

Silinmiş Şubeleri Temizleme

git pulluzak depodan silinen dallara karşılık gelen uzaktan izleme dallarını budamaz. Örneğin, biri foouzak repodan şubeyi silerse , yine deorigin/foo .

Bu, kullanıcıların hala aktif olduklarını düşündükleri için yanlışlıkla öldürülen dalları yeniden diriltmelerine yol açar.

Daha İyi Bir Alternatif: Kullanım git up yerinegit pull

Bunun yerine git pull, aşağıdaki git uptakma adı oluşturmanızı ve kullanmanızı öneririz :

git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'

Bu takma ad, tüm yukarı akış kollarından (ölü dalları budama) en son taahhütleri indirir ve yerel şubeyi yukarı akış dalındaki en son taahhüde hızlı bir şekilde iletmeye çalışır. Başarılı olursa, yerel taahhütler yoktu, bu nedenle birleşme çatışması riski yoktu. Yerel (sıkıştırılmamış) taahhütler varsa hızlı ileri alma başarısız olur ve harekete geçmeden önce yukarı akış taahhütlerini gözden geçirme fırsatı verir.

Bu, çalışma dizininizi öngörülemeyen yollarla değiştirir, ancak yalnızca yerel değişiklikleriniz yoksa. Bunun aksine git pull, git upsizi asla bir birleşme çatışmasını gidermenizi bekleyen bir isteme bırakmaz.

Başka seçenek: git pull --ff-only --all -p

Aşağıdaki git uptakma ad için bir alternatiftir :

git config --global alias.up 'pull --ff-only --all -p'

Öğesinin bu sürümü git up, aşağıdaki git uptakma adla aynı davranışa sahip :

  • yerel şubeniz yukarı akışlı bir dal ile yapılandırılmadıysa hata iletisi biraz daha şifreli
  • Git'in gelecekteki sürümlerinde değişebilecek belgelenmemiş bir özelliğe ( -piletilen argüman fetch) dayanır

Git 2.0 veya daha yenisini kullanıyorsanız

Git 2.0 ve daha yeni sürümlerle git pullvarsayılan olarak yalnızca ileri sarma birleştirmeleri yapılandırabilirsiniz :

git config --global pull.ff only

Bu git pullgibi davranmasına neden olur git pull --ff-only, ancak yine de tüm yukarı akış taahhütlerini getirmez veya eski origin/*dalları temizlemez, bu yüzden hala tercih ederim git up.


6
@brianz: git remote update -pile eşdeğerdir git fetch --all -p. Yazma alışkanlığım var git remote update -pçünkü bir zamanlar seçenek fetchyoktu -p. Önde gelen ilgili !, açıklamasına bakınız alias.*içinde git help config. "Takma ad genişletmesine bir ünlem işareti eklenirse, kabuk komutu olarak değerlendirilir."
Richard Hansen

13
Git 2.0 pull.ff, takma adlar olmadan aynı şeyi başarıyor gibi görünen bir yapılandırma ekler .
Danny Thomas

51
Bazı nedenler "diğerleri çılgınca şeyler yaptığında çekme sorunlarına neden olabilir" gibi geliyor. Hayır, sorun yaratan yukarı yönlü bir repodan vazgeçmek gibi çılgınca şeyler. IMO rebase'i henüz yerel olarak henüz itilmemiş bir taahhütte yaptığınızda güvenlidir. Örneğin, basmadan önce çektiğinizde, yerel taahhütlere yeniden basmak, geçmişinizin doğrusal kalmasına yardımcı olur (doğrusal tarih bir anlaşma kadar büyük olmasa da). Yine de git upilginç bir alternatif gibi geliyor.
mcv

16
Puanlarınızın çoğu yanlış bir şey yaptığınızdan kaynaklanmaktadır: kendi çalışma alanınızdaki kodu gözden geçirmeye çalışıyorsunuz . Bu iyi bir fikir değil, sadece yeni bir şube oluşturun, --rebase = koru ve ardından o dalı fırlatın (veya isterseniz birleştirin).
funkaster

5
@ funkaster'ın buradaki anlamı çok mantıklı, özellikle de: "Diğer İnsanların Taahhütlerini Gözden Geçirme Zorluğu". Bu, Git kullanıcılarının çoğunun gözden geçirme akışı değil, hiçbir yerde tavsiye edilmediğini gördüğüm bir şeydir ve başlığın altında açıklanan gereksiz tüm ekstra çalışmaların sebebidir git pull.
Ben Regenspan

195

Cevabım, ortaya çıkan tartışmadan çekildi HackerNews'te :

Soruyu Betteridge Manşet Kanunu'nu kullanarak cevaplamaya cazip hissediyorum: Neden git pullzararlı kabul ediliyor? Öyle değil.

  • Doğrusal olmayanlıklar özünde kötü değildir. Eğer gerçek tarihi temsil ediyorlarsa sorun olmaz.
  • Kaydedilmesini kazara reintroduction rebased memba yanlış tarih akış yönüne göre öncesinden yeniden yazma sonucudur. Geçmiş birkaç depoda çoğaltıldığında geçmişi yeniden yazamazsınız.
  • Çalışma dizinini değiştirmek beklenen bir sonuçtur; tartışmalı yararlılık, yani hg / monoton / darcs / other_dvcs_predating_git davranışı karşısında, ama yine de özünde kötü değil.
  • Birleştirme için başkalarının çalışmalarını gözden geçirmek için duraklatma gereklidir ve yine git pull'da beklenen bir davranıştır. Birleştirmek istemiyorsanız git getirme işlevini kullanmalısınız. Yine, bu önceki popüler DVD'lere kıyasla git'in bir deyimidir, ancak beklenen davranıştır ve özünde kötü değildir.
  • Uzak bir şubeye karşı yeniden pazarlamayı zorlaştırmak iyidir. Kesinlikle gerekmedikçe tarihi yeniden yazmayın. Hayatım boyunca (sahte) doğrusal bir tarih arayışını anlayamıyorum
  • Dalları temizlememek iyidir. Her repo ne tutmak istediğini biliyor. Git'in efendi-köle ilişkileri kavramı yoktur.

13
Katılıyorum. Doğasında zararlı hiçbir şey yok git pull. Ancak, tarihi kesinlikle gerekli olandan daha fazla yeniden yazmak istemek gibi bazı zararlı uygulamalarla çelişebilir. Ancak git esnektir, bu yüzden farklı bir şekilde kullanmak istiyorsanız, kesinlikle yapın. Ama bunun nedeni, siz (iyi, @Richard Hansen) git'te olağandışı bir şey yapmak istediğiniz ve git pullzararlı olduğu için değil .
mcv

28
Daha fazla anlaşamadım. İnsanlar savunuyor git rebaseve dikkate git pullzararlı? Gerçekten mi?
Victor Moroz

10
Birinin ekseni olarak ahlakı olan bir grafik oluşturduğunu görmek ve git komutlarını iyi, kötü veya aradaki bir yerde olarak sınıflandırmak güzel olurdu. Bu grafik geliştiriciler arasında farklılık gösterir, ancak bir kullanım hakkında çok şey söyler git.
michaelt

5
Opsiyon git pullolmadan benim sorun --rebaseoluşturduğu birleştirme yönüdür. Farka baktığınızda, bu birleşmedeki tüm değişiklikler, değişiklikleri yapan kişiden ziyade, çeken kişiye aittir. Birleştirme işleminin iki ayrı dal (A -> B) için ayrıldığı bir iş akışını seviyorum. )
Craig Kochis

4
Öyleyse, bir başkasının ya da başka bir yoldan sadece birkaç saniye önce çekip çekmediğini bilmek size ne kazandırır? Bunun sadece gürültü olduğunu ve gerçekten ilgili tarihi gizlediğini düşünüyorum. Bu, tarihin değerini bile azaltır. İyi bir tarih a) temiz olmalı ve b) aslında önemli bir geçmişe sahip olmalıdır.
David Ongaro

26

Git'i doğru kullanırsanız zararlı değildir. Kullanım durumunuz göz önüne alındığında sizi nasıl olumsuz etkilediğini görüyorum, ancak paylaşılan geçmişi değiştirmeyerek sorunları önleyebilirsiniz.


10
Bunun üzerinde durmak gerekirse: Herkes kendi dalında çalışırsa (bence git'i kullanmanın doğru yolu git pullbudur ), herhangi bir sorun değildir. Git'te dallanma ucuz.
AlexQueue

18

Kabul edilen cevap talepleri

Rebase-pull işlemi, birleştirmeleri korumak için yapılandırılamaz

ancak bu yanıtı gönderen Git 1.8.5'ten itibaren ,

git pull --rebase=preserve

veya

git config --global pull.rebase preserve

veya

git config branch.<name>.rebase preserve

dokümanlar demek

Ne zaman preserve,da geçer --preserve-mergesyerel taahhüt birleştirme kaydedilmesini 'git çekme' çalıştırarak düzleşmiş olmayacak şekilde 'git rebase' yanında.

Bu önceki tartışma daha ayrıntılı bilgi ve diyagramlara sahiptir: git pull --rebase --preserve-merges . Ayrıca neden git pull --rebase=preservedoğru olmadığını açıklıyor git pull --rebase --preserve-merges, bu da doğru olanı yapmıyor.

Bu önceki tartışma, rebase'nin koru-birleştirme varyantının gerçekte ne yaptığını ve bunun normal bir rebase'den çok daha karmaşık olduğunu açıklar: git'in "rebase --preserve-merges" i tam olarak ne yapar (ve neden?)


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.