Birden Çok İşlemi Göndermeden Önce Birinde Birleştirme


134

Bu soru yalnızca bu görevin nasıl gerçekleştirileceğiyle değil, bunu yapmanın Git ile iyi veya kötü bir uygulama olup olmadığı ile ilgilidir.

Yerel olarak ana dalda işlerin çoğunu yaptığımı düşünün, ancak "topical_xFeature" adını vereceğim bir topikal dal oluşturdum. "Topical_xFeature" üzerinde çalışma ve ana dalda başka işler yapmak için ileri geri geçiş sürecinde, "topical_xFeature" dalında birden fazla işlem yaptığım ortaya çıktı, ancak her kaydetme arasında it.

Öncelikle , bu kötü uygulamayı düşünür müsün? İtme başına dal başına bir işleme bağlı kalmak daha akıllıca olmaz mı? Hangi durumlarda, bir itme yapılmadan önce bir şubede birden fazla işlemin olması iyi olur?

İkincisi , topical_xFeature dalındaki çoklu işlemleri bir itme için ana dala getirmeyi en iyi nasıl başarabilirim? Bunun için endişelenmemek ve birden fazla işlemin zorlandığı durumlarda baskı yapmak bir sıkıntı mı yoksa taahhütleri bir şekilde birleştirip sonra itmek daha az can sıkıcı mı? Yine, bunu nasıl yapmalı?

Yanıtlar:


142

İlk sorunuz için, hayır, aynı anda birden fazla kaydı zorlamakta yanlış bir şey yok. Çoğu zaman, çalışmanızı birkaç küçük, mantıklı çalışmaya bölmek isteyebilirsiniz, ancak bunları yalnızca tüm serinin hazır olduğunu hissettiğinizde yukarı itin. Veya bağlantınız yokken yerel olarak birkaç işlem yapıyor olabilirsiniz ve tekrar bağlandığınızda hepsini zorluyorsunuz. Kendinizi itme başına bir işlemle sınırlamanıza gerek yok.

Genelde, her bir taahhüdü tek, mantıklı, tutarlı bir değişiklik olarak tutmanın iyi bir fikir olduğunu düşünüyorum, bu da çalışması gereken her şeyi içerir (bu nedenle kodunuzu bozuk bir durumda bırakmaz). İki kaydetmeniz varsa, ancak yalnızca ilkini uygularsanız kodun kırılmasına neden olacaksa, ikinci kesinlemeyi birinciye sıkıştırmak iyi bir fikir olabilir. Ancak, her birinin makul bir değişiklik yaptığı iki taahhüdünüz varsa, bunları ayrı taahhütler olarak itmek iyidir.

Birkaç işlemi bir arada ezmek istiyorsanız, kullanabilirsiniz git rebase -i. Dalda iseniz topical_xFeature, koşarsınız git rebase -i master. Bu, önek olarak listelenmiş bir grup kaydetme ile bir düzenleyici penceresi açacaktır pick. İlki dışında hepsini değiştirebilirsiniz squash, bu da Git'e tüm bu değişiklikleri saklamasını söyler, ancak onları ilk işlemede ezin. Bunu yaptıktan sonra master, özellik dalınızı kontrol edin ve birleştirin:

git checkout topical_xFeature
git rebase -i master
git checkout master
git merge topical_xFeature

Alternatif olarak, her şeyi topical_xFeatureiçine sıkıştırmak istiyorsanız master, aşağıdakileri yapabilirsiniz:

git checkout master
git merge --squash topical_xFeature
git commit

Hangisini seçeceğiniz size kalmış. Genel olarak, birden fazla küçük kaydetme konusunda endişelenmem, ancak bazen fazladan küçük kaydetmelerle uğraşmak istemezsiniz, bu yüzden onları bire sıkıştırırsınız.


1
--Squash ile birleştirdikten sonra, konu dalını ile silemiyorum git branch -d topic. Git neden tüm değişikliklerin birleştirildiğini belirleyemiyor?
balki

7
@balki Çünkü Git, yamaların belirli dalın geçmişinde görünüp görünmediklerine bağlı olarak birleştirilip birleştirilmediğini algılar. Squashing onları değiştirir; yeni bir commit haline gelirler ve bu yeni commit diğerleriyle aynı şeyi yaparken Git bunu söyleyemez, sadece aynı commit ID'sine (SHA-1) sahiplerse commit'lerin aynı olup olmadığını söyleyebilir. . Yani onu ezdikten sonra git'e eski şubeyi git branch -D topiczorla silmek için silmesini söylemelisin .
Brian Campbell

67

Kodu itmeden önce birden çok İşlemi tek bir işlemde birleştirmek için genel olarak izlediğim yol budur.

Bunu başarmak için GIT tarafından sağlanan ' squash ' konseptini kullanmanızı öneririm .

Aşağıdaki adımları izleyin.

1) git Rebase -i ana (yerine ana de belirli bir kullanım için işlemek)

Tüm taahhütlerinizi göstereceği rebase etkileşimli düzenleyiciyi açın. Temel olarak, tek bir işlemde birleştirmek istediğiniz taahhütleri belirlemeniz gereken yer.

Bunların sizin taahhütleriniz olduğunu ve editörde buna benzer bir şey gösterdiğini hayal edin.

pick f7f3f6d changed my name a bit    
pick 310154e updated README formatting and added blame   
pick a5f4a0d added cat-file  

Bu işlemlerin normalde log komutunu kullanırken gördüğünüzün tersi sırada listelendiğini unutmamak önemlidir. Yani, eski kayıt ilk önce gösterilecek.

2) Son taahhüt edilen değişiklikler için "seç" i "squash" olarak değiştirin. aşağıda gösterildiği gibi bir şey. Bunu yaptığınızda, son 2 kaydetmeniz birincisi ile birleştirilecektir.

pick f7f3f6d changed my name a bit         
squash 310154e updated README formatting and added blame   
squash a5f4a0d added cat-file

Birleştirecek çok fazla taahhüdünüz varsa kısa formu da kullanabilirsiniz:

p f7f3f6d changed my name a bit         
s 310154e updated README formatting and added blame   
s a5f4a0d added cat-file

düzenleme için 'i' kullanın, düzenleyicinin yerleştirilmesini sağlar. En üstteki (en eski) işlemenin, birleştirilecek önceki bir işlem olmadığı için ezilemeyeceğini unutmayın. Bu yüzden "p" seçilmesi gerekiyor. Ekleme modundan çıkmak için 'Esc'yi kullanın.

3) Şimdi, aşağıdaki komutla editörü kaydedin . : wq

Bunu kaydettiğinizde, önceki üç kaydetmenin tümünün değişikliklerini tanıtan tek bir kaydınız olur.

Umarım bu sana yardımcı olur.


5
Belki bu başkaları için açıktır, ancak "git rebase -i" dediğinizde, hangi commit'den başlayacağınızı da belirtmeniz gerekir. Bu, bu örneği izlemeyi denediğimde fark etmediğim bir şeydi. Dolayısıyla, bu örnekte, "git rebase -i xxxxx" olacaktır; burada xxxxx, kronolojik olarak f7f3f6d'den hemen önceki kaydetmedir. Bunu bir kez anladığımda, her şey tam olarak yukarıda anlatıldığı gibi çalıştı.
nukeguy

Bu ilginç @nukeguy, belirli bir commit belirtmeyen herhangi bir sorunum olmadı. Sadece oradayken varsayılan olarak ayarlandı.
JCrooks

Belki @nukeguy gibi, başlamam git rebase -i HEAD~2için faydalı bir yerdi. Sonra bu cevap yardımcı oldu. Sonra, git status"Dalınız ve 'köken / özellik / xyz' birbirinden ayrıldı ve her biri sırasıyla 1 ve 1 farklı kaydetme var." Ben gerekiyordu Yani git push origin feature/xyz --force-with-leasebakın stackoverflow.com/a/59309553/470749 ve freecodecamp.org/forum/t/...
Ryan

11

Birincisi : hiçbir şey, her dalda her dalda yalnızca bir commit olmasını söylemez: bir push, uzak bir depoda yerel bir geçmiş (yani bir işlem koleksiyonu) yayınlamanıza izin veren bir yayın mekanizmasıdır.

İkincisi : a git merge --no-ff topical_xFeature, zorlamadan önce ana konu çalışmanızı tek bir taahhüt olarak kaydeder master.
(Bu şekilde, tutmak topical_xFeaturesize kayıt anlamına ileri evrimlendirilmesinde etrafında masteryeni single sonraki mektup birleştirme no-ff üzerinde taahhüt bir şekilde.
Kurtulmak alan birisi topical_xFeaturehedeftir, daha sonra git merge --squashayrıntılı olarak, doğru seçenektir Brian Campbell bireyin cevabı .)


Bence istediğin bu --squashdeğil --no-ff. --no-ffbir birleştirme taahhüdü oluşturur, ancak aynı zamanda tüm taahhütleri de bırakır topical_xFeature.
Brian Campbell

@Brian: Cevabınıza katılıyorum ve olumlu oy verdim, ancak ilk olarak --no-ff seçeneğini düşündüm çünkü topical_featuredallanmayı sürdürmek ve dalda tek bir taahhüt kaydetmek istedim master.
VonC

8

Ana şubeye geçin ve güncel olduğunuzdan emin olun.

git checkout master

git fetch origin / master ile ilgili güncellemeleri almak için gerekli olabilir (git yapılandırmanıza bağlı olarak)

git pull

Unsur dalını ana dalda birleştirin.

git merge feature_branch

Ana şubeyi başlangıç ​​durumuna sıfırlayın.

git reset origin/master

Git artık tüm değişiklikleri aşamasız değişiklikler olarak kabul ediyor. Bu değişiklikleri tek bir commit olarak ekleyebiliriz. Ekleme . izlenmeyen dosyalar da ekleyecektir.

git add --all

git commit

Referans: https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit


3
bu cevabı takip etmek ve görselleştirmek gerçekten çok kolay.
jokab

6
  1. Önce her şeyin ardından gelmesini istediğiniz taahhüdü seçin.

    git reflog
    5976f2b HEAD@{0}: commit: Fix conflicts
    80e85a1 HEAD@{1}: commit: Add feature
    b860ddb HEAD@{2}: commit: Add something
    
  2. Seçtiğiniz kafaya sıfırlayın (seçtim HEAD@{2})

    git reset b860ddb --soft
    
  3. git status (Sadece emin olmak için)

  4. Yeni kaydetmenizi ekleyin

    git commit -m "Add new commit"
    

Not: HEAD@{0}& HEAD@{1}Artık 1 kayıtla birleştirildi, bu birden fazla kaydetme için de yapılabilir.

git reflog tekrar görüntülenmeli:

git reflog
5976f2b HEAD@{0}: commit: Add new commit
b860ddb HEAD@{1}: commit: Add something

0

Birden Fazla İşlemi Bire Otomatikleştiren Bir Araç

Kondal Kolipaka'nın dediği gibi . "Git rebase -i" kullanma

"Git rebase" mantığı

"Git rebase -i" kullanılırken git, geçerli .git / rebase-merge dizininde git-rebase-todo dosyasını oluşturur ve ardından kullanıcıların işlem için git-rebase-todo dosyasını düzenlemesine izin vermek için git düzenleyicisini çağırır. Bu nedenle aracın aşağıdakileri karşılaması gerekir:

  1. Git düzenleyicisini sağladığımız araca değiştirin;
  2. Araç git-rebase-todo dosyasını işler.

Varsayılan git düzenleyiciyi değiştirin

git config core.editor #show current default git editor
git config --local --replace-all  core.editor NEW_EDITOR # set the local branch using NEW_EDITOR as git editor

Bu nedenle, aracın git düzenleyicisini değiştirmesi ve git-rebase-todo dosyasını işlemesi gerekir. Aşağıdaki python kullanan araç:

#!/usr/bin/env python3
#encoding: UTF-8

import os
import sys

def change_editor(current_file):
    os.system("git config --local --replace-all  core.editor " + current_file) # Set current_file as git editor
    os.system("git rebase -i") # execute the "git rebase -i" and will invoke the python file later with git-rebase-todo file as argument
    os.system("git config --local --replace-all core.editor vim") # after work reset the git editor to default

def rebase_commits(todo_file):
    with open(todo_file, "r+") as f:
        contents = f.read() # read git-rebase-todo's content
        contents = contents.split("\n")
        first_commit = True
        f.truncate()
        f.seek(0)
        for content in contents:
            if content.startswith("pick"):
                if first_commit:
                    first_commit = False
                else:
                    content = content.replace("pick", "squash") # replace the pick to squash except for the first pick
            f.write(content + "\n")

def main(args):
    if len(args) == 2:
        rebase_commits(args[1]) # process the git-rebase-todo
    else:
        change_editor(os.path.abspath(args[0])) # set git editor

if __name__ == "__main__":
    main(sys.argv)

Referans: https://liwugang.github.io/2019/12/30/git_commits_en.html


4
Lütfen web sitesi tanıtımınızı azaltın. Ayrıca bkz . Spam gönderen nasıl olunmaz.
2019
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.