Урок курса

Итоговая миссия: две задачи, один проект

Git и GitHub с нуля: бесплатный курс с практикой

Конкурирующие изменения строки статуса и отложенная строка версии должны попасть в общую main обоих клонов. Для этого нужно сохранить изменения обоих участников при конфликте, вернуть временную правку и довести её отдельный коммит до remote и main коллеги. Чистый status без нужного текста в общей истории ещё не подтверждает результат.

Развёртывание среды: локальный remote и два клона

В git_practice.zip уже лежит готовый bare-репозиторий remote/shared.git с одной веткой main и одним коммитом. README.md в нём выглядит так:

# Командный справочник

Контакт: команда

Статус: черновик

Распакуйте весь архив в новую пустую папку через файловый менеджер. Откройте терминал в этой папке и перейдите в git_practice:

cd "git_practice"

Папок clone_a и clone_b в свежей распаковке ещё нет. Выполняйте блоки последовательно в одном терминале; команды cd ниже задают переходы между клонами.

Оба клона нужно создать до того, как кто-либо внесёт изменение в remote. Это принципиально: если сначала создать один клон, опубликовать в него коммит, а потом клонировать второй — у клонов будет разная стартовая точка и конкурирующего push не получится в нужный момент. Создайте оба сразу:

git clone remote/shared.git clone_a
git clone remote/shared.git clone_b

Каждый клон получит собственную копию репозитория и автоматически запомнит remote/shared.git как origin. Теперь у обоих клонов один и тот же единственный коммит — общий предок.

Clone не копирует авторскую конфигурацию. Перед первым коммитом в каждом клоне нужно задать имя и email локально:

cd clone_a
git config user.name "Алиса"
git config user.email "alice@example.invalid"
git status
git log --oneline
cd ../clone_b
git config user.name "Боб"
git config user.email "bob@example.invalid"
git status
git log --oneline
cd ..

git status должен показать On branch main, nothing to commit, working tree clean. git log --oneline — ровно один коммит. Совпадающие ID исходного коммита подтверждают общий предок. Терминал после cd .. снова находится в git_practice. Отказ push появится после двух независимых конкурирующих коммитов при описанном порядке отправок; одного общего предка для отказа недостаточно.

Параллельные изменения: ветки, коммиты, stash и отклонённый push

Оба участника работают независимо, не зная о правках друг друга. Это ключевое условие сценария: ветки должны происходить от общего исходного коммита, а не от результата чужой работы.

Боб начинает первым. В clone_b создаёт ветку, редактирует README, фиксирует изменение и публикует:

cd clone_b
git switch -c feature/bob
# Отредактируйте README.md: замените «Статус: черновик» на «Статус: в работе»
# Контакт «команда» остаётся без изменений
git add README.md
git commit -m "Обновить статус: в работе"
git switch main
git merge feature/bob
git push origin main

Push проходит, потому что main в remote пока совпадает с точкой, от которой Боб ответвился. Remote теперь содержит коммит Боба.

Алиса работает параллельно в clone_a. Она ещё не делала fetch, поэтому её локальная main и origin/main указывают на исходный коммит — тот же общий предок:

cd ../clone_a
git switch -c feature/alice
# Отредактируйте README.md:
#   «Статус: черновик» → «Статус: готово к проверке»
#   «Контакт: команда» → «Контакт: alice@example.invalid»
git add README.md
git commit -m "Обновить статус и контакт"

После коммита Алиса добавляет в README строку Версия: 1.0, но пока не готова её фиксировать — это незаконченная правка. Чтобы она не мешала дальнейшим операциям и не потерялась, её откладывают в stash:

# Добавьте строку «Версия: 1.0» в конец README.md (не коммитьте)
git add README.md
git stash push -m "Версия 1.0 — незавершённая"

Stash сохраняет проиндексированное изменение и возвращает рабочую папку к состоянию последнего коммита. git status покажет чистое дерево.

Алиса объединяет свою ветку в локальную main:

git switch main
git merge feature/alice

Merge проходит быстрым перемотом (fast-forward), потому что main ещё не содержит коммита Боба. Теперь Алиса пробует отправить результат:

