git init
Данная команда создает папку .git, вот ее содержимое:
- hooks/ - это настраиваемые скрипты, которые могут встраиваться в различные Git команды и операции. Можно написать собственный hook и он попадет в эту папку. По умолчанию после git init создаются несколько hook-ов с именами файлов hook_name.sample, они остаются не активированными пока не будут переименованы hook_name. git help hooks выдаст больше информации по этой теме.
- info/ - доп. информация о репозитории. Единственный файл внутри exclude содержит master список файлов, которые исключаются из мониторинга Git-ом. Отличается от .gitignore тем что любой шаблон исключений записанный в exclude отражается только на локальный репозиторий и не влияет на последующие клоны. А .gitignore является частью истории и может быть подвергнут другим командам: add, commit, merge, clone, pull, push.
- config - project/repository-specific configuration file
- description - user-defined описание репозитория, которое используется программой gitweb для отображения клиентам листинга репозитория. Пакет gitweb поставляется вместе со стандартной инсталляцией и нужен для предоставления веб-интерфейса к репозиториям.
- objects/ - все что попадает под Git, рассматривается как объекты. Объекты бывают 4 типов: blobs (binary large object), trees (служат для внутреннего представление папок и структуры контента проекта, Git tree objects могут ссылаться на Git blobs и/или другие Git tree objects), commits (метаданные внесенных изменений: автор изменения, committer изменения, e-mail адреса, дата, время), и tags ("человеческие" имена для других объектов, обычно для commit-ов чтобы их было легче искать).
- HEAD - указатель на активную ветвь. Например, для master branch: ref: refs/heads/master, а для test_release branch: ref: refs/heads/test_release
- refs/ - SHA-1 IDs важных точек в репозитории, таких как tags (refs/tags) и branches (refs/heads). Каждый branch name это файл в refs/heads и этот файл содержит SHA-1 ID для commit-а конкретно из которого (parent по другому) создался данный branch. То же самое для tags - каждый tag это файл в папке refs/tags который имеет единственный SHA-1 ID на который он ссылается. Если папки heads и tags будут устроены иерархически то это просто означает что использовалось hierarchically structured name для branch или tag (например, git branch kamia/kashin приводит к heads/kamia/kashin).
- index - содержимое этого файла станет следующим commit-ом. Это то место где Git хранит staging area information. Или другими словами это то место где хранятся файлы которые пользователь хочет за-commit-ить в репозиторий.
git add
Когда выполняется команда add, Git обновляет файл index используя текущий контент найденный в working tree (staging your changes), и подготавливает staged-контент для следующего commit-а, подготовка включает в себя следующие шаги:- Вычисление hash для контента.
- Принятие решений, где создавать новый контент или ссылаться на существующий blob object.
- Фактическое создание или связывание ссылкой blob.
- Создание tree object для отслеживания расположения контента.
После этого index будет содержать snapshot контента в working tree для следующего commit-а.
Эта команда может быть выполнена несколько раз. Она только добавляет контент указанных файлов, каждый раз когда команда add запускается. Если нужно чтобы последующие изменения тоже вошли в следующий commit, нужно запустить git add снова чтобы добавить новый контент в index.
Большее значение должно быть уделено процессу, в котором оба объекта, blob и tree создаются и связываются с их соответствующими hash IDs, как показано на рисунке:
Tree может указывать не только на blob, но также и на другое tree, образуя иерархическую сеть:
git commit
Когда выполняется эта команда, создается commit-объект из метаданных контента/изменений, которые были добавлены командой git add ранее. Метаданные включают в себя следующее:- имя автора изменения, соответствующая дата и время;
- имя автора commit-а данных изменений, соответствующая дата и время.
head содержит имя ветви, а не SHA-1 ID commit-а, на который он указывает. Это потому что трудно идентифицировать ветвь по ее commit ID когда объем commit-ов внутри ветви постоянно меняется, следовательно "branch moves".
blob и tree объекты создаются как часть add операции; они будут уничтожены процессом garbage collection через несколько месяцев.
Теперь если сделать git status то можно убедиться что staged-изменения больше не находятся в состоянии staged.
git status
Когда команда status выполняется, Git проверяет файловые пути и размеры. Если нет различий, он оставляет все как есть, иначе любые найденные различия, подвергаются вычислению хэша и проверяется связь с другими хэшами.Сравнение файловых путей проходит следующими этапами:
Первый статус означает изменения которые уже были добавлены (staged) но не за-commit-ены. Поэтому выполнение git commit завершит versioning процесс.
Второй и третий статусы означают что изменения еще не были добавлены (staged) для commit-а. Поэтому для завершения versioning процесса, нужно их сначала добавить командой git add и потом git commit.
git clone
Внутренний процесс:- создание целевой папки и выполнение git init в ней;
- установка remote tracking branches в целевом репозитории для каждой ветви представленной в исходном репозитории (git remote);
- извлечение объектов, ссылок (внутри .git папки);
- выполение checkout.
git remote
Когда выполняет команда remote, Git проходит по всем remotes добавленным в репозиторий путем считывания их из секции remote в локальном конфигурационном файле .git/configПример:
[remote "capsource"]
url = https://github.com/cappuccino/cappuccino
fetch = +refs/heads/*:refs/remotes/capsource/*
Наименование capsource является псевдонимом для URL, который задается при добавлении нового remote в репозиторий. Параметры:
- url - ссылка на удаленный репозиторий, который вы хотите отслеживать, и получать содержимое из него;
- Fetch - информация которая говорит Git-у о refs (branches и tags) из remote которые должны отслеживаться. По умолчанию отслеживаются все refs из удаленного репозитория, что указывается как refs/heads/*. Они размещаются в папке локального репозитория capsource размещенной в refs/remotes/capsource/*
git branch
- сбор всех наименований ветвей из .git/refs/heads/
- поиск active/current working branch с помощью .git/HEAD
- отображение всех ветвей в возрастающем порядке со звездочкой (*) рядом с активной ветвью
git tag
- получение SHA-1 ID соответствующего commit-a;
- валидация наименования тега на конфликт с существующими именами;
- валидация наименования тега на соответствие правилам именования;
- создание объекта тега с данным именем, которое mapped на соответствующий SHA-1 ID, который может быть найден в .git/refs/tags/
git fetch
- проверка на URL или remote наименование, git fetch remote_name (или) url
- если ничего не указано, то считывается конф. файл по умолчанию для получения default remote
- если найден, извлекаются named refs (heads и tags) из удаленного репозитория вместе с ассоциированными с ними объектами
- полученные ref names сохраняются в .git/FETCH_HEAD в целях возможного слияния в будущем
git merge
- идентификация обоих merge кандидатов из папки heads, на основе указанных параметров
- поиск общего предка для обоих heads и загрузка всех их объектов в память
- выполнение diff (difference) между общим предком и head one
- применение diff к head two
- если есть изменения в пересекаемых областях, маркерами обозначается конфликт и происходит информирование пользователя об этом для того чтобы пользователь разрешил конфликт, добавил изменения и сделал commit
- если нет конфликтов, то выполняется слияние обоих содержимых и выполняется merge commit с метаданными об этом
git pull
- git fetch с заданными параметрами
- вызов git merge чтобы объединить полученный branch head в текущую ветвь
git push
- идентификация текущей ветви
- поиск default remote в конфигурационном файле (если не будет найдет то выдается просьба указать наименование remote или URK в качестве параметра для git push)
- получение информации об отслеживаемых remote's URL и heads (branches)
- проверка на то изменялся ли remote со времени последнего fetch: а) получение списка ссылок из удаленных репозиториев (git ls-remote) б) проверка на существование вхождений из списка локальной истории; если ссылка из remote является частью истории локального репозитория, это очевидно что не было изменений с момента последнего fetched/pulled из remote; поэтому Git позволяет напрямую сделать push изменений в remote; если ссылка из remote не является частью истории локального репозитория, Git понимает что удаленный репозиторий подвергался изменениям с момента вашего последнего fetched/pulled из него; поэтому он попросит сделать сначала git fetch или git pull
git checkout
- Fetches the named paths in the working tree.
- Fetches the related objects from the index.
- Updates the contents of the working tree with the ones from the index.
-b
Этот параметр используется для порождения новой ветви из checked out позиции характеризуемой commit ID.
git checkout -b <your_branch_name>
или
git checkout branch
git checkout <branch_name>
Эта команда создает новую ссылку в .git/refs/heads/ с конкретным commit ID.
--track
Этот параметр используется для установки upstream configuration обычно при создании новой ветви с параметром -b.
После выполнения, в .config файл в .git папке добавляется отдельная секция:
[branch "master"]
remote = origin
merge = refs/heads/master
Это случается когда выполняется команда
git checkout --track -b master origin/master
Git packfiles
Например, есть 2 одинаковых текстовых файла по 5 МБ каждый. Git создаст один blob, т.к. одинаковое содержимое дает одинаковый SHA-1 ID. Теперь изменим второй файл. Git создаст новый blob (5+ МБ) для второго файла, который изменился. Можно задать два вопроса:- Почему Git создает новый blob для всего содержимого?
- Почему бы не оставить старый blob для двух файлов, и дополнительно не создать новый blob для разницы со вторым файлом, чтобы использовать пространство более эффективно?
Передача packfiles
Git поддерживает не только передачу refs и ассоциированных с ними plain blob, tree, commit,и tag objects, но и packfiles на таких операциях как clone, fetch, push, и pull. Git имеет 2 множества протоколов для передачи данных между remotes.
- один для pushing data с клиента на сервер
- другой для fetching data с сервера на клиент