Урок курса
Итоговая миссия: две задачи, один проект
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?
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
