$ sudo teach IT
Модуль 4 · Ветки · Урок 4.5

Практикум: ветки на визитке

Вы сами проведёте две ветки к конфликту, решите его и оставите в истории аккуратное слияние.

Практикум~25 минутНовичокветкиконфликт слияния

Задание

Практикум по веткам Git: вы сами создадите ветку, параллельно измените тот же участок файла в main, получите конфликт слияния и решите его — полный цикл работы с ветками на вашей визитке. Сначала попробуйте без подсказок, а ниже ждёт подробный разбор.

За модуль вы научились создавать ветки, сливать их, решать конфликты и откладывать правки на полку. Пора собрать всё вместе.

С чего начинаем

Вы на main, git status чистый, git branch показывает только * main, а последний коммит — Merge branch 'feature/footer-style'. Если что-то не так, сначала закоммитьте или спрячьте правки.

Что сделать

  1. Создайте ветку feature/new-project. Добавьте в список «Мои проекты» на главной (<ul> в разделе projects) пункт <li>Калькулятор</li> сразу после «Список дел». Закоммитьте: «Добавить проект «Калькулятор»».
  2. Вернитесь на main и добавьте в то же место того же списка другой пункт: <li>Игра «Угадай число»</li>. Закоммитьте: «Добавить проект «Угадай число»».
  3. Посмотрите граф всех веток: должна быть развилка.
  4. Слейте feature/new-project в main и получите конфликт.
  5. Решите конфликт: в списке должны остаться оба проекта — сначала «Игра «Угадай число»», затем «Калькулятор», без маркеров.
  6. Завершите слияние коммитом с сообщением по умолчанию и удалите слитую ветку.

Что должно получиться

Терминал
$ git log --oneline --graph
*   155da06 (HEAD -> main) Merge branch 'feature/new-project'
|\
| * 52b34af Добавить проект «Калькулятор»
* | e626731 Добавить проект «Угадай число»
|/
*   8f03c75 Merge branch 'feature/footer-style'
...

Почему конфликт, если строки разные

Ни одна ветка не меняла существующие строки, обе только добавили новую. Но добавили в одно и то же место — после «Список дел». Git не знает, какой пункт поставить первым и нужны ли оба, поэтому спрашивает вас. Вставка в одно место — тоже конфликт.

Разбор

Шаг 1. Ветка и пункт «Калькулятор».

Терминал
$ git switch -c feature/new-project
Switched to a new branch 'feature/new-project'
$ git diff
...
       <li>Список дел</li>
+      <li>Калькулятор</li>
     </ul>
...
$ git add index.html
$ git commit -m "Добавить проект «Калькулятор»"
[feature/new-project 52b34af] Добавить проект «Калькулятор»
 1 file changed, 1 insertion(+)

В git diff одна строка с +: новый пункт встал после «Список дел».

Шаг 2. Параллельная правка в main.

Терминал
$ git switch main
Switched to branch 'main'
$ git add index.html
$ git commit -m "Добавить проект «Угадай число»"
[main e626731] Добавить проект «Угадай число»
 1 file changed, 1 insertion(+)

После git switch main пункта «Калькулятор» в файле нет — он в ветке. Строку «Игра «Угадай число»» вы вставили в main перед git add.

Шаг 3. Развилка на графе.

Терминал
$ git log --oneline --graph --all
* e626731 (HEAD -> main) Добавить проект «Угадай число»
| * 52b34af (feature/new-project) Добавить проект «Калькулятор»
|/
*   8f03c75 Merge branch 'feature/footer-style'
...

Разбор по строкам

  • (HEAD -> main) — вы на main, в ней свой новый коммит.
  • (feature/new-project) — у ветки тоже свой коммит; |/ — обе начались от 8f03c75. Перемотки не будет: нужен merge-коммит.

Шаг 4. Слияние и конфликт.

Терминал
$ git merge feature/new-project
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
$ git status
On branch main
You have unmerged paths.
...
	both modified:   index.html
HTML · index.html (список с конфликтом)
    <ul>
      <li>Сайт-визитка</li>
      <li>Список дел</li>
<<<<<<< HEAD
      <li>Игра «Угадай число»</li>
=======
      <li>Калькулятор</li>
>>>>>>> feature/new-project
    </ul>

Разбор по строкам

  • «Сайт-визитка» и «Список дел» — общие строки, Git их не трогал.
  • <<<<<<< HEAD и строка «Игра «Угадай число»» — версия текущей ветки main.
  • ======= — разделитель; ниже «Калькулятор» — версия из ветки, подписанной в >>>>>>> feature/new-project.

Шаг 5. Решение: оставить оба пункта. Здесь как раз подходит кнопка VS Code Accept Both Changes: она оставит обе версии подряд, сначала текущую (HEAD), потом входящую, и сама удалит маркеры. В терминальном варианте просто удалите три строки-маркера. Результат:

HTML · index.html (конфликт решён)
    <ul>
      <li>Сайт-визитка</li>
      <li>Список дел</li>
      <li>Игра «Угадай число»</li>
      <li>Калькулятор</li>
    </ul>

