Git: история и патчи
Повторение: цикл работы
- Синхронизация: pull (fetch+merge) или clone
- Работа:
- Редактирование
- Фиксация commit
- → (1.)
- Публикация: push
Ещё повторение: переписывание истории с помощью reset
Тройственное объединение
Сложный мерж с конфликтами
- Как получается
- Как выглядит недомержеенный текст с конфликтами
см diff3
- Почему это нельзя сделать автоматом
Результат: дополнительный merge commit
- Как выглядит история после мержа
Использование mergetool — melt, vimdiff, …
Rebase
Недостатки мержа:
- мерж-коммит
- запутанный граф разработки
- если в отдельной ветке лежат какие-то фиксы, они «тонут» в истории при мерже:
- соответствующее изменение датируется временем коммита (это могло быть давно, поди найди)
- если после этого были какие-то изменения в том же контексте, надо разрешать конфликт…
…который (внимание!) выглядит так, как если бы разработчики основной ветки что-то делали с пофикшенным файлом (а на самом деле это мы пытаемся применить старые фиксы к новому файлу)…
…и результат этого действия оседает в мерж-коммите
Теперь представьте, что в этой ветке хранятся наши специальные патчи на апстрим, которые апстриму не нужны, а нам нужны. Тогда с каждой новой версией апстрима накладывать их будет всё сложнее.
Что надо/не надо:
- Надо накладывать фиксы на свежеизменённые файлы (как оно в жизни и бывает), а не пытаться наложить изменения поверх фиксов
- Надо хранить только фиксы, актуальные для последней версии (т. е. история модификации этих фиксов нас не интересует)
Идея: «проиграть» изменения, сделанные в фиксах, прямо поверх свежего пастрима
Это очень старая идея «обмена патчами», см. ниже
- В этой картинке, в целом, всё:
Assume the following history exists and the current branch is "topic": A---B---C topic / D---E---F---G master From this point, the result of either of the following commands: git rebase master git rebase master topic would be: A'--B'--C' topic / D---E---F---G master
история ветки topic полностью переписывается, начиная с общего коммита
- все сделанные коммиты — другие, в т. ч. применены к (возможно) другим контекстам
- Commit message и author сохраняются
Следствия:
Ветку topic нельзя публикорвать (как минимум, не стоит никому клонировать)
История разработки topic имеет линейный вид
если (как в примере) rebase делается на вершину (HEAD) ветки master, то последующий topic в master делается по алгоритму fast forward и не приводит к мерж коммиту вообще
даже если приходится устранять конфликты: мы просто коммитим получившиеся новые изменения, и продолжаем дальше
Интерактивный rebase: приукрашивание истории
Идея: «переиграть» все коммиты в данной ветке, начиная с некоторого
- Переставить их местами
- Слить коммит и последующие его фиксапы
- Переписать commit message
- Удалить некоторые
- …
Идеально перед публикацией
Взаимодействие между разработчиками с помощью патчей
diff и его возможности, diff -u
patch, и его возможности (в первую очередь — по наложению патча на уже изменённый файл)
изменения и их контекст в diff -u
- определение сместившегося контекста
определение незначительно изменившегося контекста (например, незначащих пробелов)
git-format-patch: серии патчей
формат: diff -u с дополнениями
можно приложить patch-ем
Но лучше git-am, потому что он сохранит дату, commit message и author.