Станислав Станиславович решил расширить функцонал Pascal ABC.NET и поручил своему студенту написать библиотеку функций для работы с датой и временем. Однако студент не использовал Git и GitHub, а поэтому, когда его жёсткий диск сгорел, весь код пропал. Студента поругали, а работа по написанию библиотеки была поручена вам.
Вы, будучи разумнее вышеупомянутого студента, решили начать работу с создания гит-репозитория.
Запустите Git Bash и перейдите в директорию, где хотите создать репозиторий (в этом задании она обязательно должна быть пуста):
$ cd имя-директории
Создайте гит-репозиторий в этой директории:
$ git init
Теперь, когда репозиторий создан, давайте напишем приветственное сообщение для всех, кто захочет почитать исходники нашей библиотеки.
Создайте в репозитории файл README.md
удобным для вас способом и опишите в нём назначение репозитория с помощью Markdown-разметки.
Ниже можно увидеть пример такой разметки. Узнать больше о Markdown можно тут.
Обратите внимание, что не нужно копировать приведённый ниже пример. В README.md
нужно внести информацию о вашем репозитории и его предназначении.
# Мой любимый репозиторий
Здесь я пишу о том, как же я люблю маркдаун.
А люблю я его по следующим причинам:
- Он крутой.
- В нём есть списки.
- *И наклонный шрифт.*
- **И жирный шрифт.**
- `И красивый моноширинный шрифт.`
Отлично, теперь проверим изменения и сохраним их в репозитории:
Увидеть текущий статус файлов в репозитории можно с помощью следующей команды:
$ git status
Гит сообщит, что наш файл README.md untracked и подсветит его красным. Нужно сообщить ему, что мы собираемся сохранить изменения этого файла:
$ git add <filename>
Снова проверим статус: файл зелёный и гит радостно сообщает, что готов запоминать изменения. Запоминаем:
$ git commit -m "<message>"
Обратите внимание, что важно писать хорошие сообщения коммитов, отражающие суть произведённых изменений. Среди англоговорящих программистов принято писать глаголы в сообщениях к коммитам в повелительном наклонении. Например “Add readme file” подойдёт в нашем случае.
Если проверить статус сейчас, гит скажет, что новых изменений нет.
Изменения в файлах, которые уже были добавлены в индекс, можно не добавлять в коммит отдельными git add
, а воспользоваться следующей командой:
git commit -am "<message>"
Пришло время писать саму программу: назовите файл DateTime.pas и создайте в ней такой текст:
begin
end
Скомпилируйте, снова проверьте git status
. Обратите внимание, что в изменениях появился исполняемый файл, который хранить в репозитории совершенно не обязательно. Давайте скажем гиту, что сохранять его не нужно.
Некоторые файлы мы никогда не захотим помещать в репозиторий (например исполняемые файлы или файл с ключом какого-нибудь API). Такие файлы стоит добавить в gitignore.
Для того чтобы сделать это, нужно создать файл .gitignore
и указать в нём относительные пути ко всем нежеланным файлам и директориям, например:
# удалим все исполняемые файлы
*.exe
# удалим все файлы и папки с именем bin
bin
# удалим конкретный файл с секретными сведениями
\data\secret_key.txt
Гит не будет отображать изменение или создание таких файлов, и, разумеется, не будет сохранять изменения в них.
Подумайте, какие файлы не нужно сохранять в репозитории и напишите .gitignore
для вашей библиотеки.
Если вы используете Linux и не видите в папке проекта созданный файл .gitignore
, то его можно открыть в терминале командой nano .gitignore
.
Какая удача, Станислав Станиславович пишет вам с хорошей новостью: пока вы настраивали репозиторий он попробовал восстановить данные с диска, однако нашёл только этот файл с тестами. Скачайте его, положите в папку репозитория, используйте этот файл c заглушками для функций, сделайте коммит.
Во многих упражнениях мы будем использовать стандартный тип DateTime
, содержащий поля Year, Month, Day, Hour, Second, Millisecond, к которым можно обращаться через точку.
Реализуйте функцию
IsLeapYear
, проверяющую год на високосность (пока что самым простым способом, считая каждый четвёртый год високосным) так, чтобы она проходила тесты (это требование справедливо для всех заданий и больше упоминаться не будет). Сделайте коммит.Реализуйте функцию
DaysInMonth
, считающую количество дней в данном месяце данного года с использованием предыдущей функции. Сделайте коммит.Реализуйте функцию
LaterInDay
, возвращающая ту из двух данных точек во времени, которая находится ближе к вечеру. Сделайте коммит.
О нет, Станислав Станиславович следил за вашей работой и обнаружил, что вы сделали метод LaterInDay
, который на самом деле делать было не нужно, придётся отменять коммит.
Мы столкнулись с необходимостью отменить коммит. Для начала посмотрим историю коммитов:
$ git log
Если добавить после этой команды число как параметр (например git log -3
), то будет выведено только указанное количество последних коммитов.
Если нам нужно отменить самый последний коммит из истории, используем:
$ git revert HEAD
Если же не последний — придётся вместо HEAD написать целиком его хэш-код (длинная последовательность шестнадцатеричных чисел, подсвеченная в логе жёлтым). Сейчас не стоит пробовать удалить не последний коммит, так как такая попытка скорее всего вызовет дополнительные затруднения.
Сразу после этого откроется текстовый редактор, в котором можно поменять сообщение для ревертирующего коммита, но обычно того, что сгенерировалось по умолчанию, бывает достаточно.
Важно понимать что мы не удалили данные о том что изменения были совершены, а сделали изменение, возвращающее нужное нам состояние проекта. В истории сохранились сведения и о всех совершённых изменениях, и об их отмене, в чём можно убедиться запустив git log
ещё раз.
Удалите тесты для метода
LaterInDay
. Сделайте коммит.Напишите функцию
LaterInYear
, проверяющую, какой из двух дней ближе к новому году (31.12, грядущему, а не прошедшему). Сделайте коммит.
У нас есть стабильная версия библиотеки. Сейчас мы хотим добавить в неё несколько связанных по смыслу функций, предварительно убедившись в их работоспособности.
Для того чтобы работать над изменениями в проекте и не сломать ничего в стабильной версии существуют ветки. По умолчанию в репозитории есть только одна ветка -- master
. В этой ветке находится тот код, который разработчики полагают полностью работающим и готовым к использованию.
Создадим новую ветку:
$ git branch <branch-name>
И переключимся на неё
$ git checkout <branch-name>
Теперь можно продолжать разработку как обычно, сохраняя изменения в новой ветке, пока новые функции не станут достаточно хороши чтобы присоединиться к стабильной версии.
Измените функцию проверки года на вискокосность так, чтобы она работала корректно в современной системе летоисчисления (годы, кратные четырём вискокосные, если они не кратны 100, однако такие годы високосны, если они кратны 400). Перепишите тесты, чтобы они корректно проверяли новое содержание метода. Сделайте коммит.
Напишите функцию
DaysInYear
, определяющую количество дней в данном году. Сделайте коммит.Напишите функцию
DaysInYearRange
, определяющую суммарное количество дней в годах от первого до второго включительно (первый год будет меньше или равен второму). Сделайте коммит.
Когда мы написали и протестировали функции, можно добавлять их в стабильную версию библиотеки. Для этого мы сольём нашу новую ветку с master
.
Прежде всего, нужно убедиться что совершённые изменения закоммичены с помощью git status
, и если нет, то закоммитить. После этого переключимся на master
:
$ git checkout master
И сделаем слияние:
$ git merge <branch-name>
Когда работа с веткой завершена, она перестаёт быть нужной, и мы можем её удалить:
$ git branch -d <branch-name>
Продолжаем добавлять методы в библиотеку (разумеется, используя ветки (одной ветки хватит на все оставшиеся задания, не требующие явно сделать ещё одну)):
Напишите функцию
SeconsInHours
, считающую количество секунд в данном количестве часов. Сделайте коммит.Оу, да это была ну уж слишком простая функция. Ревертируйте коммит с функцией
SeconsInHours
и удалите тесты для это функции (сделайте коммит).Напишите функцию
IsYearOfApocalypse
, определяющую был ли в указанный год апокалипсис (концы света были в 1992, 2005, 2011 годах). Напишите тесты. Сделайте коммит.
Ой-ёй, на этот раз вы написали такую функцию, о существовании которой никто даже не должен догадываться. Этот коммит придётся удалить совсем и навсегда.
Полностью удалим коммит из истории:
$ git reset --hard HEAD~1
Для того чтобы удалить несколько коммитов сразу, на месте единицы следует указать нужное их количество.
Возможность переписывать историю проекта существует, но пользоваться ею следует исключительно в тех случаях, когда над репозиторием работает только один разработчик. В ином случае это может привести к серьёзным сложностям у других участников команды и ненависти к любителю удалять коммиты.
Подробнее о способах исправления ошибок в истории коммитов можно узнать здесь.
Если у вас уже есть удалённый репозиторий, в котором вы публикуете изменения, то после удаления коммита отправить в него изменения можно командой:
$ git push --force
Ещё раз: делать так если вы работаете над проектом не в одиночку -- очень плохо.
Что же, Станислав Станиславович доволен проделанной работой, осталось только опубликовать эту библиотеку! Для этого создаём репозиторий на github и подключим его на нашей локальной машине:
Создайте пустой репозиторий на гитхабе (кнопка “+” в правом верхнем углу экрана). Введите его имя, выберите публичным или приватным вы хотите его сделать. У вас будет возможность автоматически сгенерировать пустые README.md и .gitignore, но сейчас этого делать не стоит, потому что мы уже создали эти файлы в нашем репозитории.
Подключение локального репозитория к репозиторию на GitHub по данному адресу:
$ git remote add origin <адрес репозитория>
Локально этому удалённому репозиторию присваивается имя origin
, по которому к нему можно обращаться.
Опубликуем наш репозиторий, указав что хотим чтобы изменения из нашей ветки master
публиковались в удалённой ветке с таким же названием:
$ git push --set-upstream origin master
Такое сопоставление нужно сделать только один раз. После этого все изменения можно будет публиковать более короткой командой:
$ git push
Ну вот, библиотека успешно создана и опубликована, а вы стали начинающим пользователем Git.