From 39a7d57696f75c937b8613e648b48fc5ea235712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=9A=D0=BE?= =?UTF-8?q?=D0=B7=D0=BB=D1=8E=D0=BA?= Date: Sun, 5 Mar 2023 02:03:45 +0300 Subject: [PATCH] =?UTF-8?q?lab02:=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC?= =?UTF-8?q?=D0=B0=20=D0=BA=D0=BE=D0=BD=D1=82=D1=80=D0=BE=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B9=20Git?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- labs/lab02/README.md | 830 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 831 insertions(+), 1 deletion(-) create mode 100644 labs/lab02/README.md diff --git a/README.md b/README.md index cf458ed..44ad09b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ ## Лабораторные работы 1. [Основы языка C++](labs/lab01) -2. Система контроля версий Git +2. [Система контроля версий Git](labs/lab02) 3. Структурирование программ 4. Использование библиотек diff --git a/labs/lab02/README.md b/labs/lab02/README.md new file mode 100644 index 0000000..1de96ec --- /dev/null +++ b/labs/lab02/README.md @@ -0,0 +1,830 @@ +# Система контроля версий Git + +# Цель работы + +1. Знать понятия и компоненты систем контроля версий (СКВ), + порядок и приемы работы с ними. + +2. Уметь участвовать в командной разработке, используя конкретную СКВ — Git, + а также типовой web-интерфейс Gitea. + +# Выполнение работы и составление отчета + +Необходимо выполнить все действия без пропусков. +Читайте пункт задания до конца перед тем, как выполнять его. +Для удобства по тексту отмечены пункты, +способ выполнения которых нужно придумать **самостоятельно.** + +Нужно читать и осмысливать текст, который печатается в ответ на команды. +Если допущена ошибка, нужно повторить команду правильно. + +Отчет должен содержать все введенные команды, ответы системы, пояснения, +что было сделано между пунктами (например, отредактирован файл), а также то, +что требуется добавить в отчет по тексту задания. + +Весь текст, который был в терминале, в отчете должен быть как текст, +а не как скриншоты терминала. Скриншоты `gitk` и web UI не нужны. + +Отчет нужно закоммитить в репозитарий, который создается в ходе ЛР, +как текстовый файл `README.txt` (простой текст) +или как `README.md` в формате Markdown. +Это лучше сделать одним последним коммитом после выполнения работы. + + +## Вход в терминал и создание структуры каталогов + +Большая часть работы будет выполняться в терминале (командной строке). +Для Windows вместе с Git поставляется программа Git Bash: эмулятор терминала +Linux. Ее можно запустить из контекстного меню любого каталога пунктом +*Git Bash Here* или из меню «Пуск». + +**Самостоятельно.** +Создайте на рабочем столе каталог `lab02` для данной ЛР +и запустите в нем Git Bash. + +**Внимание.** +Даже если работа выполняется в компьютерном классе, +создавайте каталог на рабочем столе, а не на сетевом диске, +так как git не сможет нормально с ним работать. + +В терминале откроется *приглашение (prompt)* примерно такого вида: + +``` +user@mpei-dc-win7 MINGW32 /c/Users/user/Desktop/lab02 +$ +``` + +Здесь важен рабочий каталог `/c/Users/user/Desktop/lab02` +и символ `$` — начало ввода команд. + +Просмотреть файлы в рабочем каталоге можно командой `ls`. +В каталоге `lab02` пусто, поэтому `ls` ничего не выведет. + +В ходе работы будем имитировать проект с двумя участниками: Алисой и Бобом. +Компьютеры Алисы и Боба имитируют папки `lab02/alice` и `lab02/bob`: + +``` sh +mkdir alice +mkdir bob +``` + +Переход между каталогами делается командой `cd`. +Перейдем «на компьютер Алисы» — в каталог `alice`: + +``` sh +cd alice +``` + +**Самостоятельно.** +Создайте здесь каталог `project` и перейдите в него. + +Перейти на уровень выше можно командой `cd ..` +(две точки в конце, после `cd` пробел). + +**Самостоятельно.** +Перейдите из каталога проекта вверх, затем вернитесь в каталог `project`. + +Все команды нужно заносить в отчет. +Текст в Git Bash копируется при выделении, ничего нажимать не нужно. +Скопированное можно вставить в любую другую программу *Ctrl+V,* как обычно. +Для вставки в сам Git Bash из буфера обмена +нажмите правую кнопку мыши или *Ctrl+Insert.* + +## Инициализация репозитария и настройка Git + +Инициализируем репозитарий в текущем каталоге (`project`): + +``` sh +git init +``` + +К приглашению командной строки добавилось `(master)`: имя текущий ветви Git. +Ветвь `master` используется по умолчанию. + +Git хранит свои данные в каталоге `.git` в той папке, где сделано `git init`. +Ее можно увидеть командой `ls -A`. +Заходить в `.git` и что-либо делать там не нужно. +Если удалить этот каталог, репозитарий будет безвозвратно утерян. + +Git хранит три набора настроек: + +* Системные — для всех пользователей компьютера. + +* Пользовательские — для данного пользователя системы (`user` в примере). + На практике чаще всего пользуются ими. Хранятся в профиле пользователя. + +* Локальные — для отдельного репозитария, хранятся в нем же. + Используются, если нужно работать с проектами от разного имени + (примеры: личные и корпоративные проекты отдельно, Алиса и Боб в случае ЛР). + +Локальные настройки перекрывают пользовательские. +Пользовательские настройки перекрывают системные. +Настройки Git сами не находятся под контролем версий, +они специфичны для конкретного компьютера или конкретной копии репозитария. + +Настроим репозитарий Алисы, чтобы коммиты были от ее имени: + +``` sh +git config user.name 'Alice (IvanovII)' +git config user.email 'alice@example.com' +``` + +**Самостоятельно.** Укажите данные пользователя, как в примере. +Вместо `IvanovII` используйте свое имя и инициалы латиницей. +Используйте свой университетский адрес почты. +Git сам по себе не отправляет писем на этот адрес. + +Кавычки должны быть парными. +Они могут быть одинарными (`'`) или двойными (`"`). +Если нарушить парность кавычек или нажать *Enter,* не закрыв кавычку, +ввод команды продолжится на следующей строке. В этом случае можно прервать +выполнение команды, нажав *Ctrl + C,* затем ввести команду правильно. + + +## Создание коммитов + +Запустите CodeBlocks и создайте проект в репозитарии Алисы. Убедитесь, +что не создается ненужных подкаталогов: + +*Project title:* `project`\ +*Folder to create project in:* `C:\Users\user\Desktop\lab02\alice`\ +*Project filename:* `project.cbp`\ +*Resulting filename:* `C:\Users\user\Desktop\lab02\alice\project\project.cbp` + +Соберите проект. + +На этом этапе должна быть следующая структура файлов и каталогов: + +``` text +lab02 +├── alice +│   └── project <--------- текущий рабочий каталог +│   ├── .git <--------- создан командой "git init" +│   ├── bin <--------- создан CodeBlocks при сборке +│   ├── obj <--------- (то же самое) +│   ├── main.cpp <-- код программы +│   └── project.cbp <-- файл проекта +└── bob +``` + +### Занесение файлов под контроль версий + +Вернувшись в Git Bash, просмотрим состояние рабочей копии: + +``` sh +git status +``` + +**В отчете** нужно пояснить, что означает каждая строка вывода этой команды. + +Добавим файл `main.cpp` в отслеживаемые (в индекс): + +``` sh +git add main.cpp +``` + +На Windows может отобразиться такое сообщение: + +``` text +warning: LF will be replaced by CRLF in main.cpp +The file will have its original line endings in your working directory +``` + +Оно безвредно. Смысл в том, что Git хранит файлы с немного измененном виде, +чтобы обеспечивать удобную работу с репозитарием в любой операционной системе. + +**Самостоятельно.** +Еще раз просмотрите состояние рабочей копии и поясните в отчете изменения. + +Выполним коммит с файлом `main.cpp` и коротким сообщением: + +``` sh +git commit -m 'code: заготовка программы' +``` + +### Составление сообщений к коммитам + +На практике важно, чтобы описания коммитов были информативными: в будущем +по ним быстро читают историю проекта, ищут коммиты по ключевым словам. +Заголовок (первая строка) должен быть коротким (желательно до 50 символов) +и описывать суть изменений, потому что только он показывается в списке +коммитов. Часто в заголовок включают тему (к какой части проекта относится +коммит) или номер задачи в системе отслеживания ошибок: + +* `code: заготовка программы` — изменен код (а не документация, например) +* `build: update CMake version` — коммит относится к сборке +* `обрабатывает пустой массив | fixes #1234` — исправляет ошибку № 1234 +* `timer: учет високосных лет #4321` — доработка таймера по задаче № 4321 + +Временным незаконченным коммитам иногда приписывают `WIP:` (work in progress). + +Из заголовка должно быть ясно, что в целом сделано и зачем (почему, для чего). +Обычно нет смысла писать, какие именно файлы и функции были изменены, потому +что это можно просмотреть в самом коммите. После заголовка через пустую строку +может идти расширенное пояснение (тело), иногда очень длинное. + +Как и для исходного кода, главный критерий — понятность и единообразие. Можно +писать на русском или английском, в совершенной форме или в повелительном +наклонении — но одинаково во всех коммитах. + +**Самостоятельно.** +Добавьте файл `project.cbp` в индекс и сделайте коммит с ним, тема — `build`. +Сообщение после темы придумайте по смыслу изменений, например, для этого +коммита подошло бы «добавлен файл проекта» или «add project file». + +### Создание коммитов с изменениями + +Заменим тело функции `main()` на ввод двух чисел: + +``` cpp +cout << "Enter A and B: "; +int a, b; +cin >> a >> b; +``` + +**Самостоятельно.** +Просмотрите состояние репозитария (`git status`). В отчете поясните различия +между случаем, когда добавлялся новый файл, и когда изменился существующий. + +Чтобы закоммитить изменения, есть три способа, описанных ниже. Обратите +внимание: Git «видит» состояние файлов на диске, поэтому после добавления +изменений нужно сохранять файл в CodeBlocks. Желательно также собирать +программу после изменений. + +**Способ 1.** +Сначала выбрать файлы, изменения которых должны войти в коммит, затем сделать +коммит: + +``` sh +git add main.cpp +git commit -m "..." +``` + +Этот способ удобен, если изменения присутствуют не только в тех файлах, которые +коммитятся. Например, если работа над кодом уже закончена, а документация еще +не дописана и коммитить ее не нужно. + +**Самостоятельно.** +Добавьте в программу вывод суммы `a` и `b`. + +**Способ 2.** +Добавить в индекс все изменения, затем сделать коммит: + +``` sh +git add -u +git commit -m "..." +``` + +Способ удобен, если измнено много файлов. После `git add -u`, которая +добавляет в индекс измененные файлы, можно командой `git add <файл>` добавить +в индекс новые файлы. + +**Самостоятельно.** +Добавить в программу вывод разности `a` и `b`. + +**Внимание.** +Код доработок должен быть составлен в точности так: + +``` cpp +cout << "A + B = " << a + b << '\n' + << "A - B = " << a - b << '\n'; +``` + +Дальнейшие дополнения тоже должны продолжать одну большую инструкцию вывода, +а не быть отдельными. Это нужно для того, чтобы в последующих пунктах +можно было наблюдать некоторые примечательные ситуации. + +**Способ 3.** +Добавить все изменения в индекс и сделать коммит в один шаг: + +``` sh +git commit -a -m "..." +``` + +Способ полностью эквивалентен предыдущему и удобен, если коммит меняет +только существующие файлы. + +## Игнорирование файлов + +Можно заметить, что в выводе команды `git status` все время присутствуют +каталоги `bin/` и `obj/`. Они содержат бинарные файлы (целевой `*.exe` +и промежуточные), которые являются производными от исходного кода, уже +находящегося под контролем версий. Является грубой ошибкой заносить +под контроль версий продукты сборки. То же самое относится к файлам, +в которых некоторые среды сохраняют, например, состояние редактора: открытые +файлы и расположение окон одного члена команды не нужны в общем хранилище. + +Укажем Git игнорировать присутствие каталога `bin`. Для этого создадим +в CodeBlocks новый файл *(File → New... → Empty)* и запишем в него строку: + +``` text +/bin +``` + +Косая черта в начале означает путь от корня репозитария (каталога `project`), +без нее игнорировался бы файл или каталог `bin` в любой подпапке. Сохраним +файл в корне репозитарий под именем `.gitignore`, именно с точкой в начале. + +Каждое правило игнорирования пишется на отдельной строке `.gitignore`. + +Выполнив `git status`, можно видеть, что каталог `bin` не отображается. + +**Самостоятельно.** +Занесите каталог `obj` в список игнорируемых и убедитесь, что это удалось. + +Файл `.gitignore` может и обычно должен находиться под контролем версий. + +**Самостоятельно.** +Создайте коммит с `.gitignore`, тема — `git`. + + +## Просмотр истории + +### Работа с журналом репозитария + +Журнал репозитария показывает команда `git log`. У нее много опций, например: + +* `git log --stat` показывает файлы, измененные в коммитах; +* `git log --oneline --decorate` показывает коммиты компактно; +* `git log --oneline --decorate --all --graph` делает то же для всех веток. + +Среди прочего, команда показывает для каждого коммита его хэш, +например, `d2e8af7ff9c4684d0deb60d3305474bcaf69ce5c`. Некоторые версии +команды показывают хэш сокращенно — краткий вариант тоже будет восприниматься +командами Git, которые принимают хэш. + +Если лог изменений длинный, `git log` показывает текст с прокруткой. +Чтобы выйти из этого режима, нажмите `q`. + +Попробуйте каждую из приведенных команд. **В отчете** подробно опишите, +что показывается `git log --stat` для последнего коммита. + +Коммиты можно фильтровать по разным признакам: + +* `git log -- main.cpp` показывает затрагивающие `main.cpp`; +* `git log --grep "code:"` показывает коммиты с `code:` в сообщении. + +**Самостоятельно.** +Найдите сначала коммиты по теме `build`, затем коммиты, затрагивающие +`project.cbp`. + + +### Просмотр коммитов + +Содержимое отдельных коммитов просматривается командой `git show `, +где `` может быть хэшем коммита, именем ветви или выражением, +которое задает, на сколько от них отступить в истории. + +Просмотрим последний коммит тремя эквивалентными способами: + +1. `git show HEAD` (текущий) +2. `git show master` (по имени ветви) +3. `git show d2e8af` (по хэшу нужного коммита) + +Для просмотра предыдущего коммита можно либо записать его хэш, +либо указать, что от последнего нужно отступить на один коммит: `HEAD~1`. + +**Самостоятельно.** +Просмотрите предпоследний коммит **(в отчете** зафиксируйте результат единожды) +тремя способами. + + +### Просмотр изменений + +Внесем изменения в `main.cpp`: добавим печать произведения чисел, +но не станем пока делать коммит. + +Просмотрим изменения в рабочей копии: + +``` sh +git diff +``` + +**В отчете** необходимо пояснить все компоненты отображаемого патча. + +Первый аргумент команды `git diff` включает показ изменений от указанного +коммита до последнего, включая изменения в рабочей копии: + +``` sh +git diff HEAD~2 +``` + +С двумя аргументами команда показывает разницу между указанными коммитами, +например, так можно исключить изменения в рабочей копии из вывода предыдущей +команды: + +``` sh +git diff HEAD~2 HEAD +``` + +**Самостоятельно.** +Просмотрите изменения между самым первым коммитом и коммитом, добавляющим +вывод разности. + + +### Использование GUI + +Просмотр истории — одна из операций в СКВ, которую иногда удобнее выполнять +из графической среды. Вместе с Git поставляется графическая оболочка gitk +(Git GUI), которую можно вызвать пунктом *Git GUI Here* в контекстном меню +папки проекта. Эта оболочка очень примитивная, на практике пользуются +[более мощными](https://git-scm.com/downloads/guis) или встроенными в среду +разработки. + +Просмотр истории в gitk делается из меню *Repository → Visualize All Branch +History.* Можно выбирать коммит для просмотра из списка; смотреть +как изменения *(Diff),* так и версии файлов *(Old version, New version);* +искать коммиты. + +**В отчет** ничего заносить не нужно. + +## Откат изменений + +**Самостоятельно.** +Закоммитьте изменения в рабочей копии (вывод произведения). + +Предположим, необходимо отменить (откатить) этот коммит, то есть вернуться +к предыдущему. Для этого воспользуемся командной `git reset`: + +``` sh +git reset --hard HEAD~1 +``` + +Здесь `HEAD~1` указывает на коммит, к которому нужно откатить состояние рабочей +копии, а ключ `--hard` означает, что нужно привести рабочую копию точно +к состоянию выбранного коммита. + +CodeBlocks (и другие среды) могут при этом показать предупреждение, что файл +на диске был изменен, и предложить загрузить его заново. Следует согласиться. + +Добавим над функцией `main()` комментарий: + +``` cpp +// you may type whatever you want +``` + +Уберем изменения в `main.cpp` другим способом — откатив этот файл к состоянию +в последнем коммите (`HEAD`): + +``` sh +git checkout HEAD -- main.cpp +``` + +Второй способ необходим, чтобы откатывать отдельные файлы. Аргумент `HEAD` +необязателен, но вместо него можно указать не последний, а любой другой +коммит. Это полезно, если нужно восстановить состояние одного файла таким, +какое оно было в известный момент. + +## Обмен кодом через удаленное хранилище + +### Регистрация на сервере + +Зарегистрируйтесь на [Git УИТ](http://uit.mepi.ru/git) +под именем вида `KozlyukDA` (своя фамилия и инициалы, как почта МЭИ). +Пароль придумайте самостоятельно. + + +### Настройка SSH + +Отправлять изменения в удаленный репозитарий обычно могут не все. +Так, доступ на запись к репозитариям по умолчанию есть только +у создателя (пользователя, зарегистрированного на предыдущем шаге). +Загрузка комитов (доступ на чтение) из публичных репозитариев разрешена всем. + +Сервер должен выяснить, что клиент, представившийся определенным пользователем, +действительно им является (провести *аутентификацию*). +Клиент git взаимодействует с сервером по протоколу SSH (secure shell), +который использует для аутентификации пары ключей: +открытый (public, публичный) и закрытый (private, приватный) ключ. +Конкретный открытый ключ связан с конкретным закрытым. +Сначала открытый ключ загружается на сервер через web-интерфейс. +Затем любой клиент, который обладает соответствующим закрытым ключом, +может доказать это серверу. +У одного пользователя может быть несколько пар ключей, +например, для рабочего и домашнего компьютера, +тогда на сервер загружаются два открытых ключа. + +**Внимание.** +Закрытый ключ является таким же секретом, как пароль пользователя. +Любой, кто получит закрытый ключ, сможет вносить на сервер изменения +от имени вашего пользователя. +Закрытый ключ нельзя давать никому, открытый ключ можно давать свободно. + +Создать пару ключей: + +``` sh +ssh-keygen +``` + +По умолчанию закрытый ключ записывается в файл `/home/user/.ssh/id_rsa`, +можно оставить это значение по умолчанию (нажать *Enter*). +Далее нужно ввести пароль, которым будет защищен ключ, и повторить его. + +Пример вывода команды: + +`Generating public/private rsa key pair. +Enter file in which to save the key (/home/user/.ssh/id_rsa):` *(Enter)*\ +`Enter passphrase (empty for no passphrase): ` *(ввод не отображается)*\ +`Enter same passphrase again: ` *(ввод не отображается)*\ +`Your identification has been saved in /home/user/.ssh/id_rsa +Your public key has been saved in /home/user/.ssh/id_rsa.pub`\ +*(Далее следуют уникальные для каждого ключа строки.)* + +Вводить пароль каждый раз, когда используется ключ, неудобно. +Используют программу-агент, которая работает в фоне и предоставляет ключи +другим программам, в том числе git. +Пароль требуется тогда вводить один раз — при загрузке ключа в агент. + +Запустить агент: + +``` sh +eval `ssh-agent -s` +``` + +Загрузить ключ (потребуется ввести пароль): + +``` sh +ssh-add +``` + +По умолчанию `ssh-add` загружает `~/.ssh/id_rsa`, для загрузки других ключей, +если это нужно, можно передавать ей путь к файлу ключа явно. + +Отобразить открытый ключ можно командой: + +``` sh +cat ~/.ssh/id_rsa.pub +``` + +**Самостоятельно.** +Скопировать открытый ключ (текст) и добавить в список открытых ключей +своей учетной записи. Это делается в настройках (меню пользователя +в правом верхнем углу, пункт *Settings*), раздел *SSH and GPG keys,* +кнопка *New SSH key.* + +Если работа выполняется в компьютерном классе, закрытый ключ будет утерян +после выхода из учетной записи (или выключении компьютера). Проще всего +дома или на следующем занятии создать новый ключ и добавить его на сервер. +На практике ключи не уничтожают (кроме случаев, когда их украли), +а переносят как файлы, например, при переустановке системы. +Из проводника Windows файл закрытого ключа +виден как `C:\Users\User\.ssh\id_rsa`, +если понадобится его скопировать. + +### Отправка проекта на сервер + +[Создайте репозитарий](https://help.github.com/articles/create-a-repo/) +под названием `cs-lab02`. Вопреки рекомендациям по ссылке, не нужно добавлять +в репозитарий файл `README.md` или лицензию. + +После создания пустого репозитария будет показана страница с инструкциями, +как настроить связь с удаленным хранилищем: + +1. В разделе *Quick setup* нужно выбрать вариант SSH. +2. В разделе *…or push an existing repository from the command line* + даны команды, которые необходимо выполнить. + +Обновите страницу и убедитесь, что файлы проекта видны в web-интерфейсе. +Любой файл можно просмотреть в бразуере. +По ссылке *Commits* можно просматривать коммиты. + +### Получение проекта с сервера + +Предположим, к разработке проекта присоединяется Боб. +Откройте новый терминал Git Bash в каталоге `bob`. +Клонируйте проект: + +``` sh +git clone <адрес> <каталог> +``` + +На место `<адреса>` нужно подставить адрес, который использовался в команде +`git remote add` (его можно всегда отобразить командой `git remote -v`). +Каталог — название папки для проекта: используйте `project`, если не указывать, +это было бы название репозитария (`cs-lab02`). Угловых скобок в команде быть +не должно! + +Перейдите в каталог проекта «на машине Боба» (здесь и далее это означает +работу во втором терминале и над файлами в `bob/project`): + +``` sh +cd project +``` + +**Самостоятельно.** +«На машине Боба» настройте Git (`git config`) аналогично тому, как это +делалось для Алисы в начале лабораторной работы. + + + +## Совместная работа над проектом без конфликтов правок + +«На машине Боба» добавьте в программу печать произведения чисел и сделайте +коммит. Просмотрите последний коммит и убедитесь, что он сделан от имени +Боба. + +Отправьте коммит на сервер. + +``` sh +git push +``` + +**Примечание.** +Поскольку работа от лица Алисы и Боба ведется одним локальным пользователем, +используется один и тот же ключ SSH, поэтому Бобу не требуется отдельной +учетной записи на сервере и отдельного ключа SSH. +На практике у каждого разработчика, разумеется, своя учетная запись и ключ. + +Обновите страницу в web-интерфейсе и убедитесь, что коммит попал в удаленный +репозитарий. Обратите внимание, что авторство коммитов записано в самих +коммитах, оно не зависит от пользователя системы. + +«На машине Алисы» (то есть в первом терминале, в каталоге `alice/project`) +выполните загрузку изменений: + +``` sh +git fetch +``` + +Убедитесь, что в рабочей копии изменений еще не произошло. + +Просмотрите историю всех веток: + +``` sh +git log --oneline --decorate --all --graph +``` + +Как можно видеть, ветка `master` отстает на один коммит от ветки +`origin/master` (версии ветки `master` из удаленного репозитария под названием +`origin`, то есть на сервере). + +Продвиньте ветку `master` к скачанной версии: + +``` sh +git pull --ff-only +``` + +Убедитесь, что рабочая копия проекта «у Алисы» соответствует версии «у Боба». + +Команда `git pull` автоматически делает `git fetch`, поэтому можно было бы +применять только ее, но важно понимать, что получение изменений в Git +двухфазное: загрузка новой части истории и синхронизация положения веток. + +**Самостоятельно.** +«От имени Алисы» добавьте в программу печать деления, сделайте коммит, +отправьте его на сервер и получите новую версию «на машине Боба». +Иначе говоря, повторите шаги выше, поменяв местами роли Алисы и Боба. + +## Разрешение конфликтов правок при совместной работе + +Предположим, Алиса решает добавить в программу печать максимума из чисел, +а Боб — минимума. + +**Внимание.** Код вывода в программе перед выполнением дальнейшего должен +иметь следующий вид: + +``` cpp +cout << "A + B = " << a + b << '\n' + << "A - B = " << a - b << '\n' + << "A * B = " << a * b << '\n' + << "A / B = " << a / b << '\n'; +``` + +В противном случае код нужно привести в соответствие отдельным коммитом +и синхронизировать состояние «у Алисы» и «у Боба». + +«На машине Алисы» дополните программу печатью максимума, сделайте коммит +и отправьте его на сервер. + +«На машине Боба» дополните программу печатью минимума, сделайте коммит +и попытайтесь отправить его на сервер. Как можно видеть, удаленный +репозитарий не принимает изменений: коммит Боба основан не на последнем +существующем коммите. + +«От лица Боба» загрузите коммиты из удаленного хранилища и отобразите +историю всех веток — результат нужно представить **в отчете.** + +Можно видеть, что ветка `master` раздвоилась. Бобу нужно переместить свой +коммит поверх коммита Алисы, то есть поверх `origin/master`: + +``` sh +git rebase origin/master +``` + +Однако эта команда завершается с ошибкой, сообщающей о конфликте в `main.cpp`. +Просмотрите состояние хранилища и поясните **в отчете.** + +«На машине Боба» в CodeBlocks место конфликта будет отмечено прямо в коде. +Необходимо **самостоятельно:** + +1. Удалить метки конфликта: `<<<< ...`, `... >>>>` и `=====`. +2. Отредактировать код так, чтобы он включал и правки Алисы, и правки Боба. +3. Убедиться, что программа компилируется и работает. + +После того, как конфликт разрешен, нужно добавить файл в индекс и продолжить +прерванную операцию `rebase`: + +``` sh +git add main.cpp +git rebase --continue +``` + +Убедитесь, что история хранилища теперь имеет желаемый вид (зафиксировав +это **в отчете)** и отправьте изменения на сервер. + + +## Использование веток + +Предположим, пока Боб синхронизировал изменения, Алиса решила изменить +тип чисел с целых на действительные. Предполагая, что это займет время, +Алиса ведет работу в отдельной ветке. На момент начала работы репозитарий +Алисы *не* синхронизирован с сервером, то есть последний коммит добавляет +печать максимума. Все действия ведутся «на машине Алисы». + +Создайте ветку `double`: + +``` sh +git branch double +``` + +Переключитесь на нее: + +``` sh +git checkout double +``` + +**Примечание.** Создание ветки и переключение на нее можно делать одной +командой: `git checkout -b double`. Этой команде можно передать +аргумент-ссылку на коммит, где создать ветку. + +Можно заметить, что текущая ветка в приглашении терминала изменилась. + +Замените тип переменных `a` и `b` на `double` и сделайте коммит. + +Переключитесь на ветку `master`: + +``` sh +git checkout master +``` + +**Самостоятельно.** +Синхронизируйте ветку `master` «на машине Алисы» с сервером. +Просмотрите историю всех веток и занесите результат **в отчет.** + +Слейте ветку `double` в `master`: + +``` sh +git merge double +``` + +В результате слияния образуется специальный новый коммит (merge commit), +к которому Git предлагает написать сообщение в редакторе. Строки, +начинающиеся с октоторпа («решетки», `#`), в сообщение не войдут. + +Отправьте изменения на сервер. + +Просмотрите и занесите **в отчет** историю всех веток репозитария. + +### Редактор Vim + +Vim — продвинутый текстовый редактор. Он не является частью Git, но популярен +в системах семейства \*nix, поэтому предлагается по умолчанию. Не обязательно +его использовать, но нужно знать минимум для обращения с ним. + +После запуска Vim находится в так называемом *нормальном режиме.* +Чтобы начать вводить текст, нужно перейти *в режим вставки,* +нажав `i` (одну клавишу). +В режиме вставки можно набирать текст обычным образом. +Вернуться в нормальный режим можно нажатием *Escape.* +Находясь в нормальном режиме, можно сохранить сообщение и выйти из Vim +нажатием `ZZ` (две заглавные Z, то есть *Shift+Z* два раза). + +Если вместо *Shift+Z* нажать *Ctrl+Z,* Vim будет приостановлен, а коммит +останется незавершенным. В этом случае нужно вернуться в Vim командой `fg` +в терминале. + +Чтобы писать длинные сообщения, но не использовать Vim, можно указать +другой редактор (например, примитивный `nano`): + +``` sh +EDITOR=nano git merge double +``` + +# Формат защиты + +Защита состоит из ответов на теоретические вопросы по лекции +и выполнения задания, рассчитанного на 10 минут. + +Пример задания: + +1. Создать новый репозитарий. +2. Закоммитить файл `task.txt` с цифрами от 0 до 9 на отдельных строках. +3. Удалить строки с цифрами от 5 до 8, закоммитить. +4. Просмотреть предпоследний коммит. +5. Создать ветку `task` от предыдущего коммита. +6. Переключиться на ветку `task`. +7. Добавить в начало файла строки с буквами `a`, `b`, `c`, закоммитить. +8. Переключиться на ветку `master`. +9. Добавить в начало файла строки с буквами `d`, `e`, `f`, закоммитить. +10. Слить ветку `task` в `master`, разрешив конфликт так, чтобы буквы шли + по порядку.