GIT изнутри: введение (перевод)
Привет, Хабр! Представляю вашему вниманию перевод статьи «Git for Computer Scientists» автора Tommi Virtanen.
GIT изнутри: введение
От себя: Периодически почитываю статьи, как различные популярные технологии устроены под капотом, наткнулся вот на этот материал. Статья показалась интересной наличием простых и понятных схем, которые воспринимаются значительно лучше, нежели простыни унылого текста. Решил перевести на русский язык. Изображения взяты из оригинала.
Кому будет интересно и, возможно, полезно: людям, ежедневно работающим с Git (т.е. каждому второму, если не первому разработчику ПО), и желающим лучше понять механизм его работы.
Примечание: для лучшего понимания статьи следует иметь представление о таком звере, как направленный ациклический граф (directed acyclic graph, DAG).
Хранилище объектов
Хранилище объектов Git, представляет собой, грубо говоря, DAG, содержащий различные типы объектов. Объекты хранятся в сжатом виде и идентифицируются SHA-1 хэшами (это хэш НЕ содержимого файла, который представляет объект, а самого его представления в Git).
Blob

Blob — это простейший объект, просто набор байтов. Это может быть файл, символическая ссылка или что угодно. Семантику определяет объект, который на этот blob указывает.
Tree (дерево)

Объекты типа «дерево» описывают каталоги (директории). Они могут указывать на blob-ы, которые хранят содержимое файлов, а также на другие деревья, создавая таким образом структуру подкаталогов.
Если узел указывает на другой узел в DAG, говорят, что он зависит от этого узла, т.е. не может существовать без него. Узлы, на которые никто не указывает, могут быть удалены с помощью сборки мусора (команда git gc), либо восстановлены с помощью команды git fsck —lost-found.
Commit

Commit ссылается на дерево, представляющее собой состояние файлов в Git в момент, когда commit был создан. Также commit может ссылаться на другие commit-ы, являющиеся его родителями:
- Если у commit-а больше 1 родителя, это означает, что он описывает операцию merge (слияние)
- Если у commit-а нет родителей, это так называемый initial (начальный) commit (т.е. первый в репозитории)
- Также возможны случаи, когда в репозитории более 1 initial commit-а — это обычно означает слияние двух отдельных репозиториев
Телом объекта commit является commit message (сообщение).
Refs (ссылки)

Ссылки (или заголовки, или ветки) похожи на стикеры с заметками, наклеенные на узлы DAG, своего рода заметки, или закладки — «я работаю тут». В отличие, от узлов DAG, которые не могут быть изменены, и могут лишь добавляться, ссылки можно перемещать как угодно. Они не хранятся в истории и не переносятся непосредственно между репозиториями.
Команда git commit добавляет новый узел в DAG и перемещает на него закладку для текущей ветки.
Ссылки находятся в пространстве имен heads/branchname, но часть heads можно опустить.
Особняком стоит ссылка HEAD — она указывает не на узел, а на другую ссылку — это указатель на текущую активную ветку.
Remote refs

Это, грубо говоря, стикеры другого цвета. Разница состоит в том, что remote ссылки находятся в другом пространстве имен, а также управляются удаленным сервером. Для их обновления используется команда git fetch.
Tag (тэг)
Тэг — это сочетание узла DAG и стикера (еще одного цвета). Тэг указывает на commit, и включает необязательное сообщение и GPG-подпись. Стикер (ссылка) является простым способом доступа к тэгу, и в случае потери, может быть восстановлен командой git fsck —lost-found.
Таким образом, Git-репозиторий — это сочетание DAG и ссылок.
История
Теперь, зная, как Git хранит историю версий, попробуем изобразить различные операции, а также понять, чем Git отличается от систем, представляющих историю, как линейные изменения для каждой ветки.

Простейший репозиторий. Мы просто скопировали (git clone) удаленный репозиторий с единственным коммитом.

Здесь мы считали (git fetch) удаленный репозиторий и получили 1 новый commit, но еще не слили его с нашей веткой.

Вот что получится после выполнения команды git merge remotes/MYSERVER/master. Так как слияние выполнено как fast forward (в нашей локальной ветке не было локальных commit-ов), произошло следующее: изменились файлы нашей рабочей копии, а также переместился указатель на ветку.

Выполним локально git commit, а затем git fetch. Теперь у нас есть и локальный и удаленный commit. Очевидно, нужен merge.

Это результат выполнения команды git merge remotes/MYSERVER/master. Поскольку у нас был локальный commit, это уж не fast forward, и в DAG создается отдельный commit для этого merge. Заметьте — у него 2 родительских commit-а.

Вот как будет выглядеть наше дерево после нескольких commit-ов, в обе ветки (локальную и удаленную) + merge. Хорошо видно, как Git DAG фиксирует всю историю наших действий.

Однако, такую историю читать сложно. Если вы еще не опубликовали свою ветку, или договорились с другими членами команды, что они не должны отталкиваться от нее в своей работе, у вас есть альтернатива: вы можете выполнить rebase для своей ветки. В этом случае ваш commit заменяется другим commit-ом, с другим родителем, на который перемещается также ссылка на ветку.
При этом ваши старые commit-ы останутся в DAG, пока не будет произведена сборка мусора. В принципе, это своеобразная страховка, на случай, если что-то пойдет не так. Если у вас сохранились ссылки на старые commit-ы, то они будут сохранены, пока ссылки существуют.
НЕ следует выполнять rebase для веток, поверх которых другие люди создали commit-ы. Восстановить их можно (и даже не очень сложно), однако это привносит путаницу и массу бесполезной работы.

Вот как все выглядит после сборки мусора (либо игнорирования недоступных commit-ов), и создания нового commit-а поверх ветки, к которой применили rebase.

Также, с помощью rebase можно перемещать одновременно несколько commit-ов.
На этом все. Надеюсь, материал будет полезен.
Команда git-gc: опции, ключи и примеры использования
Общие команды – Общие команды, присущие различным операционным системам.
Переведено в рамках проекта tldr-ru. Licensed under the CC-BY (original work).

git gc
Оптимизировать локальный репозиторий, удалив ненужные файлы.
- Оптимизитовать текущий репозиторий:
- Агрессивная оптимизация. Занимает большее время:
git gc —aggressive
- Подавить весь вывод (тихий режим):
- Посмотреть полное руководство по команде:
Примеры кода, демонстрирующие общие подходы в программировании или же решающие небольшие прикладные задачи. Языки программирования и библиотеки, позволяющие эффективно решать задачи разработки. Объектно-ориентированное программирование, функциональное программирование и прочие подходы и …

Трюки Bash
Полезные заметки по работе с командной строкой: bash и прочие *sh. Однострочники, скрипты, позволяющие решать большие и малые задачи администрирования и настройки Юникс систем. Zsh для современного MacOS, Bash для …

Заметки о настройке различных IT-штуковин. Настройка, допиливание, полировка. Конфигурируем приложения и тюнингуем сервера. Полезные параметры и ключи запуска программ. Увеличиваем скорость, уменьшаем отклик, ускоряем работу и улучшаем результаты работы. Объясняем …

Терминал/Консоль
Команды и инструкции терминала (консоли) Linux, MacOS, Windows и прочих операционных систем. Трюки и особенности командных оболочек, скрипты для администрирования Unix. Программирование и скриптование Windows и Linux, тонкая настройка Macos. …

Также может быть вам интересно:
- Как получить дерево директорий на Bash одним однострочником
- Python: Функции
- Python: Встроенные типы данных (list, set, dict, etc)
- Python: типы данных, переменные, логическое ветвление и циклы
- Как сделать свою middleware в Django (с примерами)
Свежее на «Цифре»
MessageId или как дебажить систему с минимумом проблем
Программы, 09.09.2023
Проверочный список для выпуска промышленных приложений с иллюстрациями
Работа и управление, 30.07.2023
В Google Pixel и Windows Snipping Tool есть возможность восстановления обрезанных изображений
Новости, 23.03.2023
Два подарка «под ёлочку» от Heroes of Might and Magic
Новости, 25.12.2022
Вышел Pulsar – редактор кода на основе Atom
Новости, 25.12.2022
Ленивый backup PostgreSQL
Программы, 17.12.2022
Google анонсировала OSV-Scanner: сканер уязвимостей в программных проектах
Новости, 16.12.2022

Gitea запускает коммерческую версию, а недовольные – форк Forĝejo
На днях группа бывших разработчиков Gitea решили создать на базе хостинга кода Gitea свою версию проекта – «Forgejo». Причиной тому …

Пользователи и их создание в Django — своя регистрация на сайте
Если вашим сайтом должны активно пользоваться несколько человек, то полезно их различать, а значит — надо уметь создавать пользователей, либо …

Новый синтаксис старой команды with в Python 3.10
Как же долго моё чувство прекрасного страдало… Но в Python 3.10 появился новый парсер синтаксических конструкций Python!

Добавляем постраничную пагинацию на Django сайт
На сайтах часто встречаются многостраничные объекты: список товаров, список заметок и т.д. Поэтому важно уметь добавить навигацию по страницам на …

Новый оператор match-case в Python
В новой версии Python (3.10) появится новый оператор. Новый оператор сопоставления по шаблону (match-case).

Нет слов, одни. однострочники
На днях вышел пост со списком полезных однострочников для JavaScript программистов. Памятуя Perl-овую молодость, заглянул туда.

Добавляем переменные в контекст Django шаблонов (свой контекст-процессор)
В Django вы можете передавать данные в шаблоны посредством контекстов. Контекст передаётся из контроллера (view в терминах Django), однако, если …

Пример своей консольной команды в Django проекте
Если вы работали с Django проектом, то, скорее всего, запускали команды из консоли (manage.py). В Django есть простой способ писать …

Разграничение прав доступа на Django сайте
Почти на любом веб-сайте необходимо разделять пользователей на группы и предоставлять им разные возможности. В Django есть довольно серьёзная система …
Git gc что это
На больших репоозиториях, git зависит от способа сжатия информации истории, чтобы не занимать много дискового пространства или памяти.
Это сжатие не выполнятеся автоматически. Поэтому вы должны иногда выполнять git gc:
$ git gc
чтобы заново сжать архив. Это может занять длительное время, так что вы возможно предпочтете выполнять git-gc тогда когда не заняты чем то другим.
Обеспечение достоверности
Команда git fsck выполняет некоторое количество проверок целостности репозитория, и составляет отчет если будут найдены какие либо проблемы. Это возможно займет некоторое время. Наиболее общее предупреждение в значительной степени будут о подвешенных объектах:
$ git fsck dangling commit 7281251ddd2a61e38657c827739c57015671a6b3 dangling commit 2706a059f258c6b245f298dc4ff2ccd30ec21a63 dangling commit 13472b7c4b80851a1bc551779171dcb03655e9b5 dangling blob 218761f9d90712d37a9c5e36f406f92202db07eb dangling commit bf093535a34a4d35731aa2bd90fe6b176302f14f dangling commit 8e4bec7f2ddaa268bef999853c25755452100f8e dangling tree d50bb86186bf27b681d25af89d3b5b68382e4085 dangling tree b24c2473f1fd3d91352a624795be026d64c8841f .
Подвешенные объекты это не проблема. Самое худшее что они могут сделать это просто занять немного дополнительного дискового пространства. Иногда они могут быть вашим последним способом восстановить потерянную работу.
This book is maintained by Scott Chacon, and hosting is donated by GitHub.
Please email me at schacon@gmail.com with patches, suggestions and comments.
Команда git gc
git gc — это команда для технического обслуживания репозитория. gc расшифровывается как garbage collection, то есть «сбор мусора». Выполнение git gc буквально указывает Git, чтобы пора прибраться и навести порядок в текущем репозитория. Концепция сбора мусора берет начало в интерпретируемых языках программирования с динамическим выделением памяти. В таких языках сбор мусора используется для поиска памяти, которая стала недоступной для исполняющей программы.
В репозиториях Git накапливаются различные виды мусора. Один из них — это коммиты без родителя или без возможности доступа. Коммиты в Git могут стать недоступными при выполнении команд изменения истории, например git reset или git rebase. Git стремится сохранить историю и избежать потери данных, поэтому не удаляет открепленные коммиты. На такие коммиты все еще можно переключиться, отобрать их командой cherry-pick и проверить через git log .
Помимо очистки открепленных коммитов, git gc также сжимает сохраненные объекты Git, освобождая ценное место на диске. Когда Git обнаруживает группу похожих объектов, они сжимаются в «пакет». Пакеты представляют собой что-то вроде ZIP-файлов объектов Git и лежат в каталоге ./git/objects/pack в репозитории.
Так что же на самом деле делает git gc?
Перед выполнением команда git gc проверяет ряд значений git config. На примере этих значений становится понятно, за что еще отвечает git gc .
Конфигурация git gc
gc.reflogExpire
Необязательная переменная, по умолчанию равная 90 дням. Она задает время, в течение которого хранятся записи в журнале ссылок ветки.
gc.reflogExpireUnreachable
Необязательная переменная, по умолчанию равная 30 дням. Она задает время, в течение которого хранятся недоступные записи в журнале ссылок ветки.
gc.aggressiveWindow