← Назад к вопросам

Что самое сложное делал с Git

1.0 Junior🔥 164 комментариев
#Опыт и софт-скиллы

Комментарии (4)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Самое сложное с Git: разрешение конфликтов в слиянии с десятками изменённых файлов и откат на глубоком коммите с сохранением актуальных изменений

Одна из наиболее сложных и нетривиальных задач, с которой мне пришлось столкнуться в практике работы с Git, — это полномасштабный merge-конфликт в крупном Android-проекте с последующим необходимостью глубокого отката (revert) с сохранением критических изменений. Ситуация возникла, когда разработчики работали над двумя крупными фичами в параллельных ветках (feature/auth-overhaul и feature/payment-integration), которые несли масштабные изменения в архитектуре приложения.

Контекст проблемы

Основная ветка develop получила срочные исправления безопасности (хотфикс), после чего обе feature-ветки нужно было аккуратно влить обратно. Ветки не обновлялись относительно develop длительное время, что привело к:

  • Конфликтам в 40+ файлах, включая:
    *   `build.gradle` (версии зависимостей, новые плагины).
    *   XML-макеты с перекрывающимися изменениями в одних и тех же элементах.
    *   Kotlin/Java-классы с переработанной бизнес-логикой и изменёнными сигнатурами методов.
  • Семантические конфликты: код компилировался, но логика нарушалась из-за неявных зависимостей.

Процесс разрешения конфликта

Простое использование git merge или git rebase привело к хаосу. Пришлось применить комбинацию стратегий:

  1. Постепенное слияние через промежуточную ветку:
    git checkout -b merge-resolve
    git merge feature/auth-overhaul --no-commit
    
    После первого слияния я вручную анализировал каждый конфликт, используя `git diff` и IDE-инструменты (Android Studio).

  1. Приоритизация изменений и коммуникация. Для сложных моментов, где логика была неочевидной, я организовывал сессии живого разбора кода (Live Share) с авторами обеих веток, чтобы понять намерения.

  2. Использование git checkout --ours/--theirs для файлов, где изменения были явно одноцелевыми (например, версии зависимостей), и ручного редактирования для файлов с логикой.

  3. Постоянное тестирование. После разрешения конфликтов в группе файлов я немедленно запускал сборку и ключевые тесты:

    ./gradlew assembleDebug testDebugUnitTest
    

Новый вызов: необходимость отката с сохранением фичи

В процессе тестирования выяснилось, что feature/payment-integration основана на устаревшем API, который был deprecated, и всю фичу нужно было временно убрать из релиза. Однако внутри неё были критичные исправления багов в модуле корзины (CartManager), которые уже использовались в feature/auth-overhaul.

Простой git revert на весь коммит слияния был невозможен — он бы удалил и нужные исправления. Пришлось выполнять селективный откат (selective revert).

Решение: комбинация git revert, git cherry-pick и git rebase -i

  1. Идентификация нужных коммитов. С помощью git log --oneline --graph я нашёл хеши коммитов, вносивших:
    *   Платежную логику (нужно откатить).
    *   Исправления в `CartManager` (нужно сохранить).

  1. Интерактивный rebase для очистки истории (на временной ветке):
    git checkout -b revert-temp
    git rebase -i HEAD~20  # Открылся редактор с последними 20 коммитами
    
    В редакторе я закомментировал (удалил) строки с коммитами платежной интеграции, оставив только коммиты исправлений багов и изменений из `feature/auth-overhaul`.

  1. Перенос критичных исправлений. Я изолировал хеш коммита с исправлением CartManager из исходной ветки feature/payment-integration и перенёс его в develop:

    git checkout develop
    git cherry-pick a1b2c3d4  # Хеш коммита с исправлением бага
    
  2. Фиксация состояния и слияние. После всех манипуляций merge-resolve ветка содержала только актуальные изменения, которые были слиты в develop через Pull Request с детальным описанием проделанной работы.

Выводы и ключевые уроки

  • Коммуникация важнее инструментов. Сложные операции в Git требуют чёткого понимания намерений (intent) коллег, а не только кода.
  • Маленькие и частые мержи. Нужно избегать долгоживущих feature-веток, которые сильно отклоняются от основной линии разработки.
  • Полная картина изменений. Такие команды, как git log --stat, git show, git diff A...B (тройное точки), незаменимы для анализа.
  • Безопасность через ветки. Все сложные операции делаются во временных ветках, чтобы основная история не была сломана безвозвратно.

Эта ситуация закрепила понимание, что Git — это не просто система контроля версий, а инструмент для управления историей и координации командной работы, где самые сложные задачи часто лежат в плоскости не технических команд, а анализа последствий и принятия архитектурных решений.