Добрый день! Данная статья представляет собой краткий мануал как пользоваться Git в производственной среде. В прошлой статье я уже упоминал про развертывание Gitlab сервера внутри компании, считайте эту статью — продолжением.
Откуда черпать информацию:
-
Самая авторитетная, а так же бесплатная и находящийся в свободном доступе — «Pro Git». Читать настоятельно РЕКОМЕНДУЮ! Даже картинки есть
Поставить Git можно на любую ОС — консольные и графические клиенты есть под любую операционку.
Мое имхо — использование графических клиентов излишне, мне хватает консольного клиента, тем более в сети большинство примеров про него. Но если что — клиенты встроены во все популярные IDE.
Основные команды
Что надо обязательно знать и уметь использовать (я привожу их в случайном порядке):
-
branch — сделать ветку
-
checkout — переключиться на ветку
-
add — добавить файл в отслеживаемые
-
commit — сделать коммит (фиксацию)
-
merge — слить изменения веток
-
pull/push/fetch — стянуть или наоборот вытолкать свои изменения с сервера или на сервер
-
log — посмотреть кто и что начудил
-
stash — спрятать свои недонаработки
-
status — посмотреть текущее состояние локальной репы
-
reset — откатить ченджи
-
rm — удалить файл из отслеживаемых
-
clone — склонировать репозиторий
Подготовка к работе
Итак, дорогой друг, ты решил попробовать эту странную штуку под названием Git, хотя ни разу ей не пользовался — погнали!
1. Сгенерируй себе ssh ключ.
Я понятия не имею какой ОС ты пользуешься так что загугли как это сделать (да, я даже облегчил тебе задачу). Я использую Linux, у меня он уже есть.
2. Настрой свой git клиент. Для этого есть опции config. Мне хватает 4-х:
1 2 3 4 |
$ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com $ git config --global core.editor vim $ git config --global merge.tool vimdiff |
П.С. Имя юзера и имейл должны совпадать с теми что у тебя в профиле (см далее)
Кстати, когда ты пользуешься опцией global — ты задаешь настройку для клиента глобально (кеп), а если ты введешь такие же команды в конкретном репозитории — ты настроишь параметры только для него.
3. Иди в Gitlab через веб интерфейс (либо публичный, либо свой, если разворачивали) и там заходи со своей учеткой. И да если ты пользуешься своим Gitlab серверов, как это было в прошлой статье, не забудь выбрать вкладку LDAP:
Настройка учетки в Gitlab
Надеюсь ты смог залогиниться.
Далее идем в настройки профиля (https://гит-сервер/profile):
Там настраиваем себе язык, цвет темы, цвет редактора, аватарку, черта лысого — развлекайся.
Главное- потом не забудь зайти в пункт SSH ключи (https://гит-сервер/profile/keys) и там добавить хотя бы 1 (но только публичную часть):
(если что, я тут сократил ключ чтобы весь не вставлять)
1 2 3 |
kirill@xxx:~$ cat ~/.ssh/test-key.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDI..................................................................BzUHjyiJ+YQ== kirill@xxx:~$ |
Плюс советую поиграться с настройкой тем и редактора: https://гит-сервер/profile/preferences
И настроить дефолтный дашборд:
Создание репозитория
Давай рассмотрим создание репозитория на примере репы для бекап-скриптов. Для этого я сделал отдельный неймспейс/группу OPS (Operations)
и теперь создадим тут сначала подгруппу (New Subgroup) а потом проект (New Project). Проект это и есть репозиторий. А группу я хочу сделать для большей гранулированности — чтобы скрипты для бекапов были в подгруппе «backups». Ну так выглядит симпатичней и навигация проще имхо.
Итак, мы получаем страничку пустого проекта (сиречь репозитория):
где нам не двусмысленно подсказывают как мы можем начать работу. Такая подсказка будет появляться у вас на экране КАЖДЫЙ раз при создании пустого проекта и висеть там ДО ТЕХ ПОР пока вы хоть 1 файл в проект не зальете. Так что не надо себе сохранять как памятку:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
Command line instructions Git global setup git config --global user.name "kirill.kazarin" git config --global user.email "kazarin.ka@yandex.ru" Create a new repository git clone git@git.*имя сервера*:OPS/backups/file-backup-scripts.git cd file-backup-scripts touch README.md git add README.md git commit -m "add README" git push -u origin master Existing folder cd existing_folder git init git remote add origin git@git.*имя сервера*:OPS/backups/file-backup-scripts.git git add . git commit -m "Initial commit" git push -u origin master Existing Git repository cd existing_repo git remote rename origin old-origin git remote add origin git@git.*имя сервера*:OPS/backups/file-backup-scripts.git git push -u origin --all git push -u origin --tags |
Пример работы с репозиторием
Подготовка
Итак, для примера у меня есть папка test в которой лежат пара скриптов для бекапа файлов — я хочу запихнуть их в этот репозиторий, инициировав его. Итак, что на входе:
1 2 3 4 5 6 7 |
kirill@xxx:test$ tree -a . ├── .directory ├── file_backup.sh └── git_backup.sh 0 directories, 3 files |
Я не хочу чтобы в репозиторий попадали всякие мусорные файлы, как например скрытая папка «.directory», как тут. Для этого я делаю файл «.gitignore» в который вношу имена и маски имен объектов (файлов и каталогов) которые должны игнорироваться git-ом:
1 2 3 |
kirill@xxx:test$ vim .gitignore kirill@xxx:test$ cat .gitignore .* |
Инициализация и первый коммит
Теперь воспользуемся инструкцией из второго примера на нашей страничке пустого проекта «Existing folder»:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
kirill@xxx:test$ git init Инициализирован пустой репозиторий Git в /home/kirill/Yandex.Disk/8.dev/test/.git/ kirill@xxx:test$ git remote add origin git@гит-сервер:OPS/backups/file-backup-scripts.git kirill@xxx:test$ git status На ветке master Еще нет коммитов Неотслеживаемые файлы: (используйте «git add <файл>…», чтобы добавить в то, что будет включено в коммит) file_backup.sh git_backup.sh ничего не добавлено в коммит, но есть неотслеживаемые файлы (используйте «git add», чтобы отслеживать их) kirill@xxx:test$ git add -A kirill@xxx:test$ git commit -m "Initial commit" [master (корневой коммит) e58bc6d] Initial commit 2 files changed, 231 insertions(+) create mode 100644 file_backup.sh create mode 100644 git_backup.sh kirill@xxx:test$ git config user.name "kirill.kazarin" kirill@xxx:test$ git config user.email "kazarin.ka@yandex.ru" kirill@xxx:test$ git status На ветке master нечего коммитить, нет изменений в рабочем каталоге kirill@xxx:test$ git push -u origin master Подсчет объектов: 4, готово. Delta compression using up to 4 threads. Сжатие объектов: 100% (4/4), готово. Запись объектов: 100% (4/4), 1.95 KiB | 1.95 MiB/s, готово. Total 4 (delta 1), reused 0 (delta 0) To гит-сервер:OPS/backups/file-backup-scripts.git * [new branch] master -> master Ветка «master» отслеживает внешнюю ветку «master» из «origin». |
Теперь разберем по пунктам что я сделал:
-
Я проинициализировал или создал пустой ЛОКАЛЬНЫЙ репозиторий
-
Я связал его с удаленным репозиторием на сервере
-
Я узнал статус репозитория и увидел что у меня есть 2 не отслеживаемых файла (заметьте что той ненужной папки в списке нет)
-
Сказал добавить все файлы в обслуживаемые (флаг -А вообще опасная штука. Используйте его только если в выводе команды статус вы видите только те файлы, которые должны попасть в репозиторий и НИКАКИЕ другие. А то так и ключи, и пароли, и много что еще загружали люди в публичные репы)
-
Делаю коммит или фиксацию состояния, сразу добавляя сообщение через флаг -m. Иначе откроется редактор в котором вам нужно будет написать пояснительное сообщение к коммиту. На счет стиля сообщений и как их писать будет ниже.
-
Далее я настроил имя и имейл пользователя, от лица которого эти изменения будут улетать на сервер. Это можно было бы сделать и сразу, после инициализации репозитория. Обратите внимание — я не использовал флаг –global, а значит эти настройки применены только для данного репозитория. Почему я так сделал? Я работаю с большим числом разных гит серверов и на всех у меня разные учетные записи. Я не хочу перенастраивать клиент глобально каждый раз.
-
Я еще раз запросил статус чтобы убедиться что я зафиксировал все что хотел и что я могу отправлять изменения на сервер
-
Я отправил изменения на удаленный сервер, протолкнув (push) их.
Смотрим результат
Итак, возвращаемся в Web интерфейс гитлаба и что мы там видим:
-
Видно кто из пользователей последним ( и как давно) влил изменения.
-
Видим наши два файла и напротив них сообщение нашего коммита. Таким образом виден комментарий последнего изменения файла. Вот почему это важно. По умолчанию тут видно первую строку.
-
Так же видно сколько всего коммитов, сколько веток, какая текущая, сколько форков, Теги и пр пр пр.
Создание веток и слияние
В гите есть понятие веток — это одна из основополагающих концепций и вам ПРИДЕТСЯ ее узнать и полюбить.
Основная идея такова — есть главная ветка, которую обычно зовут «мастер» и ряд других. Например «develop», «staging» и пр. В ряде случаев для имени ветки выбирается имя фичи или изменения над которым в ней работают. Когда разработчик хочет внести изменение в код — он должен «ответвиться» от мастера, поработать, внести свои наработки в свою ветку репозитория, протестировать их и только убедившись что все хорошо (хорошей практикой является демонстрация этих наработок и их тестирования коллегам) — «влить» изменения из своей ветки в мастер.
Такой подход зовется Git Flow и выглядит примерно вот так:
Его мы сейчас и попробуем реализовать (Правда в одно лицо, но для групповой работы схема будет примерно такой же). Мы забыли добавить очень важный файл, который должен являться неизменным атрибутом каждого репозитория — файл README. Как и все git хостинги, Gitlab ищет в каталоге репозитория этот файл и если находит- показывает его содержимое на главной странице репозитория сразу под списком файлов. Gitlab понимаем и умеет рендерить разметку markdown, правда с некоторыми своими условностями, поэтому советую почитать их документацию.
Если Вам лень учить синтаксис или ставить локальный редактор makrdown, или искать плагин к свой ide, воспользуйтесь вот этим сервисом — stackedit.io
Добавим простой файл Readme в котором опишем содержимое проекта:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
kirill@xxx:test$ vim README.md kirill@xxx:test$ cat README.md # Скрипты файлового бекапа Этот репозиторий содержим скрипты для бекапа **файловых ресурсов**. Если нужно делать резервную копию чего то другого, например содержимого БД, эти скрипты **не подойдут!** ## Содержимое Пока что тут только два скрипта - для бекапа произвольного каталога файлов и для бекапа данных gitlab. > **Примечание:** Скрипт для **gitlab** не создает резервную копию gitlab самостоятельно, он лишь вызывает встроенный механизм резервного копирования, создавая ему необходимое окружение - например монтируя и проверяя каталог ## Пример использования Каждый скрипт принимает набор параметров ``` TASK_NAME="$1" SOURCE_DIR="$2" MOUNT_DIR="$3" SMB_SHARE="$4" SMB_USER="$5" SMB_PASSWD="$6" LOG_FILE="backup.log" BACKUP_DATE=$(date +"%m-%d-%y") BACKUP_FILE="$MOUNT_DIR"/cfg/etc_"$TASK_NAME"-backup-"$BACKUP_DATE".tar.gz BACKUP_AGE=7 # delete files older that this value ``` Соответственно чтобы вызвать такой скрипт, добавьте например в cron задачу следующую строку: ```bash /bin/bash file_backup.sh wiki /home/data /home/backup //192.168.100.1/backup_test kirill Qwerty.123 ``` |
Отлично, теперь давайте поработаем с git:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
kirill@xxx:test$ git status На ветке master Ваша ветка обновлена в соответствии с «origin/master». Неотслеживаемые файлы: (используйте «git add <файл>…», чтобы добавить в то, что будет включено в коммит) README.md ничего не добавлено в коммит, но есть неотслеживаемые файлы (используйте «git add», чтобы отслеживать их) kirill@xxx:test$ git checkout -b "add_readme" Переключено на новую ветку «add_readme» kirill@xxx:test$ git status На ветке add_readme Неотслеживаемые файлы: (используйте «git add <файл>…», чтобы добавить в то, что будет включено в коммит) README.md ничего не добавлено в коммит, но есть неотслеживаемые файлы (используйте «git add», чтобы отслеживать их) kirill@xxx:test$ git add README.md kirill@xxx:test$ git commit -m "README file was added" [add_readme a0747f1] README file was added 1 file changed, 30 insertions(+) create mode 100644 README.md kirill@xxx:test$ git push fatal: Текущая ветка add_readme не имеет вышестоящей ветки. Чтобы отправить текущую ветку и установить внешнюю ветку как вышестоящую для этой ветки, используйте git push --set-upstream origin add_readme kirill@xxx:test$ git push --set-upstream origin add_readme Подсчет объектов: 3, готово. Delta compression using up to 4 threads. Сжатие объектов: 100% (3/3), готово. Запись объектов: 100% (3/3), 1.16 KiB | 1.16 MiB/s, готово. Total 3 (delta 0), reused 0 (delta 0) remote: remote: To create a merge request for add_readme, visit: remote: http://гит-сервер/OPS/backups/file-backup-scripts/merge_requests/new?merge_request%5Bsource_branch%5D=add_readme remote: To гит-сервер:OPS/backups/file-backup-scripts.git * [new branch] add_readme -> add_readme Ветка «add_readme» отслеживает внешнюю ветку «add_readme» из «origin». |
Что произошло:
-
Я проверил с помощью команды status — какие изменения ждут моей реакции и что я сейчас нахожусь на ветке master ( еще это можно сделать командой branch)
-
С помощью команды checkout с флагом -b я создал и сразу переключился на новую ветку. Имена веток кстати не могут содержать пробелов и еще много чего, поэтому я обычно использую нижнее подчеркивание. И да, если не использовать -b, мне сначала пришлось бы использовать команду branch чтобы сделать ветку, а только потом команду checkout для переключения.
-
Я добавил файл README в число отслеживаемых
-
И зафиксировал его коммитом
-
После чего я попытался отправить изменения на сервер, на что gitlab ответил что такой ветки у него нет, но он же и подсказал как мне прямо из моего клиента ее создать при отправке
-
Что я и сделал опцией –set-upstream
-
Gitlab успешно принял изменения в новую ветку и сразу сгенерировал мне ссылку, пройдя по которой я могу запустить процедуру слияния (правда он няшка?)
Если мы теперь посмотрим на сервере, мы увидим что у нас появилась новая ветка — в которой присутствует наш файл README ( а в мастере его по прежнему нет):
Кстати и локально вы можете это увидеть ( а заодно потренируетесь в работе с ветками):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
kirill@xxx:test$ tree . ├── file_backup.sh ├── git_backup.sh └── README.md 0 directories, 3 files kirill@xxx:test$ git branch * add_readme master kirill@xxx:test$ git checkout master Переключено на ветку «master» Ваша ветка обновлена в соответствии с «origin/master». kirill@xxx:test$ tree . ├── file_backup.sh └── git_backup.sh 0 directories, 2 files |
Вы можете и дальше работать в этой ветке над новой «фичей» пока не решите что она готова ( в нашем случае она готова сразу) — и просто отсылать свои изменения на сервер в эту ветку, коммит за коммитом.
Но как только вы решили что вам пора «вливаться» в мастер — берем ту самую ссылку про которую я писал выше и проходим по ней ( слияние можно сделать и самому но раз уж нам все дают- почему бы нет):
Перед нами форма оформления «Запроса на слияние» — Merge request:
-
Заполняем описание
-
Выбираем ответственного (в данном случае я выбрал сам себя) — то есть того кто должен будет просмотреть изменения и утвердить что все хорошо, тем самым тоже вписаться в ответственность если изменение привнесет ошибку в код
-
Отмечаем галочку «Remove source branch when merge request is accepted.» — если не хотим чтобы наша ветка существовала на сервер после слияния (нафиг копить мусор)
-
Если есть желание- внизу есть ссылки на коммиты и изменения — мы можем еще раз просмотреть все то что наваяли в красивом виде.
-
Нажимаем «submint merge request»
Получаем Сформированный запрос где жмем кнопку «merge»
Возвращаемся в репозиторий и видим результаты слияния на ветке мастер:
Остается только «подтянуть» у себя результаты слияния в мастер ветку и удалить нашу временную ветку если она более не нужна:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
kirill@xxx:test$ git branch * add_readme master kirill@xxx:test$ tree . ├── file_backup.sh ├── git_backup.sh └── README.md 0 directories, 3 files kirill@xxx:test$ git checkout master Переключено на ветку «master» Ваша ветка обновлена в соответствии с «origin/master». kirill@xxx:test$ tree . ├── file_backup.sh └── git_backup.sh 0 directories, 2 files kirill@xxx:test$ git pull remote: Enumerating objects: 1, done. remote: Counting objects: 100% (1/1), done. remote: Total 1 (delta 0), reused 0 (delta 0) Распаковка объектов: 100% (1/1), готово. Из гит-сервер:OPS/backups/file-backup-scripts e58bc6d..f1ff53e master -> origin/master Обновление e58bc6d..f1ff53e Fast-forward README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 README.md kirill@xxx:test$ tree . ├── file_backup.sh ├── git_backup.sh └── README.md 0 directories, 3 files kirill@xxx:test$ git branch -D add_readme Ветка add_readme удалена (была a0747f1). kirill@xxx:test$ git branch * master |
Что я сделал:
-
Посмотрел список веток и на которой я сейчас ( отмечена звездочкой)
-
Убедился что в этой ветке файл README есть
-
Переключился на мастер
-
Убедился что тут файла нет
-
«Стянул» с сервера актуальную версию мастера командой pull
-
Проверил что файл появился
-
Удалил более не нужную ветку
-
Проверил что в списке веток ее больше нет.
Чего делать НЕ надо
-
Не делайте коммиты «от балды» или лишь бы что то написать. Коммит сообщение — важная штука. Рекомендую ознакомиться вот с этой статьей — как и что делать: Лучшая практика создания Git Commit’ов от OpenStack
-
Не добавляйте в коммит кучу изменений разом — вы усложняете в будущем поиск и исправление проблемных ченджей. Коммит должен быть атомарным, фиксирующим одно логическое изменение. Например Вы изменили css стиль для заголовков( добавили новый цвет и шрифт), поправили скрипт работы с БД и изменили JS для фронтэнда — добавив туда новые кнопки и новый метод. Разбейте это на 4 коммита — css, база, js кнопки и js метод. В той же статье есть хорошие примеры коммитов — Лучшая практика создания Git Commit’ов от OpenStack