Шаг 6. Отметить, закоммитить, прибрать.

Терминал
$ grep -n "<<<<<<<" index.html
$ git add index.html
$ git status
On branch main
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:
	modified:   index.html

$ git commit
[main 155da06] Merge branch 'feature/new-project'
$ git branch -d feature/new-project
Deleted branch feature/new-project (was 52b34af).

Разбор по строкам

  • grep ничего не нашёл — маркеров не осталось.
  • All conflicts fixed but you are still merging. — осталось закоммитить; в редакторе сохраните сообщение Merge branch 'feature/new-project'.
  • [main 155da06] — merge-коммит создан; ветка удалена, но её коммит 52b34af уже в истории main.

История всего модуля — пять веток: первая влита перемоткой, остальные четыре — merge-коммитами:

Терминал
$ git log --oneline --graph
*   155da06 (HEAD -> main) Merge branch 'feature/new-project'
|\
| * 52b34af Добавить проект «Калькулятор»
* | e626731 Добавить проект «Угадай число»
|/
*   8f03c75 Merge branch 'feature/footer-style'
|\
| * 7aeb0d8 Доделать стили подвала
| * 2bc48f1 Добавить стили подвала
* | 5ef5a2f Дополнить раздел «Обо мне»
|/
*   9a283db Merge branch 'feature/subtitle'
|\
| * 5162731 Уточнить подзаголовок
* | a8b0439 Изменить подзаголовок
|/
*   d3c03bd Merge branch 'feature/footer'
|\
| * 578f2d5 Добавить подвал
* | 89766ce Описать страницы в README
|/
* 5dd4568 Добавить ссылку на страницу проектов
* 294653e Добавить страницу проектов
* 5acc5ae Revert "Поменять цвет фона"
* 875cb0a Поменять цвет фона
...

Хеши у вас будут свои, а форма графа и сообщения — такими же. Начиная с Revert "Поменять цвет фона" и ниже — коммиты прошлых модулей.

Шпаргалка модуля

КомандаЧто делает
git branchсписок веток, звёздочка у текущей
git switch -c имясоздать ветку и перейти на неё
git switch имяперейти на существующую ветку
git log --oneline --graph --allистория всех веток с линиями
git merge имявлить ветку имя в текущую
git merge --abortотменить слияние с конфликтом, вернуть всё как было
git add файл + git commitотметить конфликт решённым и завершить слияние
git branch --mergedкакие ветки уже слиты в текущую
git branch -d имяудалить слитую ветку (-D — без проверки, осторожно)
git stash push -m "подпись"убрать незакоммиченные правки на полку (-u — и новые файлы)
git stash listчто лежит на полке
git stash pop / apply / dropвернуть и удалить / вернуть и оставить / удалить без возврата

Проверьте себя

  • git log --oneline --graph начинается с Merge branch 'feature/new-project', под ним две линии: «Добавить проект «Угадай число»» и «Добавить проект «Калькулятор»».
  • В списке «Мои проекты» четыре пункта, «Игра «Угадай число»» перед «Калькулятором», маркеров нет.
  • git branch показывает только * main, git stash list пуст.
  • git status: nothing to commit, working tree clean.
  • В браузере на главной: новый подзаголовок, четыре проекта, ссылка «Все проекты» и подвал.

Частые ошибки

Слили не туда. Стояли на feature/new-project и выполнили git merge main. Конфликт будет тот же, но решённый результат окажется в ветке. Ничего страшного: закончите слияние, перейдите на main и выполните git merge feature/new-project — теперь это будет перемотка, потому что всё уже соединено в ветке. Привычка на будущее: перед git merge смотреть на первую строку git status.

Остался один пункт. Нажали Accept Current Change или Accept Incoming Change вместо Accept Both Changes, и второй проект пропал из файла. Если слияние уже закоммичено, просто допишите пункт и сделайте обычный коммит «Добавить проект «Калькулятор» в список».

Маркеры на сайте. В браузере видны <<<<<<< HEAD или =======. Значит, файл закоммичен с маркерами: уберите их, git add index.html и новый коммит.

Ветка не удаляется: not fully merged. Скорее всего, слияние не завершено: вы сделали git add, но не git commit. Проверьте git status — если там still merging, выполните git commit, а потом удаляйте ветку.

Что важно запомнить

  • Цикл ветки: git switch -c — коммиты — git switch main — git merge — git branch -d.
  • Конфликт бывает и при вставке разных строк в одно место.
  • Решение конфликта — правка файла без маркеров, git add, git commit. Кнопки VS Code — помощники, но результат проверяете вы.
  • Перед слиянием — чистый git status и правильная текущая ветка.
  • После слияния ветку удаляют: коммиты остаются в истории main.

Теперь вы умеете вести проект в нескольких ветках. Но вся история пока живёт только на вашем компьютере: сломается диск — пропадёт всё, а показать сайт некому. Следующий шаг — GitHub: заведём аккаунт и создадим там репозиторий для визитки.

На следующий урок