Комментарии (4)
Ответ сгенерирован нейросетью и может содержать ошибки
Самое сложное с Git: разрешение конфликтов в слиянии с десятками изменённых файлов и откат на глубоком коммите с сохранением актуальных изменений
Одна из наиболее сложных и нетривиальных задач, с которой мне пришлось столкнуться в практике работы с Git, — это полномасштабный merge-конфликт в крупном Android-проекте с последующим необходимостью глубокого отката (revert) с сохранением критических изменений. Ситуация возникла, когда разработчики работали над двумя крупными фичами в параллельных ветках (feature/auth-overhaul и feature/payment-integration), которые несли масштабные изменения в архитектуре приложения.
Контекст проблемы
Основная ветка develop получила срочные исправления безопасности (хотфикс), после чего обе feature-ветки нужно было аккуратно влить обратно. Ветки не обновлялись относительно develop длительное время, что привело к:
- Конфликтам в 40+ файлах, включая:
* `build.gradle` (версии зависимостей, новые плагины).
* XML-макеты с перекрывающимися изменениями в одних и тех же элементах.
* Kotlin/Java-классы с переработанной бизнес-логикой и изменёнными сигнатурами методов.
- Семантические конфликты: код компилировался, но логика нарушалась из-за неявных зависимостей.
Процесс разрешения конфликта
Простое использование git merge или git rebase привело к хаосу. Пришлось применить комбинацию стратегий:
- Постепенное слияние через промежуточную ветку:
git checkout -b merge-resolve git merge feature/auth-overhaul --no-commit
После первого слияния я вручную анализировал каждый конфликт, используя `git diff` и IDE-инструменты (Android Studio).
-
Приоритизация изменений и коммуникация. Для сложных моментов, где логика была неочевидной, я организовывал сессии живого разбора кода (Live Share) с авторами обеих веток, чтобы понять намерения.
-
Использование
git checkout --ours/--theirsдля файлов, где изменения были явно одноцелевыми (например, версии зависимостей), и ручного редактирования для файлов с логикой. -
Постоянное тестирование. После разрешения конфликтов в группе файлов я немедленно запускал сборку и ключевые тесты:
./gradlew assembleDebug testDebugUnitTest
Новый вызов: необходимость отката с сохранением фичи
В процессе тестирования выяснилось, что feature/payment-integration основана на устаревшем API, который был deprecated, и всю фичу нужно было временно убрать из релиза. Однако внутри неё были критичные исправления багов в модуле корзины (CartManager), которые уже использовались в feature/auth-overhaul.
Простой git revert на весь коммит слияния был невозможен — он бы удалил и нужные исправления. Пришлось выполнять селективный откат (selective revert).
Решение: комбинация git revert, git cherry-pick и git rebase -i
- Идентификация нужных коммитов. С помощью
git log --oneline --graphя нашёл хеши коммитов, вносивших:
* Платежную логику (нужно откатить).
* Исправления в `CartManager` (нужно сохранить).
- Интерактивный rebase для очистки истории (на временной ветке):
git checkout -b revert-temp git rebase -i HEAD~20 # Открылся редактор с последними 20 коммитами
В редакторе я закомментировал (удалил) строки с коммитами платежной интеграции, оставив только коммиты исправлений багов и изменений из `feature/auth-overhaul`.
-
Перенос критичных исправлений. Я изолировал хеш коммита с исправлением
CartManagerиз исходной веткиfeature/payment-integrationи перенёс его вdevelop:git checkout develop git cherry-pick a1b2c3d4 # Хеш коммита с исправлением бага -
Фиксация состояния и слияние. После всех манипуляций
merge-resolveветка содержала только актуальные изменения, которые были слиты вdevelopчерез Pull Request с детальным описанием проделанной работы.
Выводы и ключевые уроки
- Коммуникация важнее инструментов. Сложные операции в Git требуют чёткого понимания намерений (intent) коллег, а не только кода.
- Маленькие и частые мержи. Нужно избегать долгоживущих feature-веток, которые сильно отклоняются от основной линии разработки.
- Полная картина изменений. Такие команды, как
git log --stat,git show,git diff A...B(тройное точки), незаменимы для анализа. - Безопасность через ветки. Все сложные операции делаются во временных ветках, чтобы основная история не была сломана безвозвратно.
Эта ситуация закрепила понимание, что Git — это не просто система контроля версий, а инструмент для управления историей и координации командной работы, где самые сложные задачи часто лежат в плоскости не технических команд, а анализа последствий и принятия архитектурных решений.