====== Git ======
[[https://git-scm.com/book/ru/v2|Документация]]
===== Общее =====
:!: Сведения
**Git** как таковой opensource-софт, вся работа выполняется **непосредственно в нем**, системы типа **github / gitlab** это общедоступные **хранилища**, в которых можно размещать репозитории для внешнего хранения, софт так или иначе работает прежде всего с **локальным репозиторием** и уже отдельным действием отправляет данные на внешку.\\
**master** главная ветка по умолчанию, создается **первым коммитом**\\
:!: Авторизация\\
Непонятная ситуация с авторизацией, вроде ввели новый способ по токенам, по крайней мере в винде только через него получилось, в линуксе по ssh ключу удалось.. (используется id_rsa.pub)\\
Постоянная конфигурация хранится в файле "~/.bash_profile" (в винде по крайней мере)\\
Для хранения токенов можно использовать:
* windows - командой "**git config --global credential.helper manager-core**"
* linux - "**git config --global credential.helper store**"
Минус в том что хранится в открытом виде, есть варианты **store/cache**, второй хранит 15 минут и только в памяти\\
# Установка\\
apt git install\\
# Инициализация проекта
cd /'project' && git init
# Добавить удаленный репозиторий
git remote add (или origin для репы по умолчанию) https://github/uset/repo
# например
git remote add origin git@github.com:ncily/gh_actions.git
# Отправка проекта
# Добавление файлов к проекту
git add . (file1 file2 ...)
# Фиксация изменений (-m коммент, -a применить ко всем либо к указанным файлам)
git commit -m "Text comment" -a (or changed-file1)
# Отправка на удаленный репозиторий
git push [ветка]
# Скачивание
git pull [origin]
git checkout [master]
# Проверка ключа
ssh -T git@github.com
ssh -vT git@github.com
# Авторизация по SSH
После создания пары ключей SSH вам необходимо добавить открытый ключ на GitHub.com, чтобы включить доступ по SSH для вашей учетной записи
В параметрах уч записи в ГХ, добавляем SSH-ключ, саписываем туда содержимое файла ".ssh/id_rsa.pub" нужно учетки
После этого, проверяем авторизацию командой "ssh -T git@github.com"
:!: Работа с внешними репами
[[https://git-scm.com/book/ru/v2/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B-Git-%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-%D1%83%D0%B4%D0%B0%D0%BB%D1%91%D0%BD%D0%BD%D1%8B%D0%BC%D0%B8-%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D1%8F%D0%BC%D0%B8|Дока]]
git remote [-v]
git remote add (origin для репы по умолчанию)
git remote remove/rename
git remote show
# Отправить изменения
git push [branch]
# Скачать изменения
git pull (или без указания, origin по умолчанию)
git fetch
:!: Ветки
[[https://git-scm.com/book/ru/v2/%D0%92%D0%B5%D1%82%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-Git-%D0%A3%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2%D0%B5%D1%82%D0%BA%D0%B0%D0%BC%D0%B8|Дока]]\\
**Слияние** выполняется из той ветки в которую нужно добавить указанную (переходим в мастер и указываем ветку которую хотим в него добавить)\\
Слияние происходит в точке ответвления, если после ответвления, в источнике, данном месте были изменения, это вызывает конфликт слияния, решать который нужно вручную\\
**Rebase** в целом тоже самое что и слияние, но работает иначе, слияние совмещает последние коммиты веток, а перебазирование вставляет последний коммит в точку ответвления и применяет последовательно всю историю изменений, получается, тем самым делая его обновленной копией последнего коммита в мастере (в которую сливается)\\
[[https://git-scm.com/book/ru/v2/%D0%92%D0%B5%D1%82%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-Git-%D0%9F%D0%B5%D1%80%D0%B5%D0%B1%D0%B0%D0%B7%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5|Дока]]\\
git branch [-v]
# Слитые [не слитые] ветки
git branch --merged [--no-merged] [name]
# Удалить (удалится только слитая ветка, -D для удаления не слитых)
git branch -d
git branch --all
# Переключение веток и загрузка их в рабочий каталог
git checkout <существующая ветка>
git checkout -b <новая ветка>
# История коммитов
git log <имя ветки> <--all>
git log --oneline --decorate --graph --all
:!: Коммиты
# Удалить последний коммит (сдвинуть указатель на шаг назад)
# Удаленный репозиторий может не принять такой прикол, для пуша добавляем --force
git reset --hard HEAD~1 [либо хэш-код]
# Слияние с предыдущим коммитом
git commit --amend
# Разница между текущим состоянием и указанным коммитом
git diff
# Работа с тегами
git push --delete origin refs/heads/
git push --delete origin refs/tags/
git tag -d
Коммит это слепок, содержит **blob (большой бинарный) объект**, и хеш сумму каждого файла, в т.ч. дерево каталогов.\\
Каждый коммит содержит **ссылку на предыдущий** так формируется цепочка.\\
**Ветка** это ничто иное как **условный указатель** на последний коммит, который будет указан родителем следующему. **Master** абсолютно обычная ветка, просто умолчательная и по наитию используется как основная\\
{{ :develop:git0.jpg?direct&500 |}}
**HEAD** это указатель на текущую, локальную ветку, используемую сейчас, увидеть ее можно в команде **git log**\\
| {{ :develop:git1.jpg?direct&600 |}} | {{ :develop:git2.jpg?direct&600 |}} |
При переходе между ветками, **заменяется все содержимое рабочего каталога**, файлы автоматически подменяются\\
:!: Общее/Ошибки/Использование
**.gitignore**\\
В файле просто перечисляются файлы/папки или их шаблоны, которые нужно игнорировать для загрузки, может располагаться в корне\\
Ошибка "git submodule update failed with 'fatal: detected dubious ownership in repository at'"\\
git config --global --add safe.directory '*'
либо в конфиге
[safe]
directory = *
:!: Общие примеры
# Теги (полный путь для тегов, который не пересекается с ветками- :refs/tags/tagname)
git push origin :tagname
git push --delete origin tagname
git tag --delete tagname // удалить локальный тег
# создание тега
./execute_on_all_repos.sh git tag -a "1863.9" -m "1863.9"
# запушить вроде так долджно быть
./execute_on_all_repos.sh git push origin "1863.9"
# Удаление тегов
./execute_on_all_repos.sh git push --delete origin refs/heads/1830
# Удалить удаленную ветку
git push origin --delete 1854_norm
./execute_on_all_repos.sh git push origin --delete 1854_norm
# Удалить локальную ветку
git branch --delete -D 1854_norm
./execute_on_all_repos.sh git branch --delete -D 1854_norm
# Генерирует уникальную строку, на основании последнего тега, с добавлением хеша последнего коммита
# В данном случае для мозговой сборки, вида "1862.1-14-g9f97cdb7dc"
git describe
# Можно задать шаблон для отбора имеющихся тегов, здесь берет мгашный тег, на выходе: "mga.18.0.51129-18-g9f97cdb7dc"
git describe "--match=mga*" --abbrev=8
# Эта команда фильтрует по маске и возвращает перечень имеющихся тегов
git ls-remote --quiet --tags --refs --sort=-version:refname | grep -oP mga.*
git ls-remote --quiet --tags --refs --sort=-version:refname | grep -oP 'refs/tags/\K'
git ls-remote --quiet --tags --refs | grep -oP 'refs/tags/\K\d{4}\.\d+'
// автосгенерированный либо релизный тег
git describe --match=[0-9]* --abbrev=8 | tr -s '\r\n' ' ' | sed 's/ //g'
:!: Интеграция GitHub и Jenkins
[[https://www.blazemeter.com/blog/how-to-integrate-your-github-repository-to-your-jenkins-project|Источник]]\\
:!: SCM (Source Control Management)
Один из вариантов в проекте ГХ создаем вебхук, с указанием адреса дженкинса, указываем по каким событиям отправлять триггер, в дженкинс.\\
Затем в джобе дженкинса, указываем адрес репозитория, в "Build Trigger", "GitHub hook trigger for GITScm polling" и вроде как все\\
В тоже время есть и другие варианты "Build Trigger", возможно в них можно обойтись без вебхука на стороне ГХ и указания адреса дженкинса\\
Так, чтобы работать из репы, нужно код пайплайна разместить там и выбрать "Pipeline script from SCM"
:!: Экспорт из GitLab в GitHub
Работает в т.ч. и как актуализация уже существующего экспорта в GH\\
[[https://stackoverflow.com/questions/22265837/transfer-git-repositories-from-gitlab-to-github-can-we-how-to-and-pitfalls-i|Source]]\\
[[https://github.com/piceaTech/node-gitlab-2-github|Source2]]\\
# from gitLab
git clone --mirror git@your-gitlab-site.com:username/repo.git
cd repo
# to gitHub
git push --no-verify --mirror git@github.com:username/repo.git
:!:
:!: Old
**Общее**
Есть 4 основных элемента: **Рабочий каталог**, **Промежуточная область**, **Локальный репозиторий**, **Удаленный репозиторий**\\
{{:develop:git_0.png?direct&400|}}
* **git add** - добавление файла из рабочего каталога в промежуточную область
* **git commit** - из промежуточной области в локальный репозиторий
* **git push** - загрузка из локального репозитория в удаленный
* **git fetch** - скачивание из удаленного репозитория в локальный
* **git merge** - перенос из локального репозитория в рабочий каталог
* **git pull** - получение удаленного репозитория сразу в рабочий каталог, две предыдущие команды вместе
** Установка **
Нормальный клиент здесь- [[https://gitforwindows.org/]]\\
После установки делаем подпись, в "git bash" пишем:
$ git config --global user.name "YourName"
$ git config --global user.mail "YourMail"
$ git config --global -- list
** Доступ SSH **
Затем настраиваем сертификат, для без парольного доступа.\\
git bash:
# Генерация ключевой пары (можно: -t rsa -b 4096 -C)
$ ssh-keygen -t ed25519 -C "YourEMail"
Вводим имя файла, парольную фразу можно не вводить, чтобы не вводить ее при каждом обращении в git\\
После завершения, файлы будут в домашней директории пользователя, помещаем их в "~/.ssh" \\
закрытый ключ переименовываем в "id_rsa" (тут **неясный момент!**)\\
Содержимое открытого ключа (".pub") копируем при создании ключа в лк git'a, там нужно добавить ключ, с содержанием этого открытого ключа\\
Так же нужно добавить созданных ключ агенту авторизации
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_ed25519
После пишем: **"$ ssh -T git@github.com"** (можно добавить -vT, для расширенного вывода), для принятия сертификата, в ответе должна фигурировать строка типа: "Hi "YourName"! You've successfully authenticated, but GitHub does not provide shell access", если так, тогда все норм\\
** Траблы с тортилой **
При установке стоило совершить один неверный шаг и выбрать тортилу как транспорт, п*зда, от нее нет спасения, работать она не работает, с таким подходом во всяком случае, и сменить никак не удавалось долгое время, в итоге заменил переменную окружения **GIT_SSH**, установил путь к стандартной утилите ("C:\Program Files\Git\usr\bin\ssh.exe") и заработало.\\
** Использование **
Репозитории создаются и далее привязаны к конкретным каталогам, для работы с репозиторием нужно перейти в его каталог.\\
** Инициализация репозитория **
Переходим в созданный каталог: "**$ git init**"\\
** Добавление файлов **
Добавление в промежуточную область: "**$ git add .**"\\
Точка добавит все, можно указать конкретные, либо маску\\
Просмотр состояния: "**git status**"
** Фиксация изменений **
Фиксация изменений в файлах: "**$ git commit -m "text-comment"**"\\
Отмена фиксации: "**$ git reset HEAD~1**"\\
** Удаленный источник **
Добавление: "**$ git remote add origin **"\\
Список доступных: "**$ git remote -v**"\\
** Дополнительно **
# Изменения в файлах:
$ git diff
# История фиксаций:
$ git diff- ????
# Мержинг если есть конфликты коммитов
$ git merge --allow-unrelated-histories
===== Применение =====
:!: Кейсы
**Сборка с незасабмиченным топиком из геррита**\\
Переходим в начальную ветку, например мастер, на вкладке геррите ищем по ИД нужный коммит, важно, нужно начинать с последнего коммита в этом топике, в этот репозиторий, можно посмотреть по порядковому номеру, есть в url\\
Находим последний коммит, чекаутимсяв него, после этого, на вкладке гита, уже будут присутствовать все предыдущие коммиты этого топика, в этой репе\\
Если есть коммиты из другой репы, аналогично, находим последний, чекаутимся, проверяем что в гите есть все предыдущие\\
Создаем ветку, пушим ее\\
:!: Пример слияния репозиториев
Точнее включение одного репозитория в другой, подпроектом\\
# Клонируем тот репозиторий, который будет мержиться
git clone https://github.com/first-repo
cd first-repo
git remote rm origin # На всякий случай отвязываем репозиторий
# Подготавливаем репозиторий: перемещаем всё содержимое репозитория (за исключением папки .git) в отдельную папку, которая и будет подключаться в другой репозиторий
mkdir first_repo
git mv $(ls -A | grep -v first_repo | grep -v .git) first_repo/
git commit -m "prepare repo for merging in main_repo - move all to new subdir"
# Клонируем рядом целевой репозиторий
cd ..
git clone https://github.com/main_repo
cd main_repo/
# Подключаем к нему подготовленный первый репозиторий и вытаскиваем его master в отдельную ветку first-repo
git remote add first-repo ../first-repoe/
git fetch first-repo
git branch first-repo remotes/first-repo/master
# Мержим ветку в локальный master
git merge first-repo --allow-unrelated-histories
git remote rm first-repo
# Проверяем и пушим
git log
git push
:!: Cмена Remote
git remote -v
# View existing remotes
# origin https://github.com/user/repo.git (fetch)
# origin https://github.com/user/repo.git (push)
git remote set-url origin https://github.com/user/repo2.git
# Change the 'origin' remote's URL
git remote -v
# Verify new remote URL
# origin https://github.com/user/repo2.git (fetch)
# origin https://github.com/user/repo2.git (push)
===== =====