http://uneex.org/LecturesCMC/PythonDevelopment2023/04_MergetoolCommandline
https://youtu.be/uVh3BEL1iyU
Вообще merge commit опасная штука, их плодить не надо т.к. могут быть конфликты, когда редактируется одно и то же место, которое правится вручную при merge commit
Сложное слияние
При merge и rebase могут возникать конфликты: в двух историях изменён один и тот же контекст:
- Создадим заведомо конфликтующий коммиты на двух ветках $ git init
Initialized empty Git repository in /home/george/example/.git/ $ git add . $ git commit -a -m "Initial commit" [master (root-commit) 8ab1be9] Initial commit 1 file changed, 63 insertions(+) create mode 100644 keyword.py $ git branch second $ git branch * master second $ grep -Ev "except|False" /usr/lib64/python3.10/keyword.py > keyword.py $ git diff diff --git a/keyword.py b/keyword.py index cc2b46b..9f30ffb 100644 --- a/keyword.py +++ b/keyword.py @@ -16,7 +16,6 @@ Alternatively, you can run 'make regen-keyword'. __all__ = ["iskeyword", "issoftkeyword", "kwlist", "softkwlist"] kwlist = [ - 'False', 'None', 'True', 'and', @@ -31,7 +30,6 @@ kwlist = [ 'del', 'elif', 'else', - 'except', 'finally', 'for', 'from', $ git commit -a -m "False+except" [master f1fbdeb] False+except 1 file changed, 2 deletions(-) $ git checkout second Switched to branch 'second' $ grep -Ev "finally|yield" /usr/lib64/python3.10/keyword.py > keyword.py $ git diff diff --git a/keyword.py b/keyword.py index cc2b46b..251bd3a 100644 --- a/keyword.py +++ b/keyword.py @@ -32,7 +32,6 @@ kwlist = [ 'elif', 'else', 'except', - 'finally', 'for', 'from', 'global', @@ -50,7 +49,6 @@ kwlist = [ 'try', 'while', 'with', - 'yield' ] softkwlist = [ $ git commit -a -m "finally+yield" [second 0804e39] finally+yield 1 file changed, 2 deletions(-) $ git log --graph --pretty=oneline --abbrev-commit --all * 0804e39 (HEAD -> second) finally+yield | * f1fbdeb (master) False+except |/ * 8ab1be9 Initial commit
Итак, у нас есть три состояния файла keyword.py:
8ab1be9 (общий предок)
f1fbdeb (на ветке master) — без False и except
0804e39 (на ветке second) — без finally и yield
Контекст изменений для except и finally пересекается
- ⇒ при слиянии будут конфликты
- Попробуем объединить:
1 $ git branch 2 master 3 * second 4 $ git merge master 5 Auto-merging keyword.py 6 CONFLICT (content): Merge conflict in keyword.py 7 Automatic merge failed; fix conflicts and then commit the result. 8 $ grep -EC3 "<<<<|====|>>>>" keyword.py 9 'del', 10 'elif', 11 'else', 12 <<<<<<< HEAD 13 'except', 14 ======= 15 'finally', 16 >>>>>>> master 17 'for', 18 'from', 19 'global', 20
Часть изменений применены (про False и про yield), потому что контексты не пересекались, часть (про except и finally) — нет.
- Файл содержит вставки вида:
<<<<<<< HEAD … ======= … >>>>>>> master
- Это т. н. 3-way diff по схеме «общий предок + конфликтующие изменения»
Все неконфликтующие изменения из обеих веток применены
HEAD — это содержимое текущей ветка, master — с чем мержим
было бы неплохо ещё знать, что раньше-то было, но тут не показывается
Все "<<<<<<<", "=======" и ">>>>>>>" надо убрать (и ненужные изменения тоже)
- Получится merge commit с изменением, неравным тому, что делалось на ветках
Если вас удовлетворяют изменения, проделанные на ветке master, можно просто git checkout master keyword.py,
но тогда пропадут все изменения, включая уже применённые.
Когда всё готово, делаем git commit -a:
2 …
3 $ git commit -a
4 [second 6568682] Merge branch 'master' into second
5 $ git log --graph --pretty=oneline --abbrev-commit --all
6 * 6568682 (HEAD -> second) Merge branch 'master' into second
7 |\
8 | * f1fbdeb (master) False+except
9 * | 0804e39 finally+yield
10 |/
11 * 8ab1be9 Initial commit
12
Если в историях больше одного коммита, merge надо продолжить с помощью git merge --continue
Если вы окончательно запутались (особенно в многокоммитных мержах), всё можно откатить назад с помощью git merge --abort
Mergetool
Инструмент, в котором есть
, имеет общее название «merge tool».
Список: git mergetool --tool-help
- Запускается вместо ручного исправления конфликтов
*vimdiff показывает четыре окна:
«Эта» ветка (LOCAL)
Общий предок (BASE)
«Та» ветка (REMOTE)
Файл с конфликтами (его и надо исправлять)
Могут остаться backup-файлы, их надо удалить git clean -f
- Другие утилиты позволяют «накликивать» изменения)
Пример на том же репозитории:
просто удалим merge-коммит (git reset --hard HEAD~)
вызовем git merge
вызовем git merge-tool --tool=gvimdiff (или meld)
:diffget RE " get from REMOTE :diffget BA " get from BASE :diffget LO " get from LOCAL
Для постоянного вызова правильного mergetool:
$ git config --global merge.tool ваш_mergetool
Комментариев нет:
Отправить комментарий