|
|
|
@ -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 <refspec>`,
|
|
|
|
|
где `<refspec>` может быть хэшем коммита, именем ветви или выражением,
|
|
|
|
|
которое задает, на сколько от них отступить в истории.
|
|
|
|
|
|
|
|
|
|
Просмотрим последний коммит тремя эквивалентными способами:
|
|
|
|
|
|
|
|
|
|
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`, разрешив конфликт так, чтобы буквы шли
|
|
|
|
|
по порядку.
|