git push origin main

Remote отказывает. Пример сообщения (путь и пояснение отказа зависят от вашего вывода; вместо fetch first может быть non-fast-forward):

 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to '../remote/shared.git'
hint: Updates were rejected because the remote contains work that you do not have locally.

Отказ детерминирован: пока Алиса работала, Боб уже сдвинул вершину main в remote вперёд. Локальная main Алисы не содержит его коммита, поэтому push перезаписал бы чужую работу — Git этого не допускает. Сохраните этот вывод: он понадобится как доказательство наблюдения отказа.

Fetch, merge с конфликтом и согласование статуса

Терминал остаётся в clone_a на локальной main. После отказа push Алиса получает историю коллеги и объединяет её с локальной main:

git fetch origin
git merge origin/main

Fetch обновляет origin/main до коммита Боба, не затрагивая рабочие файлы. Merge пытается объединить две ветки истории — и здесь возникает реальный конфликт.

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

git status покажет:

You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   README.md

Откройте README.md: конфликтный блок содержит обе версии строки статуса. git diff помогает проверить правки; сами строки и маркеры в файле выглядят так:

<<<<<<< HEAD
Статус: готово к проверке
=======
Статус: в работе
>>>>>>> origin/main

Требование к итоговой формулировке: сохранить обе стадии работы («в работе» и «готово к проверке») и контакт Алисы. Простое удаление одного из вариантов теряет информацию. Осмысленный выбор — составная строка или две подписанные строки:

Вариант A (одна строка):

Статус: в работе → готово к проверке

Вариант B (две строки):

Статус (Боб): в работе
Статус (Алиса): готово к проверке

Любой из вариантов допустим, если он содержит обе стадии и объяснён. Контакт должен остаться alice@example.invalid — это требование зафиксировано.

Отредактируйте README.md: уберите маркеры <<<<<<<, =======, >>>>>>> и запишите выбранный текст. Убедитесь, что в файле нет ни одного маркера конфликта. Затем зафиксируйте результат:

git add README.md
git commit -m "Объединить статусы: в работе и готово к проверке"

Сообщение выберите сами — главное, чтобы оно отражало суть слияния, а не просто гласило «merge».

После коммита опубликуйте результат:

git push origin main

На этот раз push проходит: локальная main содержит коммит Боба как предка, поэтому remote принимает обновление. На данном этапе миссия выполнена наполовину — конкурирующие коммиты согласованы и опубликованы. Строка «Версия: 1.0» всё ещё лежит в stash и в main не попала.

Возврат stash, финальный коммит и верификация обоих клонов

Слияние опубликовано, но миссия не завершена: строка Версия: 1.0 находится в stash и в общей истории её нет. Пока она не закоммичена и не опубликована, критерий не выполнен.

В том же терминале, который остаётся в clone_a, Алиса возвращается в свою feature-ветку и обновляет её от объединённой main:

git switch feature/alice
git merge main

Merge переносит в ветку merge-коммит со статусом и контактом. Рабочая папка теперь отражает согласованное состояние. Применяем stash:

git stash list
# убедитесь, что запись существует
git stash apply

Если сохранённая правка пересекается с новым содержимым README, Git может сообщить о конфликте применения. Изменение соседних строк само по себе не гарантирует конфликт: ориентируйтесь на фактический вывод и status. В этом случае git status покажет both modified: README.md снова. Откройте файл, найдите маркеры и уберите их, оставив строку Версия: 1.0 в нужном месте (например, в конце документа). Сохраните весь итоговый README с согласованными статусами, контактом Алисы и версией.

Если конфликта нет, строка возвращена в рабочий файл, но обычный stash apply без дополнительных флагов не обещает восстановить прежнее staged-состояние. В обоих случаях откройте полный README, проверьте требуемый текст и отсутствие маркеров, затем явно подготовьте файл и проверьте индекс:

git status
git diff
git add README.md

Проверьте результат перед коммитом:

git diff --staged

В выводе должна присутствовать строка +Версия: 1.0 и ничего лишнего. Убедившись, фиксируйте:

git commit -m "Добавить версию 1.0"

