В некоторых системах контроля версий, когда вы делаете коммит C на ветке B , коммит C находится на ветке B навсегда. Любой, кто получает коммит C , получает ветку B . Если раньше у них была их собственная ветка B , то теперь у их ветви B есть новый коммит C в нем
Git не делает это. Комитеты не привязаны к филиалам. Однако коммиты являются в основном постоянными, 1 и постоянно привязаны к тому месту, где они появляются в графе коммитов . Для того, чтобы эта работа работала, коммиты не делаются на любых ветках. Вместо этого имя ветви - это просто метка. Несколько меток могут указывать на один и тот же коммит , например:
* 305f Merge branch 'develop' (HEAD->master, origin/master, origin/HEAD)
Здесь master
и origin/master
2 обаопределить совершить 305f
. Если вы создадите новую ветку br2
сейчас, это имя также укажет на фиксацию 305f
.
Коммит 305f
имеет двух родителей: 7a761b6
(его первый родитель) и d97b
(его второй родитель). Полное имя 305f
соответствует его полному хэш-идентификатору. Это никогда не изменится;и этот хэш-идентификатор навсегда зарезервирован для , что commit, который всегда будет иметь тех же двух родителей. Этот коммит замораживается на все времена и никогда не будет перемещаться.
В Git все, что делает движение - это имена ветвей . В настоящее время master
означает 305f
. Однако минуту назад master
означало 7a761b6
. Комитеты остаются на месте, навсегда, как их необработанные хэш-идентификаторы. Имена ветвей перемещаются.
Результатом всего этого является то, что множество ветвей, которые содержат некоторые изменения, динамически изменяются по мере того, как мы создаем и уничтожаем имена ветвей. В настоящее время имя master
позволяет найти все четыре коммита. Если вы позволите Git перемещать имя master
так, как предпочитает Git, эти четыре коммита будут по-прежнему доступны, начиная с 305f
и просматривая обоих его родителей, затем просматривая родителя d97b
(изатем с d97b
вы вернетесь к 7a761b6
, который вы уже видели). Обратите внимание, что new фиксирует только когда-либо добавление к графику . В общем, каждый новый коммит будет иметь некоторый существующий коммит в качестве своего родителя - своего единственного родителя, если это типичный коммит, или одного из двух родителей, если это коммит слияния. 3
Если мынарисовать эти вещи в сторону, это немного проще. Чтобы сделать это еще проще, мы можем использовать одну заглавную букву для обозначения непонятных хеш-идентификаторов, которые использует Git:
D--E <-- br1
/
A--B--C
\
F--G <-- br2
Здесь имя br1
позволяет нам найти commit E
, который находит D
, затем C
, затем B
, затем A
(и останавливается, потому что A
является первым коммитом). Имя br2
позволяет нам найти G
, затем F
, затем C
, затем B
, затем A
(и затем остановить). Таким образом, первые три коммита находятся на обеих ветвях, в то время как два коммита - это только одна одна ветвь.
Стирание имени br1
вызывает коммиты D
иE
чтобы стать неотразимым. В конце концов Git выбросит их по-настоящему. Если вместо этого мы добавим новый коммит, выполнив git checkout br1
, сделав все необходимые изменения git add
и git commit
, мы получим новый хэш-идентификатор H
и добавим имя br1
, чтобы включить его:
D--E--H <-- br1
/
A--B--C
\
F--G <-- br2
Теперь есть шесть коммитов, доступных с br1
, начиная с H
и работая в обратном направлении. Если мы создадим новое имя br3
, чтобы запомнить, где находится E
, мы захотим немного перерисовать график:
H <-- br2
/
D--E <-- br3
/
A--B--C
\
F--G <-- br2
Обратите внимание, что ни один из коммитов не имеетна самом деле изменилось: мы просто добавили H
, чтобы освободить место для метки br3
.
Если мы удалим name br3
позже, это нормально: нет коммитов, которые исключительно найдено через br3
. Коммит E
не исчезнет, потому что br1
находит H
, который находит E
.
1 в основном достигается через достижимость . Вы находите коммиты, начиная с какой-либо ветви или имени тега, который предоставляет необработанный хэш-идентификатор. Затем, найдя коммит, вы используете его родительские хеш-идентификаторы, чтобы найти предшествующий коммит. Затем вы используете эти коммиты для поиска их родителей и т. Д.
Выполняя этот процесс из каждой ссылки - см. Сноску 2 -Git находит все достижимые коммиты. Любые коммиты, которые существуют в репозитории и которые недоступны для этого процесса, в конечном итоге собираются и удаляются.
2 Имя master
является именем ветви. Его полное имя действительно refs/heads/master
, а имена, полное имя которых начинается с refs/heads/
, являются именами ветвей. В отличие от этого, origin/master
на самом деле является именем для удаленного слежения : его полное имя начинается с refs/remotes/
, а затем продолжается origin/master
. Git иногда удаляет только часть refs/
из этого имени, так что вы видите remotes/origin/master
.
Теги, если они есть, живут в refs/tags/
. Все это вместе называется refs или ссылки . В reflogs хранятся дополнительные скрытые ссылки. Reflog - это просто файл журнала, в котором хранятся значения - предыдущие хэш-идентификаторы, - которые были сохранены в ссылке до того, как вы или Git обновили его. Срок действия этих записей журналов в конце срока истекает, и именно поэтому преднамеренно оставленные коммиты - например, те, которые вы заменили новыми и улучшенными версиями с новыми идентификаторами хеша - в конечном итоге удаляются.
3 Техническое определение коммит слияния состоит в том, что он имеет по крайней мере двух родителей. Поэтому вы также можете создать коммит слиянием с 3 или более родителями, но редко есть причина для этого. Следует также отметить, что можно создать новый коммит с no parent. За исключением самого первого коммита - того, который я обозначил A
на боковых графиках - вы не будете делать это и в обычной практике.