Однажды знакомая постучалась мне в Аську и спросила, чем мы на работе пользуемся, чтобы управлять и версионировать код. В итоге получился чатик про SVN на часок.
Долгое время тот раздел был полезной справкой для моих школьников. Сначала отсылаешь их штудировать тот лог и пошагово делать, что написано. И только потом отвечаешь на оставшиеся вопросы. Очень экономило преподское время.
SVN больше не в моде, поэтому на основе того чата сочиняю новый. Всё то же самое, но про Гит.
Git. За час.
(22:26:07) Серёджа будем использовать git .
(22:26:11) В. это что такое?
(22:26:48) Серёджа https://ru.wikipedia.org/wiki/Git
(22:27:08) Серёджа это система контроля версий
(22:28:01) В. а есть какая-нибудь ломанная её копию, чтобы посмотреть чего она из себя представляет?
(22:28:13) Серёджа это же опенсорс
(22:28:22) Серёджа там должна быть ссылка чо скачивать
(22:28:50) Серёджа для винды: https://git-scm.com/download/win
(22:29:01) Серёджа на линукс проще поставить через пакетный менеджер.
(22:33:37) Серёджа на Мак я ставлю через brew . Хотя как-то и без него, наверное, можно.
(22:33:48) В. блин. я тут пока врубаюсь че мне качать)
(22:33:56) Серёджа В общем, установка — это отдельная тема. Мы эту часть чата потом сочиним.
(22:37:04) Серёджа Она к тому же отличается на разных осях, так что, пока как-нибудь сама давай.
Установка Git на Alpine Linux
(22:37:30) Серёджа Ещё хорошо бы покрыть тему доступа к сервису: пароли, ключи, ssh-config и прочее. Теперь вы понимаете, почему я с детьми начинал с SVN, он в сто раз проще ложится в неподготовленную голову. Ну ладно, продолжаем…
(22:38:26) В. качается
(22:41:30) В. ога скачала
(22:42:30) Серёджа ставь.
(22:42:37) В. ога
(22:42:40) В. щас. вернусь
(22:47:53) В. тут
(22:48:01) Серёджа ага.
(22:48:04) В. хм. а русификация к нему есть?
(22:48:33) Серёджа щас объясню всё, можно будет без русификации обойтись.
(22:48:38) В. давай
(22:48:39) Серёджа
создай пустую папку:
mkdir repo-service
(22:49:23) В. есть
(22:49:31) Серёджа
Создай в ней «голый» репозиторий:
git init --bare repo-service
(22:50:15) В. ога
(22:50:46) Серёджа получилось?
(22:51:01) В. да
(22:51:02) Серёджа значит. У нас получился репозиторий, который будет имитировать Гит-сервис из интернета, типа такой домашний ГитХаб.
(22:51:27) Серёджа
теперь делаешь в другом месте другую папку:
mkdir repo
(22:51:55) В. и?
(22:52:08) Серёджа
клонируешь в него репо из сервиса:
git clone repo-service repo
(22:52:55) В. и?
(22:53:34) Серёджа
repo-service
— это путь до репозитория, который только что создала. Обычно это URL до репозитория на сервисе в сети.
(22:53:45) Серёджа Но у тебя сейчас это тупо подпапка в том же каталоге, где ты сейчас стоишь, поэтому относительный путь от твоего места — это тупо имя папки.
(22:54:09) В. ога. проканало
(22:54:21) Серёджа круто. Это ты сделала рабочую копию
(22:54:46) В. ога
(22:54:47) Серёджа
Если ты напишешь:
cat repo/.git/config
, то увидишь раздел
[remote "origin"]
, где будет абсолютный путь в твоей файловой системе до
repo-service
Скриншот терминала с исполнением команд, упомянутых момент создания репозитория
(22:55:01) Серёджа
обычно путь до репозитория выглядит как-нибудь вроде:
git@github.com:chromium/chromium.git
или
https://github.com/chromium/chromium.git
(22:55:15) Серёджа ну в смысле, когда он на серваке
(22:55:15) Серёджа
Переходи в каталог репозитория
cd repo
и ещё немножко подготовки: нужно назвать гиту своё имя и почту,
которые он будет подставлять в качестве автора кода.
git config user.email your-mail@example.org
git config user.name Your Name
(22:55:28) В. а дальше?
(22:55:31) Серёджа дальше. можно работать. создай там текстовый файл
(22:55:42) Серёджа и напиши чего-нибудь в несколько строчек
(22:57:40) В. ога. я уже файл запихала в первую папку.
(22:57:52) В. ну он типа сохранился в хранилище
(22:58:01) Серёджа сделала коммит?
(22:58:09) В. да
(22:58:12) Серёджа как?
(22:58:18) В.
git add first.txt && git commit -m "my first commit"
(22:58:28) В. гы) что ещё можно с ним делать. ну запихаю я туда кучу файлов. и что?
(22:58:47) Серёджа
напиши
git status
(22:58:54) В. ога
(22:59:09) Серёджа
видишь, в последней строчке
nothing to commit, working tree clean
?
Скриншот терминала: настройки автора, первый коммит и проверка статуса
(22:59:11) Серёджа да
(22:59:18) Серёджа отлично.
(23:00:05) В. значит файл закопировался в хранилище или как его обозвать не знаю?
(23:00:19) Серёджа в репозиторий. В его рабочую копию, которая как-бы на компе у программиста.
(23:00:39) Серёджа теперь измени файл
(23:00:49) Серёджа добавь пару строчек и измени какие-нибудь
(23:01:15) Серёджа
напиши
git status
потом
(23:01:17) В. изменила.
(23:01:21) Серёджа
видишь:
modified: first.txt
(23:01:21) В. и?
(23:02:57) Серёджа
git status
показывает общее состояние. Теперь напиши
git diff
, увидишь что конкретно изменилось.
(23:03:03) Серёджа С минусиками — строчки, которые удалились, с плюсиками — которые добавились. Изменённые — как-бы удалились и добавились одновременно.
(23:03:15) В. ога вижу
Скриншот терминала: статус и просмотр изменений
(23:03:20) Серёджа хорошо. закрывай.
(23:03:24) Серёджа
делай коммит:
git commit -am "some changes in my first file"
(23:03:30) Серёджа
флаг
-a
означает, что ты коммитишь все изменённые файлы,
которые уже были под контролем гита. Новые файлы тебе бы пришлось добавлять отдельной командой
git add ...
(23:03:39) Серёджа
Флаг
-m
означает, что ты тут же в команде пишешь комментарий к коммиту. Комментарий — полезная штука. Без
-m
он откроет в терминале дефолтный текстовый редактор и предложит написать комментарий к коммиту в нём.
(23:03:54) Серёджа Заметь. В репозиторий сохраняются только изменения.
(23:04:14) Серёджа то есть это ты не второй файл туда залила, а только сохранила информацию о том, как файл изменился.
(23:04:47) Серёджа точно так же и наоборот. Когда кто-то что-то изменил, а ты делаешь апдейт
(23:04:57) Серёджа то ты тоже выкачиваешь только изменения
(23:05:05) В. удобно. а что ещё оно умеет?
(23:05:16) Серёджа
Теперь говори
git log
(23:06:38) В. получилось.
Скриншот терминала: лог
(23:06:44) Серёджа Видишь длиные айдишники коммитов в логах? На них можно ссылаться в разных командах, причём айдишники можно сокращать, брать от них только начало.
(23:06:57) Серёджа Пиши:
git diff aa690a5~ aa690a5
(23:07:05) В. отличия показывает!
Скриншот терминала: изменения конкретного коммита
(23:07:10) Серёджа
ты можешь выбрать любую ревизию и сапдейтиться до неё:
git checkout 12920972
(23:06:31) В. круто — могу и старые файлы видеть!!!
(23:07:25) Серёджа
т е. сказать
git checkout <commitId>
и у тебя будет версия как сто лет назад
(23:08:06) Серёджа Дальше. Бывает, что всякие проги создают в рабочей копии всякие левые файлы и папки, которым в репозитории не место.
(23:08:26) Серёджа например скомпилированый ехе файл коммитить незачем
(23:08:27) В. угу
(23:08:36) Серёджа создай какой-нибудь файл
(23:08:38) В. ога
(23:08:55) В. ога
(23:08:56) Серёджа
пиши
git status
(23:09:08) Серёджа видишь свой файл в списке Untracked files
(23:09:26) В. угу и?
(23:09:27) Серёджа
создаёшь файл
.gitignore
и записываешь свой файл туда:
/program.exe
(23:09:39) В. угу
(23:09:48) Серёджа
Теперь в
git status
твой новый файл исчез, зато появился
.gitignore
. Его нужно добавить и закоммитить.
(23:09:39) В. ога. сделала саммит.
Скриншот терминала: игнорим файл
(23:09:57) Серёджа Теперь, например, если это error.log
(23:09:58) Серёджа
то можно в игнор добавить
*.log
или
*.exe
и т. п.
(23:10:06) В. ненужный файл туда не попал!
(23:10:19) В. ога. понятно
(23:10:21) Серёджа
и все эти файлы не будут коммитится и не будут отображаться в
git status
(23:10:30) В. понятно
(23:10:36) Серёджа теперь. Ты что-то понаписала, но ещё не закоммитила и хочешь откатить.
(23:10:40) В. угу
(23:10:42) В. и?
(23:10:43) Серёджа
делаешь
git checkout -- .
это откатит все изменения, которые были под контролем гита.
(23:10:56) Серёджа
git clean -f
убирает все незатрэканные файлы из рабочей копии. Чтобы убедиться, что ты не удалишь что-то нужное, сначала
git clean -n
выдаст список тех файлов,
которые бы удалил флаг
-f
.
tutorial
(23:11:27) В. работает!
(23:11:28) Серёджа
дальше. Нужно запушить изменения:
git push
.
Скриншот терминала: гит пуш
(23:11:29) Серёджа
Создай себе где-нибудь ещё одну рабочую копию:
git clone repo-service repo-2
.
Ты увидишь в
repo-2
все те же файлы, что и в
repo
Клонируем в другую рабочую копию
(23:12:30) Серёджа Это типа другой программист присоедининлся к проекту. Надо ему тоже имя и почту настроить:
git config user.email anoghterguy@example.org
git config user.name Another Guy
(23:12:34) Серёджа Измени в новой папке файл и сделай коммит и пуш.
Другой чел пушит
(23:12:39) Серёджа
В старой сделай
git pull
Стягиваем изменения другого чела к себе
(23:12:45) В. да и в новую рабочую папку обновила по репозиторию
(23:13:42) В. да и в старой рабочей папке апдейтилась и увидела изменения что сделала в новой рабочей папке
(23:13:47) В. а что ещё можно?
(23:13:53) Серёджа А в первой папке измени файл в том же месте, где в той, только по другому.
(23:13:58) Серёджа чтобы конфликт возник
(23:14:03) В. ога
(23:14:09) В. а если я его переименую?
(23:14:16) Серёджа не. ща
(23:14:25) В. изменила и че делать?
(23:14:34) В. я их переименовала)
(23:14:34) Серёджа теперь апдейться
(23:14:43) Серёджа ну. давай поочереди
(23:15:22) Серёджа
заметь. Что переименовывать лучше не стандартной командой, а командами гита:
git mv
.
(23:15:44) Серёджа
Потому что тогда гит сразу трэкает, что это лишь изменённый файл. В репозиторий сохраняется только информация о переименовании. Впрочем, он это сам по содержимому понимает. Если один файл удалить, а другой такой же добавить и всё это засунуть в гит:
git add ...
то он поймёт, что это
было лишь переименование.
(23:15:50) Серёджа Неважно. Давай, изменяем один и тот же файл в обоих копиях. Другой чел коммитит и пушит. Ты тоже коммитишь и пушишь.
(23:16:04) В. ога возник конфликт
(23:16:09) Серёджа Это ещё не конфликт, просто ты не можешь пушить, пока не спуллишь, даже если бы изменения не были конфликтными.
Не можем запушить, пока не спуллим
(23:16:10) Серёджа пулль!
(23:16:11) В. да, вижу конфликт
Пулл с конфликтом
(23:16:13) Серёджа
И ещё
git status
.
Видишь, что статус не пишет «nothing to commit», у тебя получилось предкоммитное состояние
с изменениями и конфликтный файл помечен «both modified»,
что он изменён одновременно и у тебя, и в том коде, который пришёл из пулла.
Статус в конфликте
(23:16:15) В. понятно
(23:16:17) Серёджа Открывай конфликтный файл в текстовом редакторе.
(23:16:26) В. и?
(23:16:29) Серёджа У тебя появился кусок:
<<<<<<<<< yours
some text
from your changes
==========
another text
from incoming changes
>>>>>>>>> theirs
(23:16:38) Серёджа Сверху версия одних изменений, снизу — других.
Смотрим конфликтный файл в текстовом редакторе
Заметь, что каждый из вас правил по четыре строчки, но конфликтные только две, потому что нижние две у вас совпадают и не образуют конфликта.
(23:16:39) В. типа умный
(23:16:44) Серёджа типа да. В файле нужно убрать мусорные обозначения а из двух кусков текста выбрать или скомпоновать, тот текст, который в итоге нужен.
Поправили конфликт в текстовом редакторе
(23:16:49) Серёджа
потом сохраняешь файл, делаешь ему
git add
. Так с каждым конфликтным файлом.
Потом коммит, пуш.
Коммит решённого конфликта
(23:16:55) Серёджа
У вас теперь в дереве коммитов развилочка. Пишешь
git log --graph
.
Видишь, вы вдвоём сделали по коммиту от общего предка, а потом слили свои изменения
ещё одним коммитом. По дороге пришлось зарешать конфликт.
Граф коммитов
(23:17:05) Серёджа Если конфликтов нет, то гит сам сливает развилку в один коммит. Новый коммит на слиянии тоже образуется, но автоматически. Впрочем, это поведение регулируется разными флагами гитовских команд.
(23:18:30) Серёджа Также есть правило. Перед пушем всегда делать пулл. Но он и не даст запушить, если не всё спуллено.
(23:18:35) Серёджа Кроме того принятно пуллиться каждый день перед работой. Ну и вообще, регулярно и почаще.
(23:18:49) Серёджа Это помогает избежать неприятностей
(23:25:26) Серёджа Обычно конфликты не возникают.
(23:25:41) Серёджа Если изменения в разных частях файла, то он их нормально сам разруливает.
(23:32:12) Серёджа дальше про переименования.
(23:32:37) Серёджа Если ты просто файл переименуешь, то он подумает, что файл потерялся и появился новый без контроля версий.
(23:32:43) Серёджа старый он восстановит при апдейте
(23:32:58) Серёджа
Поэтому удалять, переименовывать надо командами
git
(23:33:40) Серёджа Чем хорошо. Ты можешь переименовать огромную преогромную папку. А в репозиторий запишется только одна строчка, что такая-то папка была переименована. (Думаю, что с копиями то же самое, но это не точно)
(23:33:50) В. ога получается
(23:34:43) Серёджа
Ну в принципе всё. В любой непонятной ситуации делай
git status
и в понятной тоже.
(23:34:49) Серёджа Ещё неплохо бы покрыть следующие темы:
- Установка на разные операционные системы, но про это и так есть дофига инструкций в инете.
- Доступ к сервису: пароли и ключи, и настройка локального хранилича кренделей для разных операционных систем.
- Работа с ветками
- Best practices
(23:34:49) Серёджа Почитай ещё статейку в википедии и документацию .
(23:35:23) В. прикольно в общем.
(23:40:22) В. а вообще спасибо — прямо просвятил. да ещё и удалённо по аське.