Это должен быть отдельный коммит — не merge-коммит статуса, а самостоятельное изменение. Теперь удалите использованную stash-запись:

git stash drop
git stash list
# список должен быть пуст

Доведите коммит до main и remote:

git switch main
git merge feature/alice
git push origin main

Синхронизируйте clone_b:

cd ../clone_b
git fetch origin
git merge origin/main

Верификация обоих клонов. Терминал сейчас находится в clone_b на main. Выполните проверки ниже здесь, затем перейдите командой cd ../clone_a и повторите весь набор в main Алисы. Сохраните оба вывода, сравните полный README и фактические ID вершин. В каждом клоне:

cat README.md

Файл должен содержать:

  • заголовок # Командный справочник
  • строку Контакт: alice@example.invalid
  • строку (или строки) с обеими стадиями статуса в выбранном представлении
  • строку Версия: 1.0
  • отсутствие маркеров <<<<<<<, =======, >>>>>>>
git status
# On branch main, nothing to commit, working tree clean

git diff
# (пусто)

git diff --staged
# (пусто)
git log --graph --oneline --all

Граф должен показывать: исходный коммит → коммит Боба и коммит Алисы как две параллельные ветки → merge-коммит → финальный коммит версии. В main обоих клонов вершина указывает на один и тот же коммит.

Чтобы убедиться, что main и origin/main согласованы:

git log --oneline -1 main
git log --oneline -1 origin/main

Оба вывода должны совпадать. Feature-ветки в clone_a и clone_b могут указывать на разные коммиты — это нормально, полный вывод --all двух клонов не обязан совпадать побайтно. Важно содержимое main и текст README.

Если все эти проверки пройдены — обе задачи выполнены: конкурирующие изменения согласованы, временная правка возвращена, закоммичена отдельно и опубликована, история обоих клонов синхронизирована.

Задача 1

Ветка задачи A уже содержит коммит; в tracked README есть отдельная незаконченная строка версии. Условие требует временно отделить эту строку, затем включить основную задачу в местную main. B уже отправил конкурирующий коммит; A пока не получал его. Шаги: К — выполнить merge origin/main и получить конфликт; М — перейти на main и включить свою feature; П — успешно отправить; Ф — получить историю; С — stash правки; Р — разрешить, add и commit; О — наблюдать отказ push. Какой порядок исполняет заданный опыт?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

В миссии первый push A отказал. A выполнил fetch и увидел коммит B в origin/main через show, но README A ещё содержит местный статус, состояние чистое. Противоречит ли это успешному получению?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 3

Письменное объяснение:
В миссии A вернулся на feature/alice, обновил её от объединённой main и вызвал stash apply. Строка «Версия: 1.0» появилась, команда завершилась успешно, но запись ещё видна в stash list. A предлагает сразу удалить запись и сообщить, что обе задачи опубликованы. Объясните: что проверить до drop, что drop делает с записью, почему возвращённая рабочая правка ещё не доступна B, и какие результаты должны появиться до заявления о завершении. Удаление записи после проверки — выбранная дисциплина этого опыта; сохранённая запись сама по себе не ошибка Git.

Платформа проверяет только ответ ниже; действия в своём репозитории и письменные ответы вы проверяете самостоятельно.

Контрольный случай:
В отдельном проекте A находится на feature/docs, обновлённой от общей main. В HEAD README ещё нет строки «Версия: 2.0». A успешно выполнил обычный stash apply, и строка появилась в README. Затем A изменил tracked файл CONTACT.md, выполнил только git add CONTACT.md и git commit -m "Обновить контакт", проверил README и выполнил stash drop. Других add, commit, merge или push после apply не было. Какой вывод о строке версии верен?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 4

Самостоятельная практика:
Настоящая локальная практика Git на своём компьютере. Площадка не запускает команды и не проверяет ваш репозиторий.

Исполнимая подготовка. Распакуйте выданный git_practice.zip в новую пустую папку, перейдите в git_practice. В remote/shared.git ветка main, один коммит; README.md содержит заголовок «# Командный справочник», контакт «команда» и статус «черновик». Создайте оба clone до изменения remote и задайте оба поля автора в каждом:

git clone remote/shared.git clone_a
git clone remote/shared.git clone_b
cd clone_a
git config user.name "Алиса"
git config user.email "alice@example.invalid"
git status
git log --oneline
cd ../clone_b
git config user.name "Боб"
git config user.email "bob@example.invalid"
git status
git log --oneline
cd ..

Оба clone на main, чисты и имеют один общий исходный коммит. init не нужен.

Две задачи. B в собственной feature/bob меняет исходную строку «Статус: черновик» на «Статус: в работе», оставляя контакт «команда». A независимо в feature/alice меняет ту же исходную строку на «Статус: готово к проверке» и контакт на «Контакт: alice@example.invalid». Каждый фиксирует свою задачу отдельным осмысленным коммитом; сообщения выберите самостоятельно. До получения чужой истории эти ветки должны происходить от исходного коммита.

A после своего коммита добавляет в tracked README строку «Версия: 1.0», пока не готовую к коммиту. Сохраните её временно и отделите от основной задачи. B первым доводит свою основную задачу до main и отправляет в remote. A доводит свою основную задачу до локальной main, пока не получает чужую историю; попытка отправки должна получить отказ. Сохраните наблюдение отказа.

Самостоятельно получите и объедините историю коллеги. Обе ветки изменили одну исходную строку статуса: подтвердите настоящий конфликт, затем разрешите его. Заказчик требует сохранить контакт A и обе стадии работы: «в работе» и «готово к проверке». Выберите понятное представление этих стадий — например, составная строка статуса или две подписанные строки. Объясните выбор, сохраните остальные строки документа и завершите объединение с осмысленным сообщением. Отправьте результат. После отправки B больше не вносит новых изменений.

Вернитесь к ветке задачи A, обновите её от уже объединённой main и верните временную строку. При конфликте возврата разберите его изученным способом; не удаляйте stash до проверки возвращённой версии. После проверки завершите работу отдельным осмысленным коммитом, доведите его до общей main и remote. Синхронизируйте main B с опубликованным результатом. Последовательность команд выберите сами из изученных; не заменяйте чужую историю принудительной отправкой.

Критерии и доказательства. В main обоих clone полный README содержит контакт alice@example.invalid, обе названные стадии статуса в вашем объяснимом представлении и «Версия: 1.0», без конфликтных маркеров. История main сохраняет исходный коммит, оба конкурирующих коммита, их объединение и отдельный финальный коммит версии. После актуального fetch main и origin/main обоих clone согласованы; status, diff и staged diff чисты. В clone_a проверенная stash-запись удалена. Приложите отказ push, конфликтный status/diff, объяснение выбранного текста, исходный и итоговый граф истории, итоговый README и status обоих clone. Согласование определяется фактической текущей историей и текстом; заранее заданных SHA, дат и единственного сообщения нет. Feature-ссылки могут различаться, поэтому весь вывод --all не обязан совпадать строка в строку.

Доступные средства: обычный редактор и ранее изученные git clone, git config user.name/user.email, git switch -c, git switch, git add, git commit -m, git merge, git push origin main, git fetch origin, git stash push/apply/list/drop, git status, git diff, git diff --staged, git log --oneline, git log --graph --oneline --all. GitHub-аккаунт не нужен.

Платформа проверяет только ответ ниже; действия в своём репозитории и письменные ответы вы проверяете самостоятельно.

Контрольный случай:
Представлены два альтернативных отчёта миссии X и Y. В каждом main и актуальная origin/main обоих clone указывают на финальный коммит В, status и оба diff чисты, stash пуст. Полный README в В одинаков в обоих отчётах и содержит требуемые контакт, стадии статуса и версию без маркеров. Буквы обозначают условные коммиты внутри каждого отчёта: О — общий исходный, А и Б — независимые задачи участников, В — отдельный коммит версии. Ниже «←» направлена от коммита к его родителям.
X: А ← О; Б ← О; М ← (А, Б); В ← М.
Y: А ← О; Б ← О; Т ← А; В ← Т.
Какой отчёт дополнительно подтверждает сохранение обеих исходных задач в объединённой истории main?

Выберите один вариант
Без регистрации · результат не сохраняется

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку