DevOps_Tools_Guides
  • Readme
  • Git
  • Docker
  • Ansible
  • Bash
  • Vim
Powered by GitBook
On this page
  • Git
  • Содержание
  • Начало работы
  • Начальная настройка окружения
  • Инициализация репозитория
  • Основы
  • Клонирование репозитория
  • Просмотр текущего состояния
  • Подробный просмотр файлов при изменении
  • Добавление в отслеживаемые файлы
  • Фиксация изменений
  • Игнорирование файлов
  • Удаление файлов
  • Перемещение или переименование файлов
  • История коммитов
  • Работа с удалёнными репозиториями
  • Отправка данных на сервер
  • Получение данных с сервера
  • Тэги
  • Псевдонимы
  • Настройка репозитория
  • Именование коммитов
  • Полезные ссылки
  • Ветвление
  • Создание и просмотр веток
  • Смена ветки
  • Слияние веток
  • Перемещение веток
  • Сравнение слияния и перемещения веток
  • Модели ветвления
  • Инструменты Git
  • Редактирование коммитов
  • Отмена коммитов
  • Отмена изменений при уже отправленном коммите
  • Перенос указателя ветки
  • Восстановление файла к определённому коммиту
  • Откладывание изменений
  • Копирование коммитов
  • Подключение к репозиторию по ssh
  • Подмодули
  • Подпись коммитов
  • Повторное слияние
  • Поиск ошибок
  • Быстрый поиск плохого коммита
  • Просмотр кто написал эту строку
  • Поиск по истории коммитов
  • Администрирование
  • Сборка мусора и оптимизация репозитория
  • Очистка проекта от лишних файлов
  • Журнал действий
  • Массовое изменение истории
  • Целостность объектов
  • Запуск сервера
  • Внутреннее строение Git
  • Blob
  • Tree
  • Commit
  • Tag
  • References
  • Низкоуровневые команды
  • Просмотр объекта

Git

PreviousReadmeNextDocker

Last updated 1 year ago

Git

Содержание

Начало работы

Начальная настройка окружения

Для начальной конфигурации репозитория требуется установить имя и email для репозитория. Опция --global используется для настройки всех репозиториев текущего пользователя.

git config --global user.name "<your-name>"
git config --global user.email "<your-email>

Инициализация репозитория

Инициализация репозитория git в текущей директории, в результате будет создана специальная директория .git со всеми настройками git-репозитория.

git init

Основы

Клонирование репозитория

Команда для клонирования репозитория с сервера.

git clone <url>

Если требуется склонировать в другую директорию, то вторым параметром указывается путь к директории.

git clone <url> <path>

Для клонирования определённой ветки, нужно указать через флаг -b.

git clone -b <branch-name> <url>

Примеры:

Клонирование репозитория по https.

git clone https://github.com/torvalds/linux.git

Клонирование в определённую директорию.

git clone https://github.com/torvalds/linux.git ./my-linux

Клонирование определённой ветки в определённую директорию.

git clone -b new_linux https://github.com/torvalds/linux.git ./my-linux

Просмотр текущего состояния

Проверка текущего состояния всех файлов.

git status

При любом изменении состояния файлов, и их содержимым, status будет выдавать всю подробную информацию.

Если требуется получить краткий отчёт можно воспользоваться опцией --short или -s.

git status -s

Так же рядом с файлами будут показаны в каком сейчас файлы формате.

  • ?? - неотслеживаемый файл.

  • A - добавлен в отслеживаемые файлы.

  • M - модифицированный файл.

  • D - удалённый файл.

  • R - переименованный файл.

Подробный просмотр файлов при изменении

Для просмотра изменений в файлах используется diff.

Опции:

  • staged - посмотреть что из проиндексированного войдёт в коммит.

  • check - проверка пробелов в конце строки. (если они будут, тогда будут подсвечиваться красным).

Примеры:

Просмотр изменений файлов от последнего коммита.

git diff

Просмотр проиндексированных изменений.

git diff --staged

Просмотр изменений определённого файла.

git diff <file-name>

Проверка на наличие лишних пробелов в коде.

 git diff --check

Сравнение изменений веток.

git diff <branch-1> <branch-2>

Сравнение изменений определённого файла между ветками.

git diff <branch-1> <branch-2> <file-name>

Сравнение по коммиту.

git diff <hash-commit-1> <hash-commit-2>

Сравнение изменений определённого файла между коммитами.

git diff <hash-commit-1> <hash-commit-2> <file-name>

Добавление в отслеживаемые файлы

Для того чтобы начать отслеживать новый файл.

git add <file-name>

Если же добавляется директория, то все файлы находящиеся в ней будут так же добавлены в отслеживаемые.

Добавление всех изменений в репозитории.

git add -A

Добавление только созданных и измененных файлов, а не удаленных.

git add .

Добавление только удаленных и измененных файлов, а не новых созданных.

git add -u

Если требуется добавить изменения по частям используется флаг -p. После исользования, открвывается интерактивный режим для принятия решения добавлять в индекс это изменение или нет.

git add -p <path-file>
git add -p .
  • y - разместить этот фрагмент.

  • n - не размещать этот фрагмент.

  • q - выйти; не размещать этот фрагмент или любой из оставшихся.

  • a - разместить этот фрагмент и все последующие фрагменты в файле.

  • d - не размещать этот фрагмент и все последующие фрагменты в файле.

  • e - вручную отредактировать текущий фрагмент.

  • / - поиск фрагмента.

  • j - оставить этот фрагмент неопределенным, посмотреть следующий неопределенный фрагмент.

  • J - оставить этот фрагмент нерешённым, перейти на следующий фрагмент.

  • k - оставить этот фрагмент неопределенным, смотреть на предыдущий неопределенный фрагмент.

  • K - оставить этот фрагмент нерешенным, смотреть на предыдущий фрагмент.

  • s - разбить текущий кусок на более мелкие куски.

  • e - вручную отредактировать текущий фрагмент.

  • ? - показать справку.

Примеры:

Добавление файла.

git add README.md

Добавление директории и находящийхся в ней файлов.

git add docs/

Добавление только одного файла в директории.

git add docs/Git.md

Фиксация изменений

Фиксация измений.

git commit

После команды откроется текстовый редактор, установленный по умолчанию. Где требуется дать комментарий коммиту.

Если нужна более подробная информация об изменениях.

git commit -v

Так же можно задать сообщение об фиксации и в самой команде, без открытия текстового редактора.

git commit -m "<comment>"

Выполнение коммита со всеми изменениями в рабочем каталоге.

git commit -a

Для изменения сообщения последнего коммита используется флаг --amend.

git commit --amend

Изменение сообщения последнего коммита, без редактора.

git commit --amend -m "<new-comment>"

Если был сделан коммит, но после этого потребовалось добавить в последний коммит какие-то изменения так же используется флаг --amend.

git commit -m "<old-commit>"            # создание коммита
git add <file-name>                     # добавление изменений
git commit --amend -m "<new-commit>"    # фиксация в последний коммит

Если был добавлен или изменён файл, и при этом не требуется менять имя коммита дополнительно используется флаг --no-edit.

git commit --amend --no-edit

Для создания коммита с определённой датой используется флаг --date.

git commit --date="<your-date>"

Для создания коммита с определённым автором используется флаг --autor.

git commit --author="Name <exemple_email@exemple.com>"

Создание пустого коммита - коммита без изменений.

git commit --allow-empty -m "<message>"

Примеры:

Коммит файла.

git add file.txt
git commit -m "add file.txt"

Добавление файла в последний коммит.

git add file.txt
git commit --amend --no-edit

Создание коммита с определённой датой (27.10.2022 16:31:15).

git commit --date="2022-10-27 16:31:15"

Игнорирование файлов

Иногда нужно чтобы некоторые файлы, группа файлов или директории не добавлялись в репозиторий. Обычно в эту категорию попадают автоматически генерируемые файлы и файлы содержащие конфидициальную инфромацию.

Команда для создания такого файла.

touch .gitignore

Составление .gitignore файла.

# комментарий – это игнорируется
*.a # пропускаются файлы, заканчивающиеся на .a
*.[oa] # пропускаются файлы, заканчивающиеся на .a или .o
!lib.a # при указанном *.a, файл lib.a, будет всё равно отслеживаться
/file # игнорируется корневой файл
build/ # игнорировать все файлы в этой директории
doc/*.txt # игнорируются все файлы .txt в директории doc, но не в doc/.../file.txt
dir/**/debug.log # ** - Две звездочки соответствуют множеству каталогов или ни одному

Для просмотра файлов которые игнорируются в текущем проекте.

git ls-files --others --ignored --exclude-standard

Можно создать глобальный gitignore.

git config --global core.excludesFile ~/.gitignore

Удаление файлов

Команда git rm позволяет удалить файл и сразу добавить это его в индекс.

git rm <file-name>

Если требуется удалить из отслеживаемых файлов, но не удалять с файловой системы, то нужно использовать опцию --cached.

git rm --cached <file-name>

Если файл был изменён, но всё равно требуется его удалить, то добавляется опция --force или -f.

git rm -f <file-name>

Если нужно посмотреть какие файлы будут удалены, но не удалять их, то используется опция --dry-run или -n.

git rm --dry-run <file-name>

Примеры:

Удаление всех файлов с расширением .txt.

git rm *.txt

Перемещение или переименование файлов

Переименование файла или директории.

git mv <old-file-name> <new-file-name>

Перемещение файла или директории.

git mv <file-name> <path-to-file-name>

Примеры:

Переименование файла.

git mv Git.md Docker.md

Перемещение файла в другую директорию.

git mv Git.md docs/Git.md

История коммитов

Команда для просмотра истории коммитов. Первыми выводятся самые свежие коммиты.

git log

Для того чтобы посмотреть только 3 последних коммита, нужно использовать опцию -n.

git log -n <count-commits>

Для получения краткой характеристики используется опцию --stat.

git log --stat

Самое подробное представление истории коммитов. Показывает какие изменения были сделаны в каждом файле.

git log -p

Показывает изменённые файлы в данном коммите.

git log --name-status

Поиск по коммитам.

git log --grep="<pattern>"

Показывает коммиты по определённому автору.

git log --author="<author>"

Параметр --pretty определяет формат вывода информации.

git log --pretty=oneline

Стандартные параметры для pretty.

  • oneline

  • short

  • full

  • fuller

Так же можно определять свой вывод информации.

git log --pretty=format:"%h - %an, %ar : %s"

Самые распространённые параметры форматирования.

Параметр
Описание

%H

Хэш-код коммита

%h

Сокращенный хэш-код коммита

%T

Хэш-код дерева

%t

Сокращенный хэш-код дерева

%P

Хэш-код родительских коммитов

%p

Сокращенный хэш-код родительских коммитов

%an

Имя автора

%ae

Электронная почта автора

%ad

Дата создания оригинала

%ar

Дата создания оригинала, в относительной форме

%cn

Имя создателя версии

%ce

Электронная почта создателя

%cd

Дата создания версии

%cr

Дата создания версии в относительном формате

%s

Комментарий

Вывод коммитов с историей ветвлений и слияний.

git log --graph

Очень удобная команда, которая выводит дерево всех коммитов.

git log --all --decorate --oneline --graph

Команда для просмотра что было изменено в определённом коммите.

git show <hash-commit>

Работа с удалёнными репозиториями

Отображение удалённых репозиториев.

git remote

Посмотреть адреса, для сокращенного имени.

git remote -v

Создание нового подключения к удаленному репозиторию.

git remote add <remote-server-name> <url>

Удаление подключения к удаленному репозиторию с именем.

git remote rm <remote-server-name>

Переименование удаленного подключения с имени.

git remote rename <old-name> <new-name>

Изменение адреса, для определённого имени.

git remote set-url <remote-server-name> <url>

Просмотр удалённого репозитория.

git remote show <remote-server-name>

Отправка данных на сервер

Отправка данных на удалённый сервер. Если имя удалённого сервера origin, при отправке можно не указывать. Так же если вы находитесь в ветке, которую требуется отправить, то её можно тоже не указывать.

git push <remote-server-name> <branch-name>

Удаление удалённой ветки с сервера.

git push <remote-server-name> --delete <branch-name>

Получение данных с сервера

Команда git fetch - скачивает коммиты в специальные ветки.

Для просмотра удалённых веток.

git branch -a

Ветки будут помечены по стандарту красным цветом и выглядят - remotes/<remote-server-name>/<branch-name>.

Извлечение всех веток из репозитория.

git fetch <remote-server-name>

Извлечение определённой ветки.

git fetch <remote-server-name> <branch-name>

Извлечение всех зарегистрированных удаленных репозиториев и их веток.

git fetch --all

Опция --dry-run выводит на экран действия, которые были бы выполнены при извлечении, не выполняя их на самом деле.

git fetch --dry-run

Если после загрузки с определённого сервера появилась новая ветка, можно её переместить в свою ветку.

git checkout -b <branch-name> <remote-server-name>/<branch-name>

Команда git pull - это git fetch + git merge. При её использовании происходит скачвание данных с сервера и автоматичское слияние.

Скачать данные с удалённого сервера.

git pull <remote-server-name> <branch-name>

Если нужно скачать текущую ветку и с сервера origin.

git pull

При отправке данных git push, может произойти конфликт, что на удалённом репозитории уже были добавлены коммиты. Для этого нужно сначала скачать изменения, и только потом отправить их.

git pull <remote-server-name> <branch-name>
git push <remote-server-name> <branch-name>

Если были локальные коммиты, и на удалённом сервере тоже были сделаны коммиты, то при обычном pull, будет сделан мердж-коммит. Чтобы избавиться от него, требуется использовать опцию --rebase. При этой опции локальный коммит окажется поверх новых коммитов с сервера, а мердж-коммита не будет.

Если идёт командная работа, то лучше всегда использовать опцию --rebase, при взятии изменений.

git pull --rebase <remote-server-name> <branch-name>

Тэги

Тэги позволяют помечать определённые коммиты как важные. Как правило,используют это для пометки выходящих версий (v1.0 и т.п.).

Просмотр всех тегов.

git tag

Просмотр тегов по шаблону.

git tag -l "v1.*"

Есть 2 типа тегов, легковесные и аннотируемые теги. Легковесные это просто указатель на определённый коммит. Аннотируемые теги хранятся в базе уже как полноценный объект. Они содержат имя человека, поставившего тег, адрес его электронной почты и дату создания и пр.

Создание легковесных тегов.

git tag <tag-name>

Создание аннотируемых тегов. Если не указать опцию -m то открывается редактор, и чтобы ввести тег.

git tag -a <tag-name> -m "<comment>"

Просмотр определённого тега.

git show <tag-name>

Так же тэг можно поставить на определённый коммит.

 git tag -a <tag-name> <hash-commit> -m "<commit-tag>"

Отправление тегов на удалённый сервер.

git push origin <tag-name>

Отправка нескольких тегов сразу.

git push origin --tags

Удаление тега.

git tag -d <tag-name>

Псевдонимы

Можно задавать псевдонимы определённым командам.

Как пример можно задать длинным командам их псевдонимы.

git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status

Так же можно вводить псевдонимы для тех команд которых не хватает.

Например, вывод последнего коммита.

git config --global alias.last "log -1 HEAD"

Настройка репозитория

Посмотреть все опции команды.

git config

Есть 3 уровня конфигурации:

  • --local - локальный уровень, стоит по умолчанию, применяется к одному текущему репозиторию.

  • --global - глобальный уровень, применяется к пользователю для всех его репозиториев.

  • --system - системный уровень, применяется ко всем настройкам машины. Охватывает всех пользователей операционной системы.

Глобальные настройки для определённого пользователя обычно лежит по пути ~/.gitconfig.

Команда для просмотра заданных уже настроек.

git config --list

Команда для просмотра определённой настройки.

git config user.name

Настройка имени пользователя.

git config --global user.name "<name>"

Настройка email адреса пользователя.

git config --global user.email "<email-address>"

Выбор редактора кода по умолчанию.

git config --global core.editor <editor>

При команде git pull очень часто используется опция --rebase, настройка для автоматического использования этой опции.

git config --global pull.rebase true

Автоматическое исправление опечаток, будет автоматически предложена команда с исправлением.

git config --global help.autocorrect 1

Возможность сохранить имя и пароль в незашифрованном виде и использовать его при отправке коммитов на удалённый сервер.

git config --global credential.helper store

Команда git init по стандарту создаёт ветку master, если требуется изменить создаваемую ветку по стандарту.

git config --global init.defaultBranch <branch-name>

Моя настройка для удобного отображения дерева коммитов.

git config --global alias.tree "log --all --decorate --oneline --graph"

Именование коммитов

История коммитов это очень важная документация, которая документирует историю работы разработчков.

Именование коммитов нужно для понимания разработчикам, что было сделано в данном коммите.

В начале коммита устанавливается тип коммита.

  • test - указывает на любое создание или изменение кода тестов.

  • feat - указывает на разработку новой функции для проекта.

  • refactor- используется, когда происходит рефакторинг кода, не влияющий на логику/правила системы.

  • style - используется при изменениях форматирования и стиля кода, которые никак не меняют систему.

  • fix - используется при исправлении ошибок, которые порождают баги в системе.

  • chore - указывает на изменения в проекте, которые не влияюкт на систему или тестовые файлы. Это изменения, связанные с разработкой. Примеры: изменение правил для eslint, добавление prettier, добавление расширений файлов в .gitignore.

  • docs - используется при изменениях в документации проекта.

  • build - используется для указания изменений, которые влияют на процесс сборки проекта, или внешних зависимостей.

  • perf - указывает на изменение, которое улучшает производительность системы.

  • ci - используется для указания на изменения в конфигурационных файлах CI.

  • revert - указывает на отмену предыдущего коммита. Так же тип коммита позволяет более удобно использовать поиск по коммитам.

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

Ветвление

Создание и просмотр веток

Ветвление в git одна из самых важный знаний, для работы с репозиторием. Ветка - это указатель на определённый коммит.

Показать текущие ветки.

git branch

Создать ветку от текущей ветки.

git branch <new-branch>

Создание ветки от определённой ветки.

git branch <new-branch> <base-branch>

Если требуется указать ветку на определённый коммит.

git branch <branch-name> <hash-commit>

Если ветка уже создана нужно использовать флаг -f.

git branch -f <branch-name> <hash-commit>

Безопасное удаление ветки, если ветка не смёрджена, то она не будет удалена.

git branch -d <branch-name>

Принудительное удаление ветки.

git branch -D <branch-name>

Показать больше текущей информации о ветках, показывает последний сделанный коммит.

git branch -v

Показать на сколько опережает или отстаёт ветка от удалённого репозитория.

git branch -vv

Информация о всех ветках, включая удалённые.

git branch -a

Просмотр удалённых веток.

git branch -r

Так же можно использовать опции --merged - показывает ветки объединённые с текущей, и --no-merged - ветки которые не слиты в другие ветки.

git branch --merged
git branch --no-merged

Примеры:

Создание ветки.

git branch feature

Создание ветки на определённый коммит.

git branch feature fd85dd7

Удаление ветки.

git branch -d feature

Смена ветки

Команда для смены ветки.

git checkout <branch-name>

Смена веток так же приводит к смене файлов в рабочей директории.

Можно создать ветку и перейти в неё с помощью одной команды.

git checkout -b <new-branch>

Так же существует более новая команда для смены ветки switch.

Смена ветки.

git switch <branch-name>

Создать ветку и перейти в неё.

git switch -c <branch-name>

Примеры:

Создание ветки.

git checkout -b feature

Смена ветки.

git checkout master

Перемещение на определённый коммит.

git checkout 977baff

Слияние веток

Слияние - соединение двух веток.

Есть 2 типа слияния:

  1. fast-forward - слияние перемоткой.

Если была история веток, где от одной ветки сделана другая, и в этой ветки не было других коммитов.

o---o  master
     \
      o---o---o---o---o  feature

Тогда при слиянии будет сделана перемотка коммитов и получится такая история при слиянии.

o---o---o---o---o---o---o  master,feature

2) 3 way merge - трёхэтапное слияние.

Когда ветки разошлись, быстрого слияния не получится сделать.

o---o---o---o---o  master
     \
      o---o---o---o---o  feature

Для мерджа используется три коммита для создания слияния: два кончика ветвления и их общий предок.

Итог слияния:

o---o---o---o---o-------o  master, feature
     \                 /
      o---o---o---o---o

Для того чтобы смерджить 2 ветки, требуется перейти в ветку которую будет происходить мердж и дальше произвести слияние ветки.

git checkout <branch-name>
git merge <merged-branch-name>

Конфликты при слиянии.

Процесс слияния далеко не всегда проходит гладко. Если в двух ветках, которые сливаются, были внесли разные изменения в один и тот же файл, Git не cможет просто взять и объединить их. При слиянии появляется конфликт.

Чтобы посмотреть какие файлы имеют конфликт.

git status

При открытии файла который вызвал конфликт, система самостоятельно помечает места где вызван конфликт.

Пример:

<<<<<<< HEAD
qwerty
=======
123456
>>>>>>> new

Для решения конфликта, требуется вручную отредактировать файл, и дальше произвести коммит изменений.

Если написать git commit то git самостоятельно сгенерирует комментарий о мерже и останется только подтвердить коммит.

При возникновении конфликта можно отменить слияние.

git merge --abort

Если при мердже будет ускоренное слияние, но для истории коммитов требуется вариант 3 way, тогда можно использовать опцию --no-ff. Будет создан коммит слияния, без перемотки.

git merge --no-ff <branch-name>

До слияния.

o---o  master
     \
      o---o---o---o---o  feature

После слияния.

o---o-------------------o  master, feature
     \                 /
      o---o---o---o---o

Если в ветке было много коммитов, и эти коммиты не требуется отображать в релизе. Можно применить флаг --squash. После этого потребуется указать общий коммит для слияния.

git merge --squash <branch-name>

Перемещение веток

Перемещение - перенос всех коммитов определённой ветки, с одного коммита на коммит/коммиты выше от наследуемой ветки.

Для перемещения одной ветки в другую, требуется сначала перейти в ветку которую нужно переместить, а потом указать ветку в которую нужно переместить.

git checkout <rebased-branch-name>
git rebase <branch-name>

Можно переместить ветку, при этом находясь в другой ветке.

git rebase <branch-name> <rebased-branch-name>

При возникновении конфликта перемещения коммитов, требуется разрешить конфликт и перейти на следующий коммит.

Переход на следующий коммит.

git rebase --continue

После перемещение ветки, можно выполнить перемотку ветки куда происходило перемещение.

git checkout <branch-name>
git merge <rebased-branch-name>

Если ветка больше не нужна, её можно удалить.

git branch -d <rebased-branch-name>

При возникновении конфликта можно отменить перемещение.

git rebase --abort

Пример:

Начальная история версии.

 o---o---o---o---o  master
      \
       o---o---o---o  feature

Для перемещения требуется перейти в ветку feature.

git checkout feature

И запустить перемещение.

git rebase master

Если произошли конфликты решить их.

После этого история будет выглядеть так.

 o---o---o---o---o  master
                  \
                   o---o---o---o  feature

Если требуется переместить указать master на feature.

git checkout master
git merge feature

Дальше стало так.

 o---o---o---o---o---o---o---o---o  feature, master

И если ветка feature не нужна - удалить её.

git branch -d feature

Для трудного перемещения используется флаг --onto.

o---o---o---o---o  master
     \
      o---o---o---o---o  feature_1
           \
            o---o---o  feature_2

feature_2 основан на feature_1, и для того чтобы переместить feature_2 к master.

git rebase --onto master feature_1 feature_2

Дерево веток после перемещения.

                  o---o---o  feature_2
                 /
o---o---o---o---o  main
     \
      o---o---o---o---o  feature_1

Сравнение слияния и перемещения веток

Есть два вида соединения веток - слияние и перемещение, что лучше?

rebase:

Плюсы:

  • Упрощает историю - при каждом слиянии веток образуется дополнительный коммит о слиянии, что для истории коммитов плохо. Так же если слияние происходит часто получается пачка пустых коммитов о слиянии.

Минусы:

  • Если работа ведётся не одним человеком, то может произойти ситуация когда один разработчики переместил ветку выше, а другой ещё не перешёл на неё и при этом сделал какие-то изменения в старой версии - очень трудно потом восстанавливаться.

  • Возможны ошибки в коммитах - если в старой версии использовался метод Hello, а потом он изменился на HelloSay и при этом может не обнаружится этого, то все коммиты которые были перемещены будут "битые", так же на них будет очень плохо делать откат.

Это можно частично исправить если есть какие-либо тесты. Их можно пртестировать перед перемещением, и если будет ошибка то об этом будет сообщаться, и rebase будет ждать действий для исправления.

git rebase -x '...' master

merge:

Плюсы:

  • При мердже и не плохом коммите, будет повреждён только один коммит, и при этом оставшиеся коммиты будут целы.

Минусы:

  • При многочисленном мердже появляется куча бесполезных коммитов, что затрудняет историю коммитов и разработку.

Использовать rebase и merge нужно в правильных ситуациях. Считается, что rebase для приватных веток, когда изменения не выложены, и не будет конфликтов с другими разработчиками при перемещении. А merge лучше использовать когда уже над веткой работают несколько разработчиков.

Модели ветвления

GitFlow

  • main / master - Ветка, где один коммит является релизом выпускаемый в prod. Обычно на него могут давать тег.

  • develop / dev - Ветка, для ведения разработки и объединение всех функций.

  • feature - Ветки, которые начинаются от develop, и в них разработаевается какая-то новая фича.

  • release - Ветка, для подготовки релиза, перед пушем в main.

  • hotfix - Ветка предназначена для быстрого исправления ошибок в main.

Пример:

o-----------------------------------o  main
 \                                 /
  \                       o---o---o  release
   \                     /         \
    o---o---------------o-----------o  dev
         \             /
          o---o---o---o  feature

После создания ветки release и слияния с main, требуется также слить изменения в dev.

Если в main ветке происходит критическая ошибка, то требуется создать ветку hotfix. После изменений, изменения требуется слить и в main и в develop.

o-----------o  main
 \         /
  o-------o  hotfix
   \       \
    o-------o  dev

GitHubFlow

Облегчённая версия GitFlow, отсутствуют ветки dev, release, hotfix.

main / master - являются конечными ветками.

Пример:

o---------------o  main
 \             /
  o---o---o---o  feature

От main создаётся ветка feature, в которой разрабатывается новая фича, и после этого сразу идёт слияние в main.

GitLabFlow

Очень похожый вариант с GitHubFlow, но ветка main, не является конечной веткой.

Появляются такие ветки:

  • staging - опциональная ветка, первый рубеж тестирования.

  • pre-production - опциональная ветка, второй рубеж тестирования.

  • production - обязательная ветка, из которой происходит деплой проекта.

Пример:

o-------------------o prod
 \                 /
  o---------------o  main
   \             /
    o---o---o---o  feature

Trunk Based Development

Полностью схожая идея с GitHubFlow, только ветки feature должны иметь жизнь не более 1-2 дней.

Инструменты Git

Редактирование коммитов

Редактирование последнего коммита

Для редактирования сообщения последнего коммита.

git commit --amend

Если требуется добавить изменения каких-то файлов в последний коммит.

git add <file-name>
git commit --amend

Если требуется добавить и при этом не изменять сообщение коммита.

git add <file-name>
git commit --amend --no-edit

Редактирование сообщения нескольких коммитов

Для редактирования нескольких коммитов используется команда rebase.

Команда для того чтобы отредактировать более ранний коммит или коммиты.

git rebase -i HEAD~10

В данном варианте будут выведены на экран последние 10 коммитов.

Так же можно задать диапазон коммитов.

git rebase -i <hash-commit-1> <hash-commit-2>

Дальше открывается текстовый редактор, где можно указать с какие коммиты нужно отредактировать. Коммиты будут отображаться в обратном порядке (в отличии от git log) - сначала старые, потом новые.

pick 8754de7 1 commit
pick 408c784 2 commit
pick ec467ea 3 commit
pick ec1f912 4 commit

pick - использовать данный коммит, т.е. он будет использоваться как он есть.

Чтобы отредактировать сообщение нужно pick заменить на reword.

pick 8754de7 1 commit
reword 408c784 2 commit
reword ec467ea 3 commit
pick ec1f912 4 commit

Дальше требуется сохранить файл и выйти, и после этого каждый раз будет открываться редактор, для смены коммитов.

Если же выбрать edit, то будет происходить переход на каждый коммит, и мможно будет вручную отредактировать комммит и/или изменить файлы.

После редактирования коммита можно перейти на следующий коммит.

    git rebase --continue

Объединение коммитов

Сначала нужно вывести коммиты, которые нужно объединить.

git rebase -i HEAD~5

Вывод команды.

pick 8754de7 1 commit
pick 408c784 2 commit
pick ec467ea 3 commit
pick ec1f912 4 commit
pick 8871386 5 commit

Для того чтобы объединить коммиты нужно заменить pick на squash у более позднего коммита, для объединения с более старым.

Если требуется обединить коммиты 2 commit и 3 commit, требуется у коммита 3 commit поменять pick на squash.

pick 8754de7 1 commit
pick 408c784 2 commit
squash ec467ea 3 commit
pick ec1f912 4 commit
pick 8871386 5 commit

Или, если нужно объеденить несколько коммитов. В данном примере объединяются коммиты 2 commit, 3 commit и 4 commit. Коммит будет объединяться с предыдущим своим коммитом.

pick 8754de7 1 commit
pick 408c784 2 commit
squash ec467ea 3 commit
squash ec1f912 4 commit
pick 8871386 5 commit

Дальше, после сохранения, снова откроется текстовый редактор, чтобы задать сообщение общего коммита.

Всё, что помечено "#", является комментарием.

Было:

# This is a combination of 3 commits.
# The first commit's message is:

commit 1

# This is the 2nd commit message:

commit 2

# This is the 3rd commit message:

commit 3

Стало:

new commit squash

Смена коммитов местами

Для изменения порядка следования коммитов, так же применяется rebase. Для начала требуется открыть список коммитов, которые мы хотим изменить.

git rebase -i HEAD~3

И внутри уже просто поменять местами коммиты которые нам нужны.

Было:

pick 1e09d8d commit 1
pick a747cf7 commit 2
pick 914847a commit 3

Стало:

pick 1e09d8d commit 1
pick 914847a commit 3
pick a747cf7 commit 2

Но если в коммитах были какие-то общие изменения, то будет конфликт, который нужно будет решить.

Либо же можно отменить изменения.

git rebase --abort

Варианты использования

Все варианты команд для rebase.

  • p, pick - использовать коммит.

  • r, reword - использовать коммит, но отредактировать сообщение фиксации.

  • e, edit - использовать коммит, но остановить для внесения поправок.

  • s, squash - использовать коммит, но объединить с предыдущим коммитом.

  • f, fixup - как "сквош", но отбросить сообщение журнала этого коммита.

  • x, exec <command> - выполнить команду (остальная часть строки) с помощью оболочки.

  • b, break - остановиться здесь.

  • d, drop - удалить коммит.

  • l, label <label> - пометить текущую HEAD.

  • t, reset <label> - сбросить HEAD на метку.

Отмена коммитов

reset - универсальный инструмент для отмены изменений.

По умолчанию при вызове команды git reset используются неявные аргументы --mixed и HEAD.

Поэтому эти две команды одинаковы.

git reset
git reset --mixed HEAD~
  • --soft - отменяются коммиты, до указанного, но при этом файлы, которые были изменены в этих коммитах, остаются и все их изменения. И так же они добавлены в отслеживаемые файлы.

  • --mixed - отменяются коммиты, до указанного, изменённые файлы сохраняются, но не добавлены в отслеживаемые.

  • --hard - отменяются коммиты, до указанного, и при этом файлы не сохраняются.

Если требуется удалить коммит с удалённого репозитория, то требуется откатиться сначала на локальном репозитории, и дальше отправить их на удалённый.

git reset --hard HEAD~1
git push --force

Примеры:

Откатить 2 последних коммита, и оставить изменения.

git reset --soft HEAD~2

или

git reset --mixed HEAD~2

Удалить 2 последних коммита.

git reset --hard HEAD~2

Отмена изменений при уже отправленном коммите

Если коммит уже был сделан и отправлен коллегам, то удалять такой коммит будет не лучшим решением. Т.к. далее уже на его основе могут быть сделаны изменения других людей.

Для того чтобы исправить такую ситуацию, можно использовать revert. Он делает новый коммит который отменяет все сделанные изменения. С одной стороны это очень плохо - загрязняет историю, но с другой, может быть одним из выходов в данной ситуации.

Отмена последнего коммита.

git revert HEAD

Отменить любой коммит можно по хэшу коммита, но может случиться конфликт, который потребуется решить самостоятельно.

git revert <hash-commit>

Можно отменять несколько коммитов.

git revert <hash-commit-1>..<hash-commit-3>

Если требуется посмотреть изменения предыдущих коммитов, но не делать коммит о отмене, можно воспользоваться флагом -n.

git revert -n <hash-commit>

Перенос указателя ветки

Принудительный перенос ветки на определенный коммит.

git branch -f <branch-name> <hash-commit>

Либо же если нужно перенести ветку на другую ветку, сначала указывается ветка которую переносим, потом на какую переносим. Так же вместо ветки можно указать коммит.

 git checkout -B <branch-name-1> <branch-name-2>
 git checkout -B <branch-name> <hash-commit>

Восстановление файла к определённому коммиту

Если файл был удалён или изменён и требуется вернуть его к последнему коммиту.

git restore <file-name>

Для возвращение файла к определённому коммиту.

git restore --source=<hash-commit> <file-name>

Чтобы убрать файл из отслеживаемых файлов, но не убирать его изменения.

git restore --staged <file-name>

Откладывание изменений

Если были сделаны изменения в файлах, и нужно изменить ветку, при этом не сделав коммит, можно воспользоваться операцией stash. Операция stash берёт изменённые файлы каталога и сохраняет их в хранилище, которые можно применить в любое время.

Для того чтобы припрятать изменения, после этого можно увидеть что изменений нет.

git stash

Чтобы посмотреть список припрятанных изменений.

git stash list

Так же можно добавить сообщение при откладывании изменений.

git stash -m "<message>"

Чтобы вернуть припрятанные изменения. При этом внесённые изменения будут оставаться в хранилище даже после возвращения.

git stash apply stash@{<index>}

C опцией --index, команда попытается восстановить изменения в индексе.

git stash apply --index stash@{<index>}

Для удаления изменения из хранилища.

git stash drop stash@{<index>}

Для того чтобы вернуть изменения и сразу удалить из архива используется команда.

git stash pop stash@{<index>}

При опции --keep-index будут припрятаны изменения, но и при этом будут оставлены в индексе.

git stash --keep-index

При опции --include-untracked или -u, будут спрятаны так же и все не отслеживаемые файлы.

git stash --include-untracked
git stash -u

При опции --patch, будет запущен интерактивный режим, в котором по каждому файлу спросят, нужно ли его припрятать или нет.

git stash --patch

Так же можно изменения вынести в новую ветку.

git stash branch <new-branch-name> stash@{<index>}

Удаление всех спрятанных изменений.

git stash clear

Копирование коммитов

Команда cherry-pick позволяет копировать коммиты из другой ветки и вставить его в текущую.

Копирование одного коммита в текущую ветку.

git cherry-pick <hash-commit>

Копирование нескольких коммитов. Коммит <hash-commit-1> должен быть старше коммита <hash-commit-n>.

git cherry-pick "<hash-commit-1>..<hash-commit-n>"

При этом первый коммит не будет учитываться.

Для того чтобы он учитывался, требуется прописать ^ после первого коммита.

git cherry-pick "<hash-commit-1>^..<hash-commit-n>"

Если требуется изменить сообщение об фиксации.

git cherry-pick --edit <hash-commit>

При возникновении конфликта, требуется его решить и перейти на следующий коммит.

git cherry-pick --continue

Отмена копирование коммитов.

git cherry-pick --abort

Подключение к репозиторию по ssh

Сначала требуется сгенерировать ssh ключ. Сначала попросят ввести имя ssh ключа, его можно оставить по умолчанию. А дальше попросят ввести кодовую фразу, можно не вводить и просто нажать enter.

ssh-keygen

Ключ обычно хранится в директории ~/.ssh, по умолчанию его имя id_rsa. Генерируется два ключа открытый - id_rsa.pub, и закрытый - id_rsa. Сообщать можно только открытый ключ.

Для того чтобы передать ssh ключ github, нужно зайти на github.com, Settings, SSH and GPG keys, New SSH Key, в Title - ввести описание ключа, Key - ввести публичный ключ. И после этого можно пушить коммиты без постоянного потверждения.

Если GitHub репозиторий изначально был подключен по web URL, то требуется его поменять на ssh URL.

git remote set-url <remote-server-name> <ssh-url>

Подмодули

При работе с проектом, возникает необходимость использовать в нем другой проект. При этом нужно продолжать работать с двумя проектами по отдельности, но при этом использовать один из них в другом.

Добавление подмодуля.

git submodule add <url-repository>

При клонировании репозитория с подмодулями.

# для инициализации локального конфигурационного файла
git submodule init
# для получения всех данных этого проекта
git submodule update

Но можно сделать это более просто, передать git clone флаг --recurse-submodules.

git clone --recurse-submodules <url-repository>

Команда git pull получает изменения для подмодулей, но она не обновляет подмодули. Поэтому нужно обновить подмодули, и лучше запускать submodule update с параметром --init, чтобы проинициализировать новые подмодули, а так же с параметром --recursive, чтобы обновить вложенные подмодули.

git pull
git submodule update --init --recursive

Если установить параметр конфигурации status.submodulesummary, при git status будет так же показываться сводка по подмодулям.

git config status.submodulesummary 1
git status

Если требуется чтобы подмодуль отслеживал только нужную ветку.

git config -f .gitmodules submodule.Repoitory.branch <branch-name>

Отправка изменений не только из основного модуля, а так же из подмодуля.

При значении check, push просто завершится ошибкой, если какой-то из подмодулей не был отправлен на сервер. И тогда нужно будет вручную проходиться и оправлять изменения на сервер.

git push --recurse-submodules=check

При значении on-demand, будет пытаться отправлять самостоятельно без помощи пользователя.

git push --recurse-submodules=on-demand

Так же можно установить такое поведение по умолчанию.

git config push.recurseSubmodules check
# или
git config push.recurseSubmodules on-demand

Подпись коммитов

Для подписи коммитов используется утилита gpg.

Для того чтобы получить список имеющихся GPG-ключей.

gpg --list-keys

Для генерации ключа.

gpg --gen-key

При генерации нужно написать своё имя, email адрес. И далее нужно установить пароль для защиты ключа, так же можно оставить поле пустым и не указывать пароль.

Команда для более полной настройки ключа. Можно указать тип ключа, размер ключа и время работы ключа.

gpg --full-gen-key

Для того чтобы подписи коммитов были автоматически.

git config --global commit.gpgsign true

Если ключей несколько, можно установить определённый ключ.

git config --global user.signingkey <hash-pub-key>

Для загрузки открытого ключа на GitHub, нужно его экспортировать. Для записи его на GitHub нужно перейти в Settings, и далее SSH and GPG keys.

gpg --export --armor <hash-key> > ~/gpg-key.pub

Команда для сохранения резервной копии привтного ключа.

gpg --export-secret-keys --armor <hash-key> > ./gpg-key.asc

Для подписи тегов вместо флага -a используется флаг -s.

git tag -s <tag-name> -m "<comment>"

Так же при просмотре тега видно подпись.

git show <tag-name>

Для проверки подписанного тега. Для ее корректной работы нужно, чтобы в хранилище ключей присутствовал открытый ключ автора, поставeвшего подпись.

git tag -v <tag-name>

Для подписи коммитов используется флаг -S.

git commit -a -S -m "<comment>"

Для просмотра и проверки подписей есть параметр --show-signature.

git log --show-signature

Команды merge и pull можно заставить проверять и отклонять слияния, если коммит не содержит доверенной GPG подписи с помощью опции --verify-signatures.

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

git merge --verify-signatures <branch-name>

Если сливаемая ветка содержит только корректно подписанные коммиты, команда слияния сначала покажет все проверенные подписи, а затем выполнит слияние.

Так же если использовать флаг -S при слиянии, то коммит так же будет подписан.

git merge --verify-signatures -S <branch-name>

Для удаления ключа используется сначала удаление приватного ключа.

gpg --delete-secret-keys <name-user>

А после можно удалить уже сам ключ.

gpg --delete-keys <name-user>

Подписывать коммиты должен каждый, но при этом каждый коллега в команде должен уметь подписывать их.

Повторное слияние

Команда git rerere - это сокращение для reuse recorded resolution (повторно использовать сохранённое решение).

Эта команда позволяет попросить Git запомнить как была разрешёна некоторая часть конфликта, и в случае возникновения такого же конфликта, Git сможет его разрешить автоматически.

Разрешённые конфликты хранятся в директории ./git/rr-cache.

Команда для включения rerere.

git config --global rerere.enabled true

Просмотр какие снимки состояния сохранены.

git rerere status

Показать текущее состояние разрешения конфликта.

git rerere diff

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

  • gc.rerereResolved - как долго хранятся записи о разрешенных ранее конфликтных слияниях. По умолчанию это 60 дней.

  • gc.rerereUnresolved - как долго хранятся записи о неразрешенных конфликтах слияния. По умолчанию это 15 дней.

Поиск ошибок

Быстрый поиск плохого коммита

Если в какой-то момент оказалось, что какие-то тесты не закпускаются или какая-то часть кода перестала правильно работать, но при этом было сделано довольно много коммитов, отыскать где была допущена ошибка может быть пробематично. Команда bisect позволяет найти очень быстро плохой коммит.

Для старта поиска нужно запустить bisect.

git bisect start

Дальше требуется указать хороший коммит и плохой коммит.

git bisect bad <hash-commit>
git bisect good <hash-commit>

После этого, bisect разделит все коммиты, которые располагаются между ними, пополам, переключится в новую (безымянную) ветку на этом срединном коммите и позволит вам проверить, работает ли в нём нужный код.

Сказать что в данном коммите не работает нужный код.

git bisect bad

Сказать что в данном коммите работает нужный код.

git bisect good

Остановить поиск, и вернуться к начальной точке.

git bisect reset

Просмотр последнего успешно выполненного bisect.

git bisect log

Если имеется команда для проверки хорошего или плохого коммита, то эту часть можно автоматизировать.

Сначала нужно запустить bisect и указать хороший или плохой коммит. А далее запустить автоматическую проверку коммитов.

git bisect run <script>

Просмотр кто написал эту строку

Для полного просмотра кто написал каждую строчку в файле.

git blame <file-name>

Опция -L позволяет указать диапазон строк.

git blame -L 1,5 <file-name>

Опция -e позволяет отобразить адреса электронной почты авторов вместо имен пользователей.

git blame -e <file-name>

Опция -M позволяет находить перемещённые или скопированные строки внутри одного и того же файла. Указываться будет первоначальный автор строк.

git blame -M <file-name>

Опция -C позволяет находить строки, которые были перемещены или скопированы из других файлов.

git blame -C README.md

Поиск по истории коммитов

Для поиска строк по коммитам используется команда git grep. git grep принимает многие ключи, что и утилита grep в Linux.

Для поиска строки в git репозитории.

git grep <search-string>

Для того чтобы показать на какой строке найденный паттерн, используется опция -n или --line-number.

git grep -n <search-string>

Для того чтобы показать количество найденных параметров, используется опция -c или --count.

git grep -c <search-string>

Для более удобного вывода можно использовать опции --break - вывести пустую строку между совпадениями из разных файлов, и --heading - показывать имя файла над совпадениями в этом файле, а не в начале каждой отображаемой строки.

git grep --break --heading <search-string>

Поиск строки включая git подмодули:

git grep --recurse-submodules <search-string>

Поиск строки в файлах, подходящих под указанный шаблон:

git grep <search-string> -- <search-files>

Поиск по строке внутри указанного коммита

git grep <search-string> <hash-commit>

-e - поиск по нескольким параметрам.

git grep -e <search-string-1> -e <search-string-2>

Так же можно использовать дополнительные параметры --and, --or и --not, для сочетания нескольких шаблонов.

Если нужно найти когда было добавлено или удалено выражение можно использовать git log c флагом -S.

git log -S <search-string>

Так же есть поиск по журналу изменений строки. Для этого используется git log с флагом -L.

Можно либо указать диапазон строк и файл <start>,<end>:<file>, либо по регулярному выражению и файлу :<pattern>:<file>.

Примеры:

git log -L 4,6:file_test

git log -L :pattern:file_test

Администрирование

Сборка мусора и оптимизация репозитория

git gc занимается сборкой мусора - удаление ненужных файлов из хранилища объектов и эффективное упаковывание файлов.

Ручной запуск оптимизации репозитория.

git gc

Проверка требуется ли какое-то обслуживание.

git gc --auto

Некоторые команды могут самостоятельно запускать эту команду. Для отключения этой опции.

git config --global gc.auto 0

--aggressive - опция заставит git более агрессивно оптимизировать репозиторий за счет гораздо большего времени.

--prune=<date> - Удаление незакрепленных объектов старше даты (по умолчанию 2 недели назад). --prune=now - удаляет свободные объекты независимо от их возраста.

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

gc.pruneExpire - насколько старыми должны быть незакрепленные объекты, на которые нет ссылок, прежде чем они будут удалены. По умолчанию 2 недели назад.

Очистка проекта от лишних файлов

Команда clean предназначена только для удаления неотслеживаемых файлов и директорий.

Популярные опции для clean

  • -d - удалялись не только файлы но и директории

  • -x - удалялись файлы, которые игнорируются через .gitignore

  • -f - принудительное удаление

  • -n - предварительный запуск, показывает какие файлы будут удалены

Журнал действий

Git хранит все изменения, которые происходили в репозитории. Любые перемещения в ветки, перебазирование, удаление, всё это сохраняется в истории git.

Команда для просмотра изменений которые были совершены.

git reflog

Вывод изменений определённой ветки.

git reflog <branch-name>

Так же можно вывести в привычном формате reflog.

git log -g

Дальше по выведенным логам можно понять какие изменения были, и после этого вернуть изменения. После этой команды, он перейдет на этот коммит, и дальше уже можно будет решить как вернуть изменения.

git checkout <hash-reflog>

Либо откатиться до этого изменения

git reset <hash-reflog>

Так же можно эти изменения перенести в ветку для удобства.

git branch <recover-branch> <hash-reflog>

Данные о reflog остаются только локально, и при отправке на удалённый сервер они не будут сохранены на нём.

Стоит учитывать, что обычные записи хранятся 90 дней, если же коммит не достижим, к примеру удалена ветка, изменения будут хранится только 30 дней. Конфигурацию хранения логов можно поменять.

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

gc.reflogExpire - как долго записи в журнале ссылок каждой ветки должны оставаться доступными. По умолчанию он составляет 90 дней.

gc.reflogExpireUnreachable - как долго записи журнала ссылок, не являющиеся частью текущей ветки, должны оставаться доступными. Этот параметр по умолчанию равен 30 дням.

Массовое изменение истории

filter-branch - эта команда предназначена для перезаписи истории коммитов. Это очень мощная утилита и имеет множество подводных камней, которые могут привести к неочевидным искажениям предполагаемой перезаписи истории.

Опции.

  • --prune-empty - при удалении файла из коммита, может случится такое, что в коммите ничего нет. Эта опция сделает так, чтобы пустые коммиты будут удалены.

  • --subdirectory-filter <directory> - будет просмотр только истории, касающейся данного подкаталога.

  • --tree-filter <command> - для перезаписи истории файлов в коммитах.

  • --index-filter <command> - для перезаписи только индексированных файлов. Похож на tree-filter, но не проверяет дерево коммитов на не индексированные файлы, из-за этого работает быстрее. Очень часто использутся с git rm --cached --ignore-unmatch ....

  • --env-filter <command> - применяется если нужно изменить только данные, в которой выполняется фиксация. Можно переписать автора/коммитера/электронная почта/время и т.п.

  • --msg-filter <command> - для перезаписи сообщений фиксации.

  • --tag-name-filter <command> - для перезаписи имён тегов. Оригинальные теги не удаляются, но могут быть перезаписаны. --tag-name-filter cat, опция для того чтобы обновить теги.

  • --commit-filter <command> - для перезаписи комиитов.

Переменные по умолчанию:

  • GIT_COMMIT

  • GIT_AUTHOR_NAME

  • GIT_AUTHOR_EMAIL

  • GIT_AUTHOR_DATE

  • GIT_COMMITTER_NAME

  • GIT_COMMITTER_EMAIL

  • GIT_COMMITTER_DATE

При запуске filter-branch, для всех веток, которые эта команда затронет, будет создана копия по пути refs/original/refs/heads/<branch-name>. Это сделано для того чтобы после массового изменения истории, можно было просмотореть изменённую версию, и при ошибке откатиться обратно.

Один из вариантов удаление одной ветки.

git update-ref -d <path-for-branch>

Один из вариантов удаление всех веток.

git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

Один из вариантов отмены одной ветки.

# Возращение на прошлую ветку
git update-ref <path-for-branch> <branch-name>

# Удаление бекап ветки
git update-ref -d <path-for-branch>

Один из вариантов отмены всех изменений.

# Возращение на прошлую ветку
git for-each-ref --format="update %(refname:lstrip=2) %(objectname)" refs/original/ | git update-ref --stdin

# Удаление прошлой ветки
git for-each-ref --format="delete %(refname) %(objectname)" refs/original/ | git update-ref --stdin

Примеры:

Удаление какого-то файла во всех ветках.

git filter-branch --tree-filter "rm -f <file-name>" -- --all

-- отделяет параметры ветки фильтра от параметров ревизии, и --all, нужен для перезаписи всех веток и тегов.

Такое же удаление файла, только через index-filter.

git filter-branch --index-filter "git rm --cached --ignore-unmatch <file-name>" -- --all

Удаление коммитов одного человека.

git filter-branch --commit-filter '
    if [ "$GIT_AUTHOR_NAME" = "KotDimos" ];
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi' -- --all

Если требуется изменить имя человека который создал и пушил коммит. Так же можно указать диапазон, а не все ветки.

git filter-branch --env-filter '
    GIT_AUTHOR_NAME=KotDimos
    GIT_AUTHOR_EMAIL=KotDimos@gmail.com
    GIT_COMMITTER_NAME=KotDimos
    GIT_COMMITTER_EMAIL=KotDimos@gmail.com
    ' b63eabe..feature

Где b63eabe более ранний коммит ветки feature.

Возращение master на старую версию.

# Возращение на прошлую ветку
git update-ref refs/original/refs/heads/master master

# Удаление бекап ветки
git update-ref -d refs/original/refs/heads/master

Целостность объектов

git fsck - Проверяет подключение и действительность объектов в базе данных.

Опции:

  • --unreachable - показать объекты, которые существуют, но недоступны ни для одного из эталонных узлов.

  • --name-objects - отображается имя, описывающее, как они доступны.

  • --dangling - показать объекты, которые существуют, но никогда не используются напрямую.

  • --verbose - более подробная история объектов.

  • --lost-found - записывает висячие объекты в .git/lost-found/commit/ или .git/lost-found/other/, в зависимости от типа.

Запуск сервера

git instaweb - Программа для запуска gitweb сервера.

Опции.

  • -l / --local - привязать сервер только к локальному IP адресу.

  • --start - запустить сервер для текущего репозитория.

  • --restart - перезапустить сервер.

  • --stop - остановить сервер.

  • -d / --httpd - использовать указанный httpd демон. Поддерживаются apache2, lighttpd, mongoose, plackup, python и webrick. По умолчанию lighttpd.

  • -p / --port - порт для привязки httpd. По умолчанию 1234.

  • -b / --browser - браузер для просмотра веб страницы.

Примеры:

Запустить сервер.

git instaweb --start

Перезапустить запущенный сервер.

git instaweb --restart

Остановить запущенный сервер.

git instaweb --stop

Запустить сервер на порте 4321.

git instaweb --start --port 4321

Открыть веб страницу в google chrome.

git instaweb --browser chrome

Внутреннее строение Git

Git репозиторий представляет собой картотеку различных объектов, разложенную по именам-хешам.

Объекты бывают четырёх типов - blob, tree, commit, tag.

Blob

Blob (Binary Large Object) - это основа репозитория. Содержимое репозитория, без имени. Если добавить в git файл с содержимым, то результирующий blob-объект будет содержать только содержимое, без данных об имени файла.

Для просмотра того что хранит blob.

git cat-file -p <hash-blob>

Tree

Tree (дерево) - Объект этого типа решает проблему хранения имен файлов, а также позволяет хранить группы файлов.

Простмотр данных дерева.

git cat-file -p 94937a87cb0903787b7b517ea5f97f53b5492655

Примеры:

Дерево содержит в себе несколько blob объектов.

100644 blob db092f7d9e4ac9b4ae7ae5006e5dfa977c429d72	file1.txt
100644 blob 31c23dbefbf2605a0bf89022901da02b41e2af2e	file2.txt
100644 blob 5f5cc9d7ec9d0a46ede7f4f6de95cf317b8b19de	file3.txt

Так же дерево может содержать в себе другие деревья.

040000 tree aa7a4e54e8a9f75ced1cf720defda5067bd916fe	src
040000 tree bf59e83160c15371efcc209c5ebdbc7981c735ca    docs

И смешанно.

040000 tree aa7a4e54e8a9f75ced1cf720defda5067bd916fe	src
100644 blob db092f7d9e4ac9b4ae7ae5006e5dfa977c429d72	file1.txt

Права в первом столбце.

  • 1 цифра - 1 для файлов и символических файлов, 0 для директорий.

  • 2 цифра - 0 для файлов, 2 для символических ссылок, 4 для директорий.

  • 3 цифра - не используется, всегда 0.

  • 4-6 цифры - POSIX права.

Commit

Commit - фиксация изменения одного дерева, коммит также хранит информацию о "предках" этого дерева, то есть ссылки на родительские коммиты. Можно считать, что коммит указывает на деревья из каких произошло текущее дерево, а также автор коммита и сообщение коммита.

У самого первого коммита в репозитории не может быть предков. Он считается начальным коммитом, и считается что до него ничего не было.

Бывает, что несколько коммитов происходят от одного предка. В этом месте в истории появляется "развилка", история начинает делиться на ветви. Это происходит когда от одного коммита идёт 2 ветки.

Бывают еще коммиты, у которых несколько родителей - коммиты-слияния. Это происходит когда происходит слияние нескольких веток, и вообще количество родителей у коммита может быть не ограничено.

Вывод типа объекта.

$ git cat-file -p 475eeda53bc3f0291e7ea4a970247d3916c033d2

commit

Вывод самого объекта.

$ git cat-file -p 475eeda53bc3f0291e7ea4a970247d3916c033d2

tree a43f53d26a405f95caa823d7ae458a17cb4015f1
parent 83618fc75a2ff53d73ea0abe3ab6ca4e994d6776
author KotDimos <KotDimos@gmail.com> 1662372846 +0300
committer KotDimos <KotDimos@gmail.com> 1662372846 +0300

commit message

Tag

Теги бывают двух типов.

  • Аннотированные (Тяжеловесные).

  • Легковестные.

Аннотированный тег это специальный объект, который содержит в себе все данные которые требуются тегу.

Просмотр тега.

$ git cat-file -p annotaded-tag

object 51f0522b99cf3590675e2f3bf76b58c7914e3efc
type commit
tag annoteded-tag
tagger KotDimos <KotDimos@gmail.com> 1665228654 +0300

tag message

Легковестный тег же это просто указатель на коммит, и при просмотре его он покажет коммит.

References

Символьные имена объектов - ссылка (references), хранятся в каталоге .git/refs.

Типы:

  1. Теги (tag) - статическая ссылка на коммит. Расположены в .git/refs/tags/

  2. Ветка (head, branch) - динамическая ссылка на коммит, которая меняется при добавлении нового коммита в цепочку. Расположены в .git/refs/heads/

  3. Удаленные ветки (remote) - ветка специального вида, которая предназначена для слежения за ветками (heads) в других репозиториях. Лежат в .git/refs/remotes/

Кроме этого, есть несколько специальных ссылок, которые по историческим соображениям лежат вне каталога .git/refs. Наиболее важными являются HEAD, ORIG_HEAD и MERGE_HEAD.

HEAD - это особая ссылка, она показывает на коммит, который соответствует рабочей копии. Если быть точным, это не просто ссылка на коммит, это ссылка на текущую ветку.

Низкоуровневые команды

Просмотр объекта

Команда git cat-file нужна для просмотра содержимого или информации о типе и размере для объектов репозитория.

Опции.

  • -t - показать тип объекта.

  • -s - показать размер объекта.

  • -e - если объект существует, выходит с нулевым статусом, иначе выдаётся ошибка.

  • -p - показать содержимое объекта.

  • --allow-unknown-type - Разрешить -s или -t запрашивать сломанные/поврежденные объекты неизвестного типа.

Примеры:

Просмотреть тип объекта.

git cat-file -t 5713fb3

Вывести содержимое объекта.

git cat-file -p 5713fb3

Вывести размер объекта.

git cat-file -s 5713fb3

Так же можно найти список файлов для языков и проектов.

.

.gitignore
Интерактивный учебник направленный на закрепление теории
Начало работы
Начальная настройка окружения
Инициализация репозитория (init)
Основы
Клонирование репозитория (clone)
Просмотр текущего состояния (status)
Подробный просмотр файлов при изменении (diff)
Добавление в отслеживаемые файлы (add)
Фиксация изменений (commit)
Игнорирование файлов (.gitignore)
Удаление файлов (rm)
Перемещение или переименовывание файлов (mv)
История коммитов (log)
Работа с удалёнными репозиториями (remote)
Отправка данных на сервер (push)
Получение данных с сервера (fetch, pull)
Тэги (tag)
Псевдонимы (alias)
Настройка репозитория (config)
Именование коммитов
Полезные ссылки
Ветвление
Создание и просмотр веток (branch)
Смена ветки (checkout, switch)
Слияние веток (merge)
Перемещение веток (rebase)
Сравнение слияния и перемещения веток
Модели ветвления
GitFlow
GitHubFlow
GitLabFlow
Trunk Based Development
Инструменты Git
Редактирование коммитов (rebase, commit)
Редактирование последнего коммита (commit)
Редактирование сообщения нескольких коммитов (rebase)
Объединение коммитов (rebase)
Смена коммитов местами (rebase)
Варианты использования (rebase)
Отмена коммитов (reset)
Отмена изменений при уже отправленном коммите (revert)
Перенос указателя ветки (branch, checkout)
Восстановление файла к определённому коммиту (restore)
Откладывание изменений (stash)
Копирование коммитов (cherry-pick)
Подключение к репозиторию по ssh
Подмодули (submodule)
Подпись коммитов
Повторное слияние (rerere)
Поиск ошибок
Быстрый поиск плохого коммита (bisect)
Просмотр кто написал эту строку (blame)
Поиск по истории коммитов (grep)
Администрирование
Сборка мусора и оптимизация репозитория (gc)
Очистка проекта от лишних файлов (clean)
Журнал действий (reflog)
Массовое изменение истории (filter-branch)
Целостность объектов (fsck)
Запуск сервера (instaweb)
Внутреннее строение Git
Blob
Tree
Commit
Tag
References
Низкоуровневые команды
Просмотр объекта
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх
Наверх