Данный туториал предназначен для студентов КФУ и не знакомых с системой контроля версий git
и хостингом GitHub
.
git
- это программное обеспечение, позволяющее удобно хранить, передавать и версионировать исходный код. С помощью git
программисты могут параллельно работать над одной и той же кодовой базой, после чего объединять внесенные ими изменения.
git
хранит всю историю изменений, поэтому в случае необходимости можно откатиться к более ранней версии кода.
GitHub
- это коллаборативный git
-хостинг, т.е. сервис, позволяющий пользователям заводить, публиковать и совместно работать над git
-репозиториями.
Также GitHub
позволяет автоматизировать многие рутинные задачи; например, с помощью специальных систем можно автоматически прогонять тесты на коде, который программисты добавляют в git
. Подобным образом будут проверяться ваши домашние работы.
Для того, чтобы не иметь проблем со сдачей заданий через GitHub
, студент должен уметь следующее:
- завести профиль на
GitHub
(если его нет) - установить
git
на своей OS (желательноLinux
илиMacOS
, но можно иWindows
) - склонировать
GitHub
-репозиторий на машину - вытащить последние изменения с репозитория с помощью команд
fetch
иpull
- опционально - создать новую ветку (зависит от задания)
- после выполнения домашнего задания - добавить внесенные изменения в
git
, сделатьcommit
иpush
- через сайт
GitHub
создатьpull
-request с правильным именем и в правильную ветку - добавить своего преподавателя/практика в reviewers
- в случае необходимости -- вернуться на пункт 5 и исправить замечания преподавателя
Если вы способны выполнить все эти шаги, можете смело пропускать данный туториал, т.к. вы вряд ли узнаете из него что-то новое.
Следующие знания являются желательными, но не обязательными:
- уметь добавлять артефакты сборки (бинарники, объектные файлы) в
.gitignore
При работе с git
используются следующие термины:
-
репозиторий (
repository
) - любой проект, находящийся под управлениемgit
. Фактически - просто папка с файлами (исходный код, конфигурации, make-файлы и т.д.). Например, каждая ваша домашняя работа будет выполняться в отдельном репозитории -
коммит (
commit
) - единица изменения репозитория, т.е. набор изменений, которые вы внесли в файлы и сохранили вgit
. У каждого коммита есть уникальный идентефикатор, называемый хэшом (например,31218c50770fa40bc58189039de6714323ca63d0
), по которому на него можно ссылаться -
ветка (
branch
) - отдельно стоящая цепочка коммитов. Ветки удобно использовать для параллельной разработки нескольких фич, чтобы изолировать изменения друг от друга и иметь возможность добавлять коммиты в разные ветки параллельно. Обычно в репозитории есть т.н.master
-ветка, в которую потом сливаются (мерджатся,merge
) другие ветки. Ответвиться можно в любой момент от любого коммита. -
HEAD
- коммит, на который в данный момент переключен репозиторий. Вgit
вы можете переключаться как на ветки (тогдаHEAD
будет указывать на последний коммит в этой ветке), так и на отдельные коммиты.На картинке ниже видно пример из двух веток (голубой и ответвившейся от неё зеленой), и итоговый мердж зеленой ветки в голубую.
При работе с GitHub
используются следующие термины:
-
issue
- специальная запись, которую пользователь GitHub может оставить в любом доступном ему репозитории. Содержание может быть произвольным, но обычно в них оставляют либо сообщения о найденых в проекте ошибках, либо предложения об улучшениях (например, запросы на новые фичи) -
fork
репозитория (англ. вилка) - возможность создать полную копию чьего-то репозитория у себя. Обычно это делают по одной их двух причин:- Исходный репозиторий больше не поддерживается, поэтому вы решаете создать его копию и продолжить поддержку.
- Вы хотите добавить что-то в исходный репозиторий, но не обладаете правами для того, чтобы это делать, или просто хотите поэкспериментировать на безопасной территории.
Для того, чтобы внести изменения в оригинальный репозиторий, существует механизм, описанный в следующем пункте
-
pull-request
- механизм для контролируемого перенесения изменений из одной ветки в другую. С помощью него другие участники проекта могут смотреть, какие именно изменения предлагаются, какова причина этих изменений, а также внести свои комментарии и коррективы в код. После решения всех вопросов, а также прохождения автоматических проверок, изменения могут быть влиты в целевую ветку, а пулл-реквест закрыт. С помощью пулл-реквестов очень удобно выполнять код-ревью, поскольку можно оставлять комментарии с привязкой к конкретным участкам кода
Замечание - если у вас возникают проблемы на любом из перечисленных ниже шагов, или вы не понимаете какого-то из них, не стесняйтесь спрашивать в слаке или заводить issue
к этому репозиторию. Впрочем, первое, что вы должны сделать, когда у вас возникают проблемы - немного погуглить. Обычно решение проблемы будет лежать по первой же ссылке.
N.B. По всем перечисленным ниже командам можно получить справочную информацию, если набрать в консоли git <command> --help
. Обычно там есть много полезного.
Вот здесь описаны способы установки git
на различные платформы.
P.S. git
изначально является инструментом командной строки, и лучше всего знакомится с ним именно через терминал. После того, как вы освоитесь там, для вас не составит труда перейти на другие, иногда более удобные инструменты работы с git
(например, с помошью различных плагинов к текстовым редакторам и IDE
, или программ вроде GitKraken
и TortoiseGit
). А вот обратный переход может быть очень болезненным, особенно если вы целиком доверяли магии конкретных инструментов, не очень понимая, что происходит под капотом.
Итак, вы хотите начать работу с git
репозиторием. Есть два варианта - либо вы начинаете с чистого листа и создаете свежий репозиторий, либо вы хотите работать с уже существующим репозиторием (например, который вы форкнули на GitHub
), который в данный момент еще не скопирован на вашу машину.
В первом случае вам нужна команда git init
. Эта команда инициализирует необходимые git
метаданные в той папке, в которой вы сейчас находитесь, после чего вы можете начинать свою работу. Этой команде также можно передать путь к папке, в которой вы хотите создать репозиторий.
user@unit-1223:~$ mkdir MyAwesomeProject # создаем папку
user@unit-1223:~$ cd MyAwesomeProject/ # переходим в неё
user@unit-1223:~/MyAwesomeProject$ git init
Initialized empty Git repository in /home/user/MyAwesomeProject/.git/
user@unit-1223:~/MyAwesomeProject$
Во втором случае вам необходимо выкачать репозиторий на локальную машину. Для этого используется команда git clone <url>
, где в качестве url
вы должны передать адрес вашего репозитория (например, для скачивания этого репозитория вы должны передать туда https://github.com/cpp-practice/git-tutorial.git
).
Если клонирование прошло успешно, то в вашей текущей директории появится папка, названная в соответствии с клонированным проектом.
user@unit-1223:~$ git clone https://github.com/fedochet/MyAwesomeProject.git
Cloning into 'MyAwesomeProject'...
Username for 'https://github.com': fedochet
Password for 'https://[email protected]':
Checking connectivity... done.
user@unit-1223:~$ cd MyAwesomeProject/
user@unit-1223:~/MyAwesomeProject$
Как видно, git
попросил меня ввести дополнительные данные о себе (мои логин и пароль на GitHub
), потому что репозиторий, который я клонировал - приватный. Публичные репозитории можно клонировать и без учётной записи на GitHub
.
git
хранит информацию о том, кто является автором каждого коммита. За счёт этого в случае можно возможно найти автора конкретного куска кода и набить ему морду задать ему интересующие вас вопросы.
Чтобы git
знал что-то о вас, вам следует сконфигурировать его следующим образом:
user@unit-1223:~$ git config --global user.name User Userov # подставьте свои имя и фамилию
user@unit-1223:~$ git config --global user.email [email protected] # подставьте адрес вашей почты (желательно - такой же, как в GitHub)
Флаг --global
указывает, что эти настройки будут использованы по-умолчанию в случае, если они не указаны в текущем git
-репозитории. Без этого флага, данные настройки будут сохранены только для текущего репозитория.
Если вы не выставите эти значения, то при попытке сделать git commit
вам выдадут ошибку с указанием, что именно нужно сделать.
Обычно, когда мы работаем с репозиторием, мы хотим что-то в нём менять, например добавлять/удалять/двигать файлы, а также изменять их содержимое.
git
умеет замечать изменения, которые вы внесли в файлы относительно того состояния, в котором они были на момент HEAD
-коммита. Увидеть, какие изменения были внесены, а также в какой ветке вы в данный момент находитесь, можно с помощью команды git status
.
user@unit-1223:~/MyAwesomeProject$ git status
On branch master
Initial commit
nothing to commit (create/copy files and use "git add" to track)
user@unit-1223:~/MyAwesomeProject$
user@unit-1223:~/MyAwesomeProject$ echo "Hello world" > new_file.txt # записать "Hello world" в файл new_file.txt
user@unit-1223:~/MyAwesomeProject$ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
new_file.txt
nothing added to commit but untracked files present (use "git add" to track)
git
увидел, что появился новый (untracked
) файл.
Для того, чтобы git
запомнил его, на этом файле нужно выполнить команду git add
.
user@unit-1223:~/MyAwesomeProject$ git add new_file.txt
user@unit-1223:~/MyAwesomeProject$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: new_file.txt
Если вы измените уже существующий файл, git
тоже это заметит, и вам снова потребуется выполнить команду git add
.
user@unit-1223:~/MyAwesomeProject$ echo "Hello again" >> new_file.txt # дописать "Hello again" в new_file.txt
user@unit-1223:~/MyAwesomeProject$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: new_file.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: new_file.txt
user@unit-1223:~/MyAwesomeProject$
Обратите внимание, что сейчас new_file.txt
показывается и как готовый к коммиту, и как not staged for commit
. Это происходит потому, что git
запомнил предыдущую версию файла, а новую - ещё нет, и её нужно добавить отдельно.
Команда git add
может принимать много файлов сразу, а также целые папки.
После того, как над новым или измененным файлом выполнена операция git add
, он переходит в т.н. staged
состояние. Такие файлы отображаются в секции Changes to be committed
в выводе команды git status
. Теперь с помощью команды git commit
можно создать коммит, который будет содержать обновленное состояние репозитория.
Каждый коммит требует непустого сообщения (commit message
), которое должно коротко описывать внесенные вами изменения. Если вы просто выполните команду git commit
, то git
запустит текстовый редактор по-умолчанию с примерно таким текстом:
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
#
# Initial commit
#
# Changes to be committed:
# new file: new_file.txt
#
# Changes not staged for commit:
# modified: new_file.txt
#
(По-умолчанию это может быть nano
(выход - ctrl+X
) или vim
(выход - :q
)).
Редактор удобен в том случае, если вам нужно описать большое количество изменений; если же сообщение небольшое, то можно воспользоваться специальным флагом -m
и дописать сообщение после него.
user@unit-1223:~/MyAwesomeProject$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: new_file.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: new_file.txt
user@unit-1223:~/MyAwesomeProject$ git commit -m 'add new file'
[master (root-commit) e1c446c] add new file
1 file changed, 1 insertion(+)
create mode 100644 new_file.txt
user@unit-1223:~/MyAwesomeProject$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: new_file.txt
no changes added to commit (use "git add" and/or "git commit -a")
user@unit-1223:~/MyAwesomeProject$
Обратите внимание, что теперь секция Changes to be committed
пуста - мы уже создали коммит с этими изменениями, и они сохранены в историю git
.
Часто бывает полезно посмотреть, какие коммиты были сделаны в текущую ветку, а также какие конкретно изменения были внесены каждым коммитом.
Для первого есть несколько комманд, но основной является команда git log
:
user@unit-1223:~/MyAwesomeProject$ git log
commit e1c446c54bf4e5369e1dcc71ede6d7ec00407417
Author: Roman <[email protected]>
Date: Sat Sep 15 15:48:39 2018 +0300
add new file
Как видно, пока что мы сделали только один коммит. Сделаем еще один, чтобы коммитов было два: добавим "Hello again"
к файлу new_file.txt
user@unit-1223:~/MyAwesomeProject$ echo 'Hello again' >> new_file.txt # добавим строчку
user@unit-1223:~/MyAwesomeProject$ git add new_file.txt
user@unit-1223:~/MyAwesomeProject$ git commit -m 'add "hello again"'
[master 31218c5] add "hello again"
1 file changed, 1 insertion(+)
user@unit-1223:~/MyAwesomeProject$ git log
commit 31218c50770fa40bc58189039de6714323ca63d0 # это - хеш коммита
Author: Roman <[email protected]>
Date: Sat Sep 15 17:16:52 2018 +0300
add "hello again"
commit e1c446c54bf4e5369e1dcc71ede6d7ec00407417
Author: Roman <[email protected]>
Date: Sat Sep 15 15:48:39 2018 +0300
add new file
user@unit-1223:~/MyAwesomeProject$
Как видно, теперь коммитов два. Чтобы увидеть, что конкретно было добавлено в новом коммите, можно воспользоваться командой git diff
. Это команда умеет очень много в зависимости от своих аргументов. Без аргументов она покажет, какие изменения были добавлены в файлы, о которых git
уже знает, но ещё не были закреплены через git commit
.
Если передать ей хэш коммита, то она покажет разницу между ним и текущим HEAD
-коммитом.
user@unit-1223:~/MyAwesomeProject$ git diff e1c44 # на коммит можно сослаться через первые несколько цифр его хеша
diff --git a/new_file.txt b/new_file.txt
index 802992c..06ae335 100644
--- a/new_file.txt
+++ b/new_file.txt
@@ -1 +1,2 @@
Hello world
+Hello again
По мере прохождения курса, данный репозиторий будет обновляться. Чтобы обновить материалы по курсу и на Вашем репозитории, необходимо выполнить следующие команды:
- Добавить мой репозиторий в качестве удаленного с названием, например, template:
git remote add template https://github.com/mykfu/[repository-name]
- Обновить все удаленные репозитории (параметр --all обновляет все, можно по названию удаленного репозитория, в нашем случае template):
git fetch --all
- Объединить удаленную и вашу ветку. Вместо [branch to merge] надо указать название ветки, в нашем случае стандартная ветка master.
git merge template/[branch to merge] --allow-unrelated-histories
После шага 3. могут возникнуть конфликты. Список конфликтующих файлов будет указано в выводе, исправьте их и выполните git merge --continue
для продолжения объединения.