DevOps полезные советы по работе с Git

Как мы все знаем, Git — это распределенная система контроля версий (VCS), предназначенная для управления и отслеживания изменений в файлах и исходном коде в проектах разработки программного обеспечения. Он был создан Линусом Торвальдсом в 2005 году для эффективной разработки ядра Linux.

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

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

Как DevOps-инженер, вы можете запускать команду git init тысячу раз, но действительно ли вы понимаете, что происходит за командой git init?

git инициировать

Команда git init используется для создания нового пустого репозитория Git или инициализации существующего проекта с контролем версий Git. Эта команда устанавливает необходимые структуры данных Git и создает каталог .git в корне проекта, который содержит все метаданные и файлы конфигурации, необходимые Git для управления репозиторием.

Например, давайте создадим репозиторий git под названием git-demo с нуля и посмотрим, как он создается:

$ mkdir git-demo
$ cd git-demo
$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:  git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:  git branch -m <name>
Initialized empty Git repository in /mnt/efs/data/home/txu/code/git-demo/.git/

На другом терминале у меня запущена команда watch -n 1 -d find . для каталога git-demo, вот что произошло:

Every 1.0s: find .                                                                                                    Wed Apr 19 23:27:23 2023

.
./.git
./.git/refs
./.git/refs/heads
./.git/refs/tags
./.git/hooks
./.git/hooks/pre-push.sample
./.git/hooks/pre-merge-commit.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/applypatch-msg.sample
./.git/hooks/post-update.sample
./.git/hooks/pre-rebase.sample
./.git/hooks/fsmonitor-watchman.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/commit-msg.sample
./.git/hooks/pre-commit.sample
./.git/hooks/push-to-checkout.sample
./.git/hooks/update.sample
./.git/hooks/pre-receive.sample
./.git/description
./.git/info
./.git/info/exclude
./.git/HEAD
./.git/objects
./.git/objects/info
./.git/objects/pack
./.git/config
./.git/branches

и чтобы это выглядело лучше:

$ tree .git -L 2
.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── push-to-checkout.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

9 directories, 17 files

.git/config

Файл .git/config — это локальный файл конфигурации в репозитории Git. Он хранит настройки и предпочтения, относящиеся к репозиторию, в котором он находится. Эти настройки могут включать такие вещи, как URL-адреса удаленного репозитория, конфигурации ветвей, информацию о пользователях и другие настройки, относящиеся к репозиторию.

Параметры конфигурации в файле .git/config имеют более высокий приоритет, чем параметры в глобальном файле конфигурации (обычно расположенном по адресу ~/.gitconfig или ~/.config/git/config). Это означает, что любые настройки, определенные в файле .git/config, переопределяют глобальные настройки для этого конкретного репозитория.

Вот пример того, как может выглядеть файл .git/config:

[core]
  repositoryformatversion = 0
  filemode = true
  bare = false
  logallrefupdates = true
[remote "origin"]
  url = https://github.com/user/repo.git
  fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
  remote = origin
  merge = refs/heads/master
[user]
  name = Your Name
  email = [email protected]

.git/объекты

Каталог .git/objects является неотъемлемой частью репозитория Git, так как в нем хранятся все объекты, составляющие историю репозитория. Объектами могут быть коммиты, деревья и большие двоичные объекты (файлы), и каждый объект однозначно идентифицируется хэшем SHA-1. Объекты хранятся в формате с адресацией по содержимому, что означает, что они организованы на основе их содержимого, а не их местоположения или имени файла.

$ tree .git/objects/
.git/objects/
├── info
└── pack

2 directories, 0 files

Каталог .git/objects содержит два основных типа подкаталогов:

  • Упаковочные файлы: Git сжимает и сохраняет объекты в упаковываемом файле, когда в репозитории много объектов или во время сборки мусора. Упаковочный файл — это отдельный файл, содержащий несколько объектов в сильно сжатом формате, что помогает сократить использование дискового пространства и повысить производительность. Packfiles имеют расширение .pack и находятся в подкаталоге .git/objects/pack.
  • Свободные объекты: это отдельные объекты, которые не являются частью пак-файла. Когда вы создаете новую фиксацию или добавляете новый объект в репозиторий, он изначально сохраняется как незакрепленный объект. Свободные объекты хранятся в подкаталогах внутри каталога .git/objects, где имя подкаталога — это первые два символа хэша SHA-1 объекта, а оставшиеся 38 символов образуют имя файла.

Как правило, вам не следует взаимодействовать с каталогом .git/objects напрямую, так как Git автоматически управляет его содержимым. Когда вы используете такие команды, как git add, git commit и git fetch, Git позаботится о создании, обновлении или извлечении объектов из каталога .git/objects.

.git/информация

Каталог .git/info в репозитории Git используется для хранения дополнительных метаданных и конфигурации, относящихся к репозиторию. В то время как файл .git/config содержит основные параметры конфигурации репозитория, каталог .git/info содержит другие файлы, которые могут предоставить дополнительную информацию о настройке и репозитории.

Одним из наиболее часто используемых файлов в каталоге .git/info является файл exclude. Этот файл работает аналогично файлу .gitignore, позволяя вам указывать файлы или каталоги, которые Git не должен отслеживать. Разница в том, что шаблоны, указанные в файле .git/info/exclude, применяются только к локальному репозиторию и не передаются другим, поскольку этот файл не фиксируется и не отслеживается Git.

.git/хуки

Каталог .git/hooks в репозитории Git содержит набор примеров сценариев, называемых «перехватчиками». Хуки — это настраиваемые скрипты, которые можно настроить на автоматическое выполнение при возникновении определенных событий в репозитории Git. Они позволяют выполнять настраиваемые действия, применять политики или изменять поведение Git по умолчанию в ответ на определенные события.

Некоторые распространенные варианты использования хуков включают в себя:

  • Проверка сообщений фиксации, чтобы убедиться, что они соответствуют определенному формату.
  • Запуск тестов или проверки качества кода перед принятием фиксации.
  • Автоматическое обновление системы отслеживания проблем или отправка уведомлений при отправке фиксации в удаленный репозиторий.

Перехватчики Git могут быть написаны на любом языке сценариев, исполняемом в системе (например, Bash, Python, Perl).

По умолчанию каталог .git/hooks содержит набор примеров хуков с расширением .sample. Эти пробные хуки не активны и не будут выполняться, пока вы не переименуете их, удалив расширение .sample.

.git/HEAD

Файл .git/HEAD — это специальный файл в репозитории Git, который служит ссылкой на текущую ветку или фиксацию, извлеченную в вашем рабочем каталоге. Другими словами, он указывает на вершину ветки, над которой вы сейчас работаете.

Обычно содержимое файла HEAD является ссылкой на ветку, например:

$ cat .git/HEAD
ref: refs/heads/master

Также возможно, что HEAD находится в состоянии "detached HEAD", что означает, что он указывает непосредственно на коммит, а не на ветку. Это может произойти, например, при извлечении определенного коммита или тега. В отсоединенном состоянии HEAD файл HEAD будет содержать полный хэш SHA-1 коммита, на который он указывает, например:

a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0

Обычно вам не следует редактировать файл .git/HEAD напрямую. Вместо этого используйте команды Git, такие как git checkout, git switch или git restore, для изменения веток или коммитов. Изменение файла HEAD вручную может привести к несоответствиям в вашем репозитории или вызвать непредвиденное поведение.

.git/refs

Каталог .git/refs в репозитории Git используется для хранения ссылок на определенные коммиты. Эти ссылки, часто называемые «ссылками», являются указателями на коммиты и играют важную роль в отслеживании истории ветвей и тегов в репозитории. Рефы позволяют Git отслеживать последнюю фиксацию для каждой ветки и конкретную фиксацию, на которую указывает тег.

Каталог .git/refs содержит два основных подкаталога:

  • .git/refs/heads: Содержит ссылки на ветки в вашем репозитории. У каждой ветки есть соответствующий файл с тем же именем, что и у ветки, а содержимое этого файла — это хэш SHA-1 последней фиксации в этой ветке. Например, если у вас есть ветка с именем main, будет файл с именем .git/refs/heads/main, содержащий хэш SHA-1 последней фиксации в ветке main.
  • .git/refs/tags: Содержит ссылки на теги в вашем репозитории. Подобно ветвям, каждому тегу соответствует файл с тем же именем, что и у тега. Содержимое этого файла представляет собой хэш SHA-1 коммита, на который указывает тег. Теги обычно используются для обозначения определенных моментов в истории репозитория, таких как выпуск версии.