git merge
Scalanie w Git umożliwia ponowne połączenie podzielonej historii. Polecenie git merge
pozwala zebrać niezależne linie prac programistycznych utworzone za pomocą polecenia git branch
i zintegrować je w pojedynczą gałąź.
Należy zwrócić uwagę, że wszystkie przedstawione poniżej polecenia powodują scalenie z bieżącą gałęzią. Bieżąca gałąź zostanie zaktualizowana, aby odzwierciedlić operację scalenia, ale gałąź docelowa pozostanie całkowicie nienaruszona. Oznacza to, że polecenie git merge
jest często stosowane w połączeniu z poleceniem git checkout
, które pozwala wybrać bieżącą gałąź, oraz poleceniem git branch -d
, które umożliwia usunięcie przestarzałej gałęzi docelowej.
Jak to działa
Polecenie git merge
powoduje połączenie wielu sekwencji commitów w pojedynczą ujednoliconą historię. Najczęściej polecenie git merge
wykorzystuje się do łączenia dwóch gałęzi. Przykłady przedstawione w dalszej części niniejszego dokumentu koncentrują się na tym wzorcu scalania gałęzi. W tych scenariuszach polecenie git merge
wykorzystuje dwa wskaźniki commitów, zazwyczaj końcówki gałęzi, i wyszukuje ich wspólny commit bazowy. Gdy Git znajdzie wspólny commit bazowy, utworzy nowy „commit scalenia”, który obejmuje połączone zmiany z poszczególnych dodanych do kolejki sekwencji commitów scalenia.
Załóżmy, że mamy gałąź nowej funkcji wychodzącą z gałęzi main
. Teraz chcemy scalić tę gałąź funkcji z gałęzią main
.
materiały pokrewne
Zaawansowany dziennik Git
POZNAJ ROZWIĄZANIE
Poznaj środowisko Git z rozwiązaniem Bitbucket Cloud
Wywołanie tego polecenia spowoduje scalenie wskazanej gałęzi funkcji z bieżącą gałęzią, którą w założeniu jest gałąź main
. Git określi algorytm scalania automatycznie (to zagadnienie omówiono poniżej).
Commity scalenia różnią się od innych commitów tym, że mają dwa commity nadrzędne. Podczas tworzenia commita scalenia Git spróbuje w automatycznie magiczny sposób scalić dla Ciebie odrębne historie. Jeśli napotka fragment danych, który został zmieniony w obu historiach, nie będzie w stanie połączyć ich automatycznie. Taki scenariusz oznacza konflikt kontroli wersji i kontynuowanie procesu w Git będzie wymagać interwencji ze strony użytkownika.
Przygotowanie do scalenia
Aby scalenie przebiegło bez problemów, przed rozpoczęciem należy wykonać kilka kroków przygotowawczych.
Potwierdzanie gałęzi odbiorczej
Wykonaj polecenie git status
, aby się upewnić, że wskaźnik HEAD
wskazuje prawidłową gałąź odbiorczą operacji scalania. W razie potrzeby wykonaj polecenie git checkout
, aby przełączyć się na gałąź odbiorczą. W naszym przypadku będzie to polecenie git checkout main
.
Pobieranie najnowszych commitów zdalnych
Upewnij się, że gałąź odbiorcza i scalana zostały zaktualizowane o najnowsze zmiany zdalne. Wykonaj polecenie git fetch
, aby pobrać najnowsze zdalne commity. Po zakończeniu pobierania upewnij się, że gałąź main
zawiera najnowsze aktualizacje, wykonując polecenie git pull
.
Scalanie
Po wykonaniu opisanych wcześniej kroków w ramach „przygotowania do scalenia” można zainicjować scalanie, wykonując polecenie git merge
, w którym fragment
oznacza nazwę gałęzi, która zostanie scalona z gałęzią odbiorczą.
Scalanie z przewijaniem
Scalanie z przewijaniem może wystąpić, gdy między końcówką bieżącej gałęzi a gałęzią docelową istnieje ścieżka liniowa. Zamiast „faktycznego” scalenia gałęzi, Git po prostu integruje historie, przenosząc (lub inaczej „przewijając”) końcówkę bieżącej gałęzi do końcówki gałęzi docelowej. W ten sposób można skutecznie połączyć historie, ponieważ wszystkie commity osiągalne z poziomu gałęzi docelowej są teraz dostępne za pośrednictwem gałęzi bieżącej. Przykładowo scalenie z przewijaniem gałęzi jakiejś funkcji „some-feature” z gałęzią main
będzie wyglądało mniej więcej następująco:
Scalanie z przewijaniem nie jest jednak możliwe, jeśli gałęzie zostały rozdzielone. Jeśli nie ma ścieżki liniowej wiodącej do gałęzi docelowej, Git nie ma innego wyboru, jak połączyć gałęzie w wyniku scalania trójstronnego. W scalaniu trójstronnym łączy się ze sobą dwie historie za pomocą specjalnego commita. Przyjęta nazwa wynika z faktu, że Git generuje commit scalenia na podstawie trzech commitów: dwóch końcówek gałęzi i ich wspólnego elementu nadrzędnego.
Pomimo możliwości użycia dowolnej z tych strategii scalania, wielu programistów woli używać scalenia fast-forward (które ułatwia operacja zmiany bazy) w przypadku niewielkich funkcji lub poprawek błędów, zachowując scalenia trójstronne na potrzeby integracji funkcji, nad którymi prace trwają dłużej. W tym drugim przypadku wynikowy commit scalenia pełni funkcję symbolicznego połączenia dwóch gałęzi.
Nasz pierwszy przykład ilustruje scalanie z przewijaniem. Poniższy kod tworzy nową gałąź, dodaje do niej dwa commity, a następnie integruje ją z linią główną za pomocą operacji scalania z przewijaniem.
# Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Merge in the new-feature branch
git checkout main
git merge new-feature
git branch -d new-feature
Jest to przepływ pracy stosowany powszechnie w odniesieniu do krótkich gałęzi tematycznych, które są wykorzystywane raczej do prowadzenia odizolowanych prac programistycznych niż jako narzędzie organizacyjne dla dłużej rozwijanych funkcji.
Należy również pamiętać, że Git nie powinien zwracać błędów w odpowiedzi na polecenie git branch -d
, ponieważ nowa funkcja „new-feature” jest teraz dostępna z poziomu głównej gałęzi.
Jeśli podczas scalania z przewijaniem jest wymagane utworzenie commita scalenia dla celów ewidencyjnych, można użyć polecenia git merge
z opcją --no-ff
.
git merge --no-ff <branch>
To polecenie powoduje scalenie konkretnej gałęzi z gałęzią bieżącą, ale zawsze generuje commit scalenia (nawet w przypadku scalania z przewijaniem). Jest to przydatny sposób dokumentowania wszystkich scaleń występujących w repozytorium.
Scalanie trójstronne
Kolejny przykład jest bardzo podobny, ale wymaga scalania trójstronnego, ponieważ gałąź main
jest rozwijana, gdy prace nad funkcją są w toku. Jest to typowy scenariusz w przypadku dużych funkcji lub w sytuacji, gdy kilku programistów pracuje nad projektem jednocześnie.
Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Develop the main branch
git checkout main
# Edit some files
git add <file>
git commit -m "Make some super-stable changes to main"
# Merge in the new-feature branch
git merge new-feature
git branch -d new-feature
Należy zwrócić uwagę, że Git nie jest w stanie wykonać scalania z przewijaniem, ponieważ nie da się przenieść gałęzi main
w górę do gałęzi new-feature
bez cofania (backtracking).
W przypadku większości przepływów pracy gałąź new-feature
byłaby znacznie większą funkcją, której opracowanie trwałoby dłuższy czas, i dlatego w międzyczasie w gałęzi main
pojawiłyby się commity. Gdyby gałąź funkcji faktycznie była tak mała, jak w powyższym przykładzie, prawdopodobnie lepszym rozwiązaniem byłoby połączenie jej z gałęzią main
za pomocą operacji zmiany bazy, a następnie wykonanie scalania z przewijaniem. Pozwoliłoby to uniknąć zaśmiecania historii projektu niepotrzebnymi commitami scalenia.
Rozwiązywanie konfliktu
Jeśli w dwóch gałęziach, które próbujesz scalić, zmieniono tę samą część tego samego pliku, Git nie będzie w stanie określić, której wersji powinien użyć. W takim przypadku zatrzyma operację tuż przed commitem scalenia, umożliwiając ręczne rozwiązanie konfliktów.
Fantastyczną cechą procesu scalania w Git jest stosowanie znanego przepływu pracy opartego na schemacie edycja / umieszczenie w przechowalni / zatwierdzenie do rozwiązywania konfliktów scalania. W razie napotkania konfliktu scalania wykonanie polecenia git status
pozwoli wyświetlić pliki wymagające rozwiązania. Przykładowo, jeśli w obydwu gałęziach zmodyfikowano tę samą sekcję hello.py
,wyświetlony komunikat powinien być zbliżony do następującego:
On branch main
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py
Sposób przedstawiania konfliktów
Jeśli Git napotka konflikt w trakcie scalania, przejdzie do edycji zawartości problematycznych plików, stosując wskaźniki wizualne do oznaczenia sprzecznej zawartości po obu stronach. Znaczniki wizualne są następujące: <<<<<<<, ======= i >>>>>>>. W trakcie scalania dobrze jest wyszukać te wskaźniki w projekcie, aby sprawdzić, gdzie występują konflikty wymagające rozwiązania.
here is some content not affected by the conflict
<<<<<<< main
this is conflicted text from main
=======
this is conflicted text from feature branch
>>>>>>> feature branch;
Zasadniczo zawartość poprzedzająca znacznik =======
pochodzi z gałęzi odbiorczej, a zawartość następująca po tym znaczniku — z gałęzi scalanej.
Po zidentyfikowaniu powodujących konflikt sekcji można do nich przejść i naprawić scalenie według własnego uznania. Gdy wszystko będzie gotowe do zakończenia scalania, wystarczy uruchomić polecenie git add
na plikach, w których wystąpił konflikt, aby poinformować Git, że problem został rozwiązany. Następnie należy uruchomić standardowe polecenie git commit
, aby wygenerować commit scalenia. To dokładnie ta sama procedura, którą wykonuje się w trakcie zatwierdzania zwykłych migawek, co oznacza, że zwykli programiści mogą z łatwością zarządzać własnymi scaleniami.
Należy pamiętać, że konflikty scalania będą występowały wyłącznie w przypadku scalania trójstronnego. Sprzeczne zmiany nie pojawiają się w przypadku scalania z przewijaniem.
Podsumowanie
Ten dokument zawiera omówienie polecenia git merge
. Scalanie jest podstawowym procesem stosowanym podczas pracy w Git. Opisano mechanikę wewnętrzną leżącą u podstaw scalenia oraz różnice między scalaniem fast-forward i prawdziwym scalaniem trójstronnym. Najważniejsze wnioski:
1. Scalanie w Git polega na łączeniu sekwencji commitów w pojedynczą, ujednoliconą historię commitów.
2. W Git istnieją dwa główne sposoby scalania: fast-forward i trójstronne.
3. Git scala commity automatycznie, chyba że w obydwu sekwencjach commitów występują sprzeczne zmiany.
W tym dokumencie uwzględniono, bezpośrednio lub przez odwołanie, także inne polecenia Git, takie jak: git branch, git pull i git fetch. Więcej informacji na ich temat można znaleźć na poświęconych im osobnych stronach.
Udostępnij ten artykuł
Następny temat
Zalecane lektury
Dodaj te zasoby do zakładek, aby dowiedzieć się więcej na temat rodzajów zespołów DevOps lub otrzymywać aktualności na temat metodyki DevOps w Atlassian.