Я мало что знаю о моделях ветвления в VCS, кроме Git. Я бы сказал, что в любой DVCS вы можете реализовать ветвление путем клонирования (вы создаете ветвь путем клонирования). Так называемые «именованные ветви» Mercurial на самом деле (насколько я понимаю) коммит-метки интерпретируются только как ветви, иногда требующие локальной нумерации ревизий для устранения неоднозначности. Я думаю, что Mercurial "закладки" очень похожи на ветки Git. Два DVCS, которые имеют очень различную концепцию ветвления: Monotone и Darcs . Я думаю, что «ветвление путем копирования», которое использует Subversion, когда разделение между именем проекта и именем ветвления согласно соглашению , является неверной идеей.
В ревизиях Git формируют ориентированный ациклический граф (DAG) коммитов. Направлено, потому что совершает у родителей. Это очень важный вопрос: ребра в DAG коммитов происходят от коммитов к его родителю (или, в случае коммита слияния, к двум или более его родителям). Граф коммитов является ациклическим, что означает отсутствие цепочки (без пути), которая начинается и заканчивается одним и тем же объектом.
Глоссарий Git определяет "ветвь" как активную линию развития . Эта идея стоит за реализацией веток в Git.
Самая последняя фиксация на ветке называется tip этой ветки. На ветвь ссылается заголовок ветви , который является просто символическим именем для этого коммита. В «свободной» форме такой заголовок ветви (например, для ветви с именем 'master') представляет собой просто файл где-то в каталоге refs/heads/
внутри репозитория git (внутри .git
dir), который содержит ссылку на текущий наконечник ветви: его идентификатор SHA-1 коммита (в виде шестнадцатеричной строки).
Когда вы создаете новый коммит в Git, кончик ветки, которая в данный момент извлечена, движется вперед. Другими словами, новый коммит создается в верхней части текущей ветки, а верхняя часть ветки переходит к новой фиксации (что аналогично тому, как может продвигаться указатель на вершину стека).
Один репозиторий git может отслеживать произвольное количество веток, но ваше рабочее дерево (если оно у вас есть) связано только с одной из них («текущей» или «извлеченной» веткой). Текущая ветвь задается указателем HEAD. HEAD - это (обычно) указатель на текущую извлеченную ветвь (на имя заголовка ветки), точно так же, как заголовки веток являются указателями на кончики ветвей.
Например, если текущая извлеченная ветвь 'master', то файл .git/HEAD
(представляющий HEAD) будет содержать одну строку с LF-символами в конце с ref: refs/heads/master
(символьная ссылка на refs/heads/master
) и .git/refs/heads/master
(head ветки 'master') будет содержать, например, LF-концевую строку 0b127cb8ab975e43398a2b449563ccb78c437255
, которая является идентификатором SHA-1 до вершины ветки 'master' (то есть, если текущая ветвь не "упакована": тогда вам нужно взглянуть на .git/packed-refs
).
Некоторые команды в Git, такие как «git commit» или «git reset», манипулируют / изменяют голову ветки; другие, такие как «git checkout», управляют / меняют HEAD (символическая ссылка на текущую ветку).
Команда "git log <i>branch</i>
" показывает все коммиты, достижимые из tip tip, что означает tip of branch, его родителя, parent (или parent) этого родительского коммита и т. Д. Она отображает часть DAG коммитов.
В Git удаление ветки означает просто удаление заголовка ветви. Это может означать, что некоторые коммиты становятся «невидимыми», недостижимыми ссылками freom (ветки и теги), что означает, что в какое-то время эти коммиты могут быть собраны и удалены из репозитория. Но если вы можете удалить ветку с помощью "git branch -d ", то это означает, что никакие коммиты не будут потеряны; Вы можете принудительно удалить ветку с помощью "git branch -D ". Переименование ветви - это просто вопрос переименования заголовка ветви, символической ссылки (символического имени) подсказки ветви; имена веток нигде не сохраняются в объекте коммита.
Git также имеет концепцию reflogs , которая является локальной историей того, куда указывал конец ветви (и когда). Например, если вы измените коммит с помощью "git commit --amend", то tip будет заменен на исправленный коммит, а HEAD ^ будет родительским коммитом до и после внесения изменений, в то время как в reflog будет указана версия до внесения изменений и после внесения изменений. Если вы перематываете историю с помощью «git reset», reflog будет содержать информацию о старой ветке tip перед перемоткой.
Короче говоря, reflog обеспечивает дополнительную безопасность и простое восстановление для команд git.