Close

Konflikty scalania w Git

W systemach kontroli wersji chodzi o zarządzanie wynikami prac wielu rozproszonych autorów (zazwyczaj programistów). Czasami wielu programistów może podjąć próbę edytowania tej samej zawartości. Jeśli programista A próbuje edytować kod edytowany przez programistę B, może wystąpić konflikt. Aby ograniczyć występowanie konfliktów, programiści pracują w odrębnych, odizolowanych gałęziach. Podstawową funkcją polecenia git merge jest łączenie odrębnych gałęzi i rozwiązywanie wszelkich sprzecznych zmian.


Informacje na temat konfliktów scalania


Konflikty zazwyczaj pojawiają się, gdy dwie osoby zmienią te same wiersze w pliku lub gdy jeden programista usunie plik modyfikowany przez innego programistę. W takich przypadkach Git nie jest w stanie automatycznie wskazać poprawnej wersji. Konflikty dotyczą wyłącznie programisty, który przeprowadza operację scalania, a reszta zespołu nie jest ich świadoma. Git oznaczy plik jako źródło konfliktu i wstrzyma proces scalania. Wówczas to programista będzie musiał rozwiązać konflikt.

Rodzaje konfliktów scalania


Konflikt w trakcie scalania może wystąpić na dwóch różnych etapach: podczas uruchamiania procesu scalania i w trakcie jego realizacji. Poniżej omówiono sposoby postępowania w przypadku każdego z tych scenariuszy.

Niepowodzenie podczas uruchamiania scalania w Git

Rozpoczęcie scalania w Git będzie niemożliwe, jeśli w katalogu roboczym lub przechowalni bieżącego projektu znajdują się zmiany. Git nie uruchomi scalania, ponieważ te oczekujące zmiany mogłyby zostać nadpisane scalanymi commitami. W takim przypadku przyczyną nie jest konflikt z pracą innych programistów, tylko z oczekującymi zmianami lokalnymi. Wówczas należy ustabilizować stan lokalny za pomocą polecenia git stash, git checkout, git commit lub git reset. Niepowodzenie przy próbie rozpoczęcia scalania spowoduje wyświetlenie następującego komunikatu o błędzie:

error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory)

Niepowodzenie w trakcie scalania w Git

Niepowodzenie W TRAKCIE scalania wskazuje na konflikt między bieżącą gałęzią lokalną a gałęzią scalaną. Oznacza to konflikt z kodem innych programistów. Git postara się jak najlepiej scalić pliki, pozostawiając jednak zmiany w plikach powodujących konflikt do ręcznego rozwiązania. Niepowodzenie w trakcie scalania spowoduje wyświetlenie następującego komunikatu o błędzie:

Okno konsoli
materiały pokrewne

Zaawansowany dziennik Git

Logo Bitbucket
POZNAJ ROZWIĄZANIE

Poznaj środowisko Git z rozwiązaniem Bitbucket Cloud

error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)

Wywoływanie konfliktu scalania


Aby zapoznać się z konfliktami scalania w rzeczywistej sytuacji, w kolejnej sekcji zostanie utworzona symulacja konfliktu do późniejszego przeanalizowania i rozwiązania. W przykładzie do wykonania przykładowej symulacji zostanie użyty interfejs wiersza poleceń Git, który jest podobny do tego w systemie Unix.

$ mkdir git-merge-test
$ cd git-merge-test
$ git init .
$ echo "this is some content to mess with" > merge.txt
$ git add merge.txt
$ git commit -am"we are commiting the inital content"
[main (root-commit) d48e74c] we are commiting the inital content
1 file changed, 1 insertion(+)
create mode 100644 merge.txt

Ten przykładowy kod wykonuje sekwencję poleceń pozwalających przeprowadzić następujące operacje:

  • Utworzenie nowego katalogu o nazwie git-merge-test, przejście do tego katalogu i zainicjowanie go jako nowego repozytorium Git.
  • Utworzenie nowego pliku tekstowego merge.txt z pewną zawartością.
  • Dodanie pliku merge.txt do repozytorium i zatwierdzenie go.

W ten sposób otrzymaliśmy nowe repozytorium zawierające jedną gałąź main oraz plik merge.txt z pewną zawartością. Następnie utworzymy nową gałąź, którą wykorzystamy do wywołania konfliktu scalania.

$ git checkout -b new_branch_to_merge_later
$ echo "totally different content to merge later" > merge.txt
$ git commit -am"edited the content of merge.txt to cause a conflict"
[new_branch_to_merge_later 6282319] edited the content of merge.txt to cause a conflict
1 file changed, 1 insertion(+), 1 deletion(-)

Sekwencja powyższego polecenia spowodowała przeprowadzenie następujących operacji:

  • Utworzenie i wyewidencjonowanie nowej gałęzi o nazwie new_branch_to_merge_later.
  • Zastąpienie zawartości w pliku merge.txt.
  • Zatwierdzenie nowej zawartości.

W tej nowej gałęzi new_branch_to_merge_later utworzyliśmy commit, który zastępuje zawartość pliku merge.txt.

git checkout main
Switched to branch 'main'
echo "content to append" >> merge.txt
git commit -am"appended content to merge.txt"
[main 24fbe3c] appended content to merge.tx
1 file changed, 1 insertion(+)

Ten łańcuch poleceń powoduje wyewidencjonowanie gałęzi main, dołączenie zawartości do pliku merge.txt i zatwierdzenie go. W ten sposób w naszym przykładowym repozytorium znajdują się 2 nowe commity. Jeden w gałęzi main i jeden w gałęzi new_branch_to_merge_later. Wykonajmy zatem polecenie git merge new_branch_to_merge_later i zobaczmy, co się stanie.

$ git merge new_branch_to_merge_later
Auto-merging merge.txt
CONFLICT (content): Merge conflict in merge.txt
Automatic merge failed; fix conflicts and then commit the result.

BUM 💥. Wystąpił konflikt. Dzięki, Git, że dałeś nam o nim znać!

Identyfikowanie przyczyn konfliktów scalania


Jak można było zobaczyć w poprzednim przykładzie, Git wygeneruje opisowy komunikat informujący o wystąpieniu konfliktu. Aby uzyskać więcej szczegółów, możemy wykonać polecenie git status.

$ git status
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)

Unmerged paths:
(use "git add <file>..." to mark resolution)

both modified:   merge.txt

Dane wyjściowe uzyskane po wykonaniu polecenia git status wskazują, że w wyniku konfliktu powstały niescalone ścieżki. Plik merge.text jest teraz wyświetlany w stanie zmodyfikowanym. Przyjrzyjmy się zatem plikowi i zobaczmy, co zostało zmodyfikowane.

$ cat merge.txt
<<<<<<< HEAD
this is some content to mess with
content to append
=======
totally different content to merge later
>>>>>>> new_branch_to_merge_later

Użyliśmy tutaj polecenia cat, aby wyświetlić zawartość pliku merge.txt. Pojawiło się kilka nowych, dziwnych dodatków.

  • <<<<<<< HEAD
  • =======
  • >>>>>>> new_branch_to_merge_later

Potraktujmy te nowe wiersze jako „linie podziału konfliktu”. Wiersz ======= stanowi „centrum” konfliktu. Cała zawartość umieszczona między centrum a wierszem <<<<<<< HEAD to zawartość, która występuje w bieżącej gałęzi głównej, na którą wskazuje wskaźnik HEAD. Z kolei cała zawartość między centrum a wierszem >>>>>>> new_branch_to_merge_later to zawartość, która występuje w naszej scalanej gałęzi.

Rozwiązywanie konfliktów scalania za pomocą wiersza polecenia


Najbardziej bezpośrednim sposobem rozwiązania konfliktu scalania jest wprowadzenie zmian w pliku powodującym konflikt. Otwórz plik merge.txt w ulubionym edytorze. Na potrzeby naszego przykładu usuńmy po prostu wszystkie linie podziału konfliktu. Zmodyfikowana zawartość pliku merge.txt powinna wyglądać następująco:

this is some content to mess with
content to append
totally different content to merge later

Po wprowadzeniu zmian w pliku wykonaj polecenie git add merge.txt, aby umieścić nowo scaloną zawartość w przechowalni. Aby sfinalizować scalanie, utwórz nowy commit, wykonując polecenie:

git commit -m "merged and resolved the conflict in merge.txt"

Git zobaczy, że konflikt został rozwiązany i utworzy nowy commit scalenia, aby sfinalizować scalanie.

Polecenia Git ułatwiające rozwiązywanie konfliktów scalania


Narzędzia ogólne

git status

Pracując w Git, często używa się polecenia „status”, które w przypadku scalania ułatwia identyfikację plików powodujących konflikt.

git log --merge

Przekazanie argumentu --merge do polecenia git log spowoduje utworzenie dziennika zawierającego listę commitów, które powodują konflikt między scalanymi gałęziami.

git diff

Polecenie diff pomaga odszukać różnice między stanami repozytorium/plików. Jest to przydatne przy przewidywaniu konfliktów scalania i zapobieganiu ich występowania.

Narzędzia przydatne, gdy Git nie może rozpocząć scalania

git checkout

Za pomocą polecenia checkout można cofnąć zmiany w plikach lub zmienić gałęzie.

git reset --mixed

Polecenie reset pozwala cofnąć zmiany w katalogu roboczym i przechowalni.

Narzędzia przydatne przy rozwiązywaniu konfliktów Git w trakcie scalania

git merge --abort

Wykonanie polecenia git merge z opcją --abort zakończy proces scalania i przywróci gałąź do stanu przed rozpoczęciem procesu scalania.

git reset

Polecenia git reset można użyć w przypadku konfliktu scalania do zresetowania powodujących konflikt plików do znanego, prawidłowego stanu.

Podsumowanie


Konflikty scalania bywają trudnym doświadczeniem. Na szczęście Git oferuje zaawansowane narzędzia ułatwiające identyfikowanie i rozwiązywanie konfliktów. Git jest w stanie poradzić sobie samodzielnie z większością przypadków scalania, wykorzystując funkcje automatycznego scalania. Konflikt powstaje, gdy jeden wiersz w pliku został zmodyfikowany z poziomu dwóch różnych gałęzi lub gdy plik został usunięty z jednej gałęzi, ale edytowano go w drugiej. Konflikty występują najczęściej podczas pracy w środowisku zespołowym.

Istnieje wiele narzędzi ułatwiających rozwiązywanie konfliktów scalania. Git zapewnia wiele narzędzi wiersza polecenia, które tutaj omówiliśmy. Szczegółowe informacje na temat tych narzędzi można znaleźć na osobnych stronach dotyczących poleceń git log, git reset, git status, git checkout i git reset. Oprócz narzędzi dostępnych w Git istnieje także wiele rozwiązań innych firm usprawniających obsługę konfliktów scalania.


Udostępnij ten artykuł

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.

Ludzie współpracujący przy ścianie pełnej narzędzi

Blog Bitbucket

Ilustracja DevOps

Ścieżka szkoleniowa DevOps

Demonstracje funkcji z ekspertami Atlassian

Zobacz, jak Bitbucket Cloud współpracuje z Atlassian Open DevOps

Zapisz się do newslettera DevOps

Thank you for signing up