Kurs Git - Konflikt w trakcie scalania

Opisywane przez nas do tej pory scenariusze scalania kodu były stosunkowo proste, gdyż właściwie nie wymagały od nas podejmowania żadnych decyzji. Musieliśmy jedynie wykonywać kolejne komendy w zależności od zaistniałej sytuacji. Teraz przyszedł czas na to, aby zająć się nieco bardziej skomplikowanym przypadkiem polegającym na rozwiązywaniu konfliktu występującego w trakcie merge'a.

Manualne mergowanie

Przeanalizujmy scenariusz, w którym mamy dwóch programistów pracujących nad tym samym kodem. Załóżmy, że programista numer 1 to nasz kolega pracujący w zespole, a programistą numer 2 jesteśmy my.
  • Programista 1 tworzy nowego brancha (np. feature/Change-list-to-set) po to by zmodyfikować typ zwracanej wartości w metodzie read w pliku UserService.java. Jak pamiętamy z rozdziału Git - Tworzenie gałęzi (branchy) metoda zwracała listę. Teraz ma zwracać Seta.
    public interface UserService {
    
        void create();
        
        Set<User> read();
        
        void update();
        
        void delete();
    }
    
  • Programista 2 tworzy nowego brancha (np. feature/Change-list-to-sorted-set) również po to by zmodyfikować typ zwracanej wartości w metodzie read w pliku UserService.java. Też chciałby zwracać tutaj zbiór, ale dodatkowo uznał, że lepiej by ten zbiór był posortowany. Tak więc od teraz, według kodu tego brancha, metoda będzie zwracać SortedSet.
    public interface UserService {
    
        void create();
        
        SortedSet<User> read();
        
        void update();
        
        void delete();
    }
    
  • Programista 1 merguje swoje zmiany do lokalnego brancha master, a następnie pushuje te zmiany do zdalnego repozytorium. Tym samym obecnie na zdalnym branchu master metoda read zwraca interfejs Set.
  • Programista 2 przełącza się na lokalnego brancha master i pobiera zmiany z jego zdalnego odpowiednika, po czym uruchamia komendę merge. W tym momencie okazuje się, że zamiast oczekiwanego scalenia w postaci recursive merge programista otrzymuje informację o konflikcie:
    ...
    CONFLICT (content): Merge conflict in UserService.java
    Automatic merge failed; fix conflicts and then commit the result
    
    
  • Programista 2 musi się więc dowiedzieć co jest przyczyną jego problemów. W tym celu uruchamia komendę:
    git status
    
    W rezultacie otrzymuje informacje o plikach, których nie udało się automatycznie zmergować:
    
    ...
    # both modified:    UserService.java
    
    
    W takim przypadku programista musi wyedytować taki problematyczny plik i zmienić go ręcznie. Wchodząc do pliku można łatwo odnaleźć miejsca, w których nie powiodło się wykonanie automatycznego merge'a. Wygląda to tak:
    public interface UserService {
    
        void create();
        
        <<<<<<<
        SortedSet<User> read(); 
        =======
        Set<User> read();
        >>>>>>>
        8a2adsad078s8d7s6445a4sad09878767s....
        
        void update();
        
        void delete();
    }
    
    W pliku programista znajduje charakterystycznie oznaczone bloki kodu. Pierwszy z nich należy do programisty 2 (tego, który teraz próbuje mergować), a drugi do programisty 1 (tego, który zmergował już wcześniej). Rozwiązanie konfliktu polega na podjęciu decyzji, która wersja kodu ma pozostać (w naszym przypadku jest to tylko jedna linia kodu, ale zmiana może dotyczyć także wielu linii) oraz na manualnym usunięciu kodu, który według wiedzy programisty 2 jest starszy i już nieaktualny.

    Tak więc programista numer 2 wybiera swoje zmiany jako te finalne gdyż wie, że obecne wymagania są takie, iż metoda read ma nie tylko zwracać zbiór zamiast listy, ale też że ten zbiór ma być dodatkowo posortowany. Programista usuwa też dodatkowe oznaczenia <<<...,>>>... itp.
  • Programista 2 komituje zmiany bez podawania dodatkowych informacji o komicie. Git sam przygotuje stosowny komunikat, który będzie zawierał dane o konfliktach oraz o tym, że zostały one rozwiązane.
    git commit -a
    
    Komunikat ten zostanie wyświetlony w domyślnym edytorze. Na tym etapie, jeśli w dalszym ciągu programista chce coś zmienić w przygotowanej informacji, nadal może to zrobić. Wystarczy, ze wyedytuje zawartość wyświetlonej informacji. Na końcu, niezależnie od tego czy coś zmieniał czy nie, plik musi zostać zapisany, tak aby cały proces zakończył się sukcesem.
  • Programista 2 wypycha zmiany do zdalnego repozytorium, które od teraz zawiera manualnie zmergowany przez niego kod.
    git push 
    
Zdjęcie autora
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy: stackshare
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .


Pozycjonowanie stron: Grupa TENSE