Syntax highlighting of itnotes/git

= GIT =

<<TableOfContents()>>

== Полезные команды ==

=== Конфигурация ===

{{{#!highlight bash
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
# --- Установка редактора для коммитов
git config --global core.editor "vim"
# --- Храним доступы в файле ~/.git-credentials
#     Доступы сохраняются там автоматически
git config --global credential.helper store

}}}

=== Ветвление ===

{{{#!highlight bash
# --- удаление веток по шаблону
git branch | egrep "KDK-[0-9]+" | xargs git branch -D
# --- фиксируем изменения из detached-ветки
#      шаблон: git push <remote name> HEAD:<remote branch name>
git push origin HEAD:master
}}}

=== Клонирование и слияние ===

{{{#!highlight bash
# Клонирование крайнего коммита
git clone --depth=1 URL
# "Переход" к конкретному коммиту
git checkout [revision] .
# "Переход" на крайний коммит
git checkout -
# --- слияние со "схлопываением" коммитов
git checkout master
git merge --squash feature123
git commit -m 'merged feature #123'
# --- "перетаскивание файлов между ветками
git checkout gh-pages # переходим в целевую ветку gh-pages
git checkout master -- myplugin.js # "забираем" файл из ветки master
git commit -m "Update myplugin.js from master" # фиксируем изменения

}}}

=== Меняем историю ===

[[https://www.atlassian.com/ru/git/tutorials/rewriting-history/git-rebase|git rebase about|class=" moin-https"]]

{{{#!highlight bash
# --- схлопываем 3 коммита через rebase (в редакторе выбираем squash)
git rebase -i HEAD~3
# --- перетаскиваем коммит в ТЕКУЩУЮ ветку
git cherry-pick <commithash>

# --- удаляем историю
#     источник: https://xebia.com/blog/deleting-your-commit-history/
git checkout --orphan temp_branch
git add -A
git commit -m "Initial commit"
git branch -D main
git branch -m main
git push --force origin main
}}}

=== Журнал и история ===

{{{#!highlight bash
# Список коммитов по автору
git log --author="John Smith"
# история изменений файла
git log -- app/some/file.rb
# отображение изменений конкретного файла
git log --all --full-history -- <path/to/file>
# отображение файла из заданного коммита
git show $REV:$FILE
# поиск по commit сообщению
git log --all --grep='Build 0051'
# вывод журнала в виде графа с изменением формата
git log --pretty="format:%H %s" --graph

}}}

=== Отображение изменений ===

{{{#!highlight bash
# отображение отслеживаемой ветки
git branch -vv
# Отображение хэша крайнего коммита
git rev-parse HEAD
# Отображение всех измененных файлов в текущей и develop ветвях .
# Можно использовать опцию --name-only
git diff --name-status develop
# Отображение измененных файлов только ветви notMainDev
# Если ветвь notMainDev влита, то ничего не выводится
git diff --name-only <notMainDev> $(git merge-base <notMainDev> <mainDev>)
# то же, но короче
git diff --name-only mainDev...
# статусы
#   `A`  Added
#   `C`  Copied
#   `D`  Deleted
#   `M`  Modified
#   `R`  Renamed. Статус может дополняться числом, например R100
#   `T`  have their type (mode) changed
#   `U`  Unmerged
#   `X`  Unknown
#   `B`  have had their pairing Broken
#   `*`  All-or-none

# Отображение изменений коммита
git show <revhash>

}}}

=== Индекс и откат ===

{{{#!highlight bash
# Удаление файла из кэша
git rm --cached some-file
# Удаление директории из кэша
git rm --cached -r some-directory
# remove all files from git cache
git rm -r --cached .
git add .
git commit -m ".gitignore is now working"
# --- откат изменений
git clean -f
git checkout -- *
# Изменение сообщения крайнего коммита
git commit --amend
# Мягкий откат коммита - файлы остаются скорректированными, отменена процедура коммита
git reset --soft HEAD^
# жесткий откат
git reset --hard HEAD^
# отмена индексации, был зеленый - стал красный
git reset HEAD filename

}}}

=== Прячем изменения ===

{{{#!highlight bash
# --- прячем изменения
git stash
# --- список спрятанных изменений
git stash list
# --- "вытащить" спрятанные изменения в текущей ветке
git stash apply
# --- "вытащить" изменения через указания индекса в списке
git stash apply stash@{2}

}}}

=== Метки ===

{{{#!highlight bash
# Создание метки (тэга)
git tag -a 1.0.1 -m "Version 1.0.1"
# Создание метки для коммита
git tag -a 0.2.0 9fceb02 -m "Version 0.2.0"
# Загрузка метки в репозиторий
git push origin 1.0.1
# Удаление метки из локального репозитория
git tag -d 1.0.2
# Удаление метки из удаленного репозитория
git push origin :refs/tags/1.0.2
# Список меток с сообщениями
git tag -l --format='%(tag) %(subject)'
# --- создаем ветку из тега
git fetch --all --tags
git checkout tags/v1.0 -b v1.0-branch

}}}

=== Submodules ===

{{{#!highlight bash
# https://git-scm.com/book/ru/v2/Инструменты-Git-Подмодули
# Добавление подмодуля в проект
git submodule add REPO_URL PATH
# отображение изменений
git diff --cached SUBMODULE
# клонирование репозитория с подмодулями
git clone REPO-URL
cd repo/submodule/dir
git submodule init
git submodule update
# тоже одной командой
git clone --recursive REPO-URL
# обновление модуля
cd submodule/dir
git fetch
git merge origin/master
# --- обновление всех модулей в repo
# @note Если необходимо обновится не из master, то в файле .gitmodules
# в соответствующей секции модуля необходимо добавить branch = ..., напр:
# branch = stable
git submodule update --remote
# отображение изменений в модуле
cd ../repo/root/dir
git diff --submodule
# конфигурация для отображения изменений в модулях командой git diff (без --submodule)
git config --global diff.submodule log

# --- если в проект добавлен git-модуль, то при выполнии git pull
#     будет создана директория для модуля, но она будет пустая.
#     Чтобы ее "заполнить", необхомо выполнить команды
git submodule init
# Подмодуль «.path/or/name/of/submodule» (remote url) зарегистрирован по пути «./»
git submodule update

# cd dir/with/new/git-module
# git submodule init
# Подмодуль «.path/or/name/of/submodule» (remote url) зарегистрирован по пути «./»
# git submodule update
# Клонирование в ...

}}}

[[https://gist.github.com/myusuf3/7f645819ded92bda6677|Удаление submodule|class=" moin-https"]]

 * Delete the relevant section from the .gitmodules file.
 * Stage the .gitmodules changes `git add .gitmodules`
 * Delete the relevant section from .git/config.
 * Run `git rm --cached path_to_submodule` (no trailing slash).
 * Run `rm -rf .git/modules/path_to_submodule` (no trailing slash).
 * Commit `git commit -m "Removed submodule"`
 * Delete the now untracked submodule files `rm -rf path_to_submodule`

== Полезные ссылки ==

[[https://www.conventionalcommits.org/ru/v1.0.0-beta.2/|Conventional Commits|class=" moin-https"]]

https://git-scm.com/book/ru/v2

https://stackoverflow.com/questions/67699/how-to-clone-all-remote-branches-in-git

== Полезные утилиты ==

=== gitk ===

Графический интерфейс для git
https://stackoverflow.com/questions/1786027/how-to-view-file-history-in-git

{{{#!highlight bash
sudo apt install gitk
# show file change histroy
gitk path/to/file

}}}

== Credentials ==

При работе с git по http/https можно зафиксировать имя пользователя и включить временное запоминание пароля.

[[https://stackoverflow.com/questions/10054318/how-to-provide-username-and-password-when-run-git-clone-gitremote-git|StackOverflow|class=" moin-https"]]

{{{#!highlight bash
git config --global credential.helper cache
git config --global credential.https://github.com.username foo
git clone ...

}}}

Глобальная конфигурация

{{{
~/.gitconfig
[color]
    ui = true
[user]
    name = Nik Mikhaylichenko
    email = nn.mikh@yandex.ru
[credential "https://github.com"]
    username = nmix

}}}

Локальная конфигурация

{{{
# .git/config
[user]
    name = Николай Михайличенко
    email = n.mihailichenko@krasnodar.pro
[credential]
    username = zoid

}}}

== Изменение commit message ==

{{{#!highlight bash
git commit --amend
git push --force

}}}

= Troubleshooting =

== fatal: Needed a single revision ==

При обновлении git-модулей для одного из модулей получаем ошибку

{{{#!highlight bash
git submodule update --remote
# ...
fatal: Needed a single revision

}}}

Проблема оказалось в том, что автор модуля toml переименовал ветку master в ветку main
Необходимо прописать наименовании новой ветки в конфигурации модуля

{{{
# .gitmodules
[submodule ".vim/bundle/vim-toml"]
    path = .vim/bundle/vim-toml
    url = https://github.com/cespare/vim-toml.git
    branch = main  # <------------------

}}}

== если что-то не работает ==

`GIT_TRACE=1 GIT_SSH_COMMAND="ssh -vvv" git clone https://git.example.com/my/app.git app`

== sign_and_send_pubkey ==

При попытке залить изменения на сервер, получаем ошибку

{{{#!highlight bash
git push -u origin master 
sign_and_send_pubkey: signing failed: agent refused operation
git@bitbucket.org: Permission denied (publickey).
fatal: Не удалось прочитать из внешнего репозитория.

Удостоверьтесь, что у вас есть необходимые права доступа
и репозиторий существует.

}}}

Ошибка связана с некорректным файлом ''~/.ssh/id_rsa'', либо правами доступа к нему.

{{{#!highlight bash
ssh-add
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/zoid/.ssh/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.

}}}

Необходимо скорректировать права доступа к файлу и повторить операцию

{{{#!highlight bash
chmod 700 .ssh/id_rsa
ssh-add
Enter passphrase for /home/zoid/.ssh/id_rsa:
...
Identity added: ...

}}}