Работа с ветками и разрешение конфликтов

Мы уже освоили базовые команды Git: clone, add, commit, push, pull. Теперь мы умеем сохранять изменения, синхронизировать код с удалённым репозиторием и управлять версиями файлов. Но что, если нужно добавить новую функцию, не рискуя сломать рабочую версию проекта? Как работать над несколькими задачами одновременно, не запутавшись в изменениях?

Ответ — в использовании веток.

Ветки: изолированная линия разработки

Ветка — это отдельная линия разработки внутри репозитория. Она позволяет вносить изменения независимо от основной ветки (обычно называется main или master). Это как параллельная ветка событий: вы экспериментируете, пишете код, коммитите — и всё это не влияет на стабильную версию проекта.

💡 Зачем это нужно?
В командной разработке каждый участник может работать над своей задачей в отдельной ветке. Это предотвращает конфликты и порчу основного кода. Даже при работе в одиночку ветки помогают структурировать задачи.

Создание и переключение между ветками

Чтобы создать новую ветку, используется команда git branch <имя_ветки>.

git branch feature/login

Эта команда создаст ветку feature/login, но мы останемся в текущей ветке (например, main).

Чтобы перейти в новую ветку, используется команда git checkout <имя_ветки>:

git checkout feature/login

Теперь все изменения, коммиты и файлы будут относиться к ветке feature/login.

⚠️ Важно:
Команда git checkout используется как для переключения между ветками, так и для отката изменений в файлах. Здесь мы говорим именно о переключении веток.

Можно объединить создание и переключение в одну команду:

git checkout -b feature/login

Флаг -b означает "создать новую ветку и сразу перейти в неё".

Работа в ветке

Теперь, находясь в ветке feature/login, можно добавить новый файл — например, login.py:

# login.py
def authenticate_user(username, password):
    # Упрощённая проверка
    return username == "admin" and password == "12345"

Добавим файл в индекс и сделаем коммит:

git add login.py
git commit -m "Добавлена функция аутентификации"

Мы сохранили изменения в своей ветке. Основная ветка main при этом осталась неизменной.

Слияние веток: команда merge

Когда работа в ветке завершена, её нужно слить с основной веткой. Это делается командой git merge.

Сначала переключимся обратно в main:

git checkout main

Обновим её, если были изменения на удалённом репозитории:

git pull

Теперь выполним слияние:

git merge feature/login

Git автоматически объединит изменения. Если в main не было правок, затрагивающих те же файлы, произойдёт fast-forward — изменения просто будут добавлены в историю.

После слияния ветка feature/login больше не нужна и может быть удалена:

git branch -d feature/login

Конфликт слияния: когда Git не может объединить изменения

Иногда изменения в двух ветках касаются одного и того же участка кода. В этом случае Git не может автоматически решить, какое изменение оставить. Это называется конфликт слияния.

Давайте смоделируем такую ситуацию.

  1. В ветке main в файле config.py изменили строку:

    DEBUG = True
    
  2. В ветке feature/logging та же строка изменена на:

    DEBUG = False
    

Попробуем слить feature/logging в main:

git merge feature/logging

Git сообщит:

Auto-merging config.py
CONFLICT (content): Merge conflict in config.py
Automatic merge failed; fix conflicts and then commit the result.

Файл config.py будет выглядеть так:

<<<<<<< HEAD
DEBUG = True
=======
DEBUG = False
>>>>>>> feature/logging

Здесь:

  • <<<<<<< HEAD — начало изменений из текущей ветки (main)
  • ======= — разделитель
  • >>>>>>> feature/logging — изменения из ветки, которую мы сливаем

Как разрешить конфликт

  1. Откройте файл и вручную отредактируйте его. Например, оставьте:

    DEBUG = True  # Режим отладки включён
    
  2. Удалите все маркеры (<<<<<<<, =======, >>>>>>>).

  3. Сохраните файл.

  4. Добавьте исправленный файл в индекс:

    git add config.py
    
  5. Сделайте коммит:

    git commit -m "Разрешён конфликт: оставлен DEBUG = True"
    

Теперь слияние завершено.

💡 Конфликты — это нормально!
Они не означают ошибку. Это часть процесса командной разработки. Главное — понимать, откуда они берутся, и уметь разрешать их вручную.

Практическое упражнение

Выполните следующие шаги:

  1. Создайте ветку feature/greeting:

    git checkout -b feature/greeting
    
  2. Создайте файл greet.py:

    def greet():
        print("Привет, мир!")
    
  3. Закоммитьте изменения:

    git add greet.py
    git commit -m "Добавлена функция приветствия"
    
  4. Переключитесь в main и обновите репозиторий:

    git checkout main
    git pull
    
  5. Слейте ветку:

    git merge feature/greeting
    
  6. Удалите ветку:

    git branch -d feature/greeting
    
  7. Запушьте изменения:

    git push origin main
    

Визуализация истории: git log --oneline --graph

Чтобы увидеть структуру ветвления и слияния, используйте:

git log --oneline --graph

Это покажет наглядную схему коммитов и веток, например:

*   a1b2c3d (HEAD -> main) Merge branch 'feature/greeting'
|\
| * 4e5f6a7 (feature/greeting) Добавлена функция приветствия
* | 7g8h9i0 Обновление README
|/
* b2c3d4e Инициализация проекта

Подведение итогов

Мы изучили:

  • ветка — изолированная линия разработки
  • branch — создание ветки
  • checkout — переключение между ветками
  • merge — слияние изменений
  • конфликт слияния — ситуация, когда Git не может автоматически объединить изменения

Теперь вы можете безопасно экспериментировать с кодом, не боясь сломать основную версию проекта.

А в следующей теме — Взаимодействие с GitHub: репозитории и Pull Requests — мы узнаем, как делиться своими ветками с командой, предлагать изменения и проходить код-ревью. Это следующий шаг к реальной командной разработке.

Готовы перейти туда, где ваш код увидят другие? 🚀