Вы слишком верите в идею ветви. Git не заботится о ветвях; Git заботится о коммитах . Но чтобы сказать это, мы должны сначала остановиться и определить слово ответвление . В этом абзаце, что я подразумеваю под «ветвью», является именем ветви , например master
или develop
или feature/tall
. Для Git эти имена имеют только одну функцию: для записи необработанного хеш-идентификатора коммита.
В Git есть другие сущности, которые люди могут и действительно называют "ветвью". См. Что именно мы подразумеваем под "ветвью"?
В любом случае ветвь name в Git содержит хэш-идентификатор одного коммита. Это на самом деле очень полезно: и для нас, людей, для которых идентификаторы хешей в Git выглядят как случайный мусор, и для самого Git. Но это все , которые они держат сами. Важная информация хранится в другом месте, в основном в самих коммитах.
Git действительно заботится о коммитах. Коммиты хранят большую часть данных, которые вы ищете: кто их сделал, когда и из каких других ранее зафиксированных коммитов.
В именах ветвей не хранятся данные, которые вы ищете. У них нет информации об создателе. У них тоже нет собственной истории (но мы увидим кое-что еще через минуту). Для этого есть важная причина.
В отличие от ClearCase, Git представляет собой распределенную систему контроля версий. В ClearCase имеется централизованное управляемое хранилище: база объектов томов или VOB. Отдельные пользователи идут в центральное хранилище и получают из него что-то, а затем возвращают его обратно. Чтобы сделать это, все эти пользователи должны совместно использовать имена VOB для вещей. Так что если VOB хочет называть что-то Брюсом, то все остальные тоже могут называть это Брюсом.
С Git каждый репозиторий независим . У каждого есть свои собственные имена ветвей, независимо от имен ветвей всех остальных. only действительно универсальное имя в Git - это хэш-идентификатор. Каждый согласен с хеш-идентификаторами: коммит, чей хеш-код 08da6496b61341ec45eac36afcc8f94242763468
равен 08da6496b61341ec45eac36afcc8f94242763468
в в каждом репозитории Git. Никакой другой коммит не может иметь ID 08da6496b61341ec45eac36afcc8f94242763468
.
Если вы и я планируем соединить наши репозитории вместе, мы могли бы хотеть координировать имена наших веток время от времени, и мы может сделать это. Но мой репозиторий имеет моих названий веток, а ваш - ваших. Вы являетесь создателем всех названий вашей ветви. Я буквально не могу создать имя ветки в вашем хранилище. Все, что я могу сделать, это передать вам коммит - по его большому уродливому хэш-идентификатору - и затем попросить вашего Git создать или обновить какое-то имя. 1
Это большеОбычно все настраивается наоборот: я даю вам только для чтения доступ к моему хранилищу. Вы запускаете git fetch
, чтобы ваш Git вызывал мой Git через Интернет. Ваш Git спрашивает мой Git: Эй, другой-Git, какие у вас есть названия веток? Какие универсальные идентификаторы хеша идут вместе с этими именами ветвей? Мой Git дает вам мой список имен и хэш-идентификаторов, и ваш Git работает оттуда:
- Torek's Gitговорит, что его
master
a123456...
. У меня есть a123456...
, так что я в порядке. - Git Торека говорит, что его
dev
составляет b789abc...
. Хм, у меня нет есть b789abc...
. Возможно, мне следует запросить этот коммит по его хеш-идентификатору.
Это будет продолжаться до тех пор, пока ваш Git не получит всю информацию, которую мой Git передает на этом этапе коммуникации. Затем ваш Git по хеш-идентификатору запрашивает любой коммит, который он хочет. Если родительский коммит этого коммита - другой хеш-идентификатор, сохраненный внутри фактического коммита - представляет собой коммит, которого нет у вашего Git, ваш Git может запросить , что коммит его хэш-идентификатор и т. Д.
Evфактически, ваш Git возвращается к некоторому хеш-идентификатору, который уже есть у вашего Git - в этом случае у вашего Git есть коммит и он вообще не нужен - или у меня заканчиваются коммиты и я говорю «это все, что есть». 2 Затем ваш Git создает в вашем репозитории Git каждый коммит, который я передал.
Последнее, что делает ваш Git в этом процессе, - это создает или обновляет ваш имена для удаленного слежения . Здесь вместо того, чтобы использовать ваши ветви имена - которые ваши, а не мои! - ваш Git меняет все мои имена, простым и удобным в обращении образом. Ваш Git использует псевдоним для моего Git, а не URL. Псевдоним вашего Git, вероятно, origin
- хотя вы можете и фактически должны установить другой один для каждого другого Git, который вы собираетесь вызывать вот так. Имя origin
- это просто имя по умолчанию для Git, из которого вы сделали свой первоначальный клон.
Итак, давайте предположим, что ваш Git вызывает Git origin
. Ваш Git имеет полный список всех ветвей my и соответствующих им (одиночных) хеш-идентификаторов. Таким образом, ваш Git теперь создает или обновляет имя origin/*
, соответствующее именам моего Git. Мой Git сказал вашему Git, что my master
равно a123456...
, поэтому ваш Git создает или обновляет ваш origin/master
, чтобы он указывал на коммит a123456...
. У вас уже был этот коммит, так что мой не должен был отправлять его вам, или не попросил его, и мой Git отправил его. Мой Git сказал вашему Git, что my dev
это b789abc...
;ваш Git имеет этот коммит сейчас;ваш Git создает или обновляет ваш origin/dev
, чтобы он указывал на b789abc...
.
Опять же, это коммит , что имеет значение. Коммиты - и хэш-идентификаторы - являются универсальной валютой Git. Чьи-то имена филиалов ... ну, это те, о ком нужно беспокоиться. Мы скопируем их и сохраним как имя для удаленного слежения , но это не имена branch . Мои ветви названы моими;твои названия веток твои. Независимо от того, что Git использует кто-то, его имена ветвей их , а не чьи-либо другие.
1 Для вас может быть хорошей записьюименно я сделал этот запрос на обновление, но сам Git этого не делает. Сам Git не имеет никакой аутентификации или авторизации любого рода. Git полагается на какой-либо другой объект для выполнения любой необходимой аутентификации и / или авторизации. Так как кто-то еще делает это - если это вообще делается - Git также оставляет любую запись такой информации этой другой сущности.
2 Технически мой Git просто передает коммит, который имеет no parent, то есть root commit . Так как у него нет родителя, не существует более раннего коммита, который нужно запросить.
Git хранит некоторые собственные журналы
С учетом вышеизложенного - факт, что ваши ветви называют ваши и вы создаете и обновляете их - мы должны отметить, что Git действительно ведет журналы ваших различных ссылок . Эти журналы также ваши, чтобы делать, как вы хотите. Но каждый раз, когда ваш Git обновляет ссылку, он сохраняет предыдущее значение ссылки в «журнале ссылок».
A ref (или ссылка) в Gitявляется обобщением имен ветвей (например, master
), имен тегов (например, v2.1
), имен удаленного отслеживания (например, origin/master
) и т. д. Каждый вид имени по-прежнему просто хранит один хэш-идентификатор, но «вид» имени определяет, как вы будете его использовать.
Имя ветви - это просто ссылка, полное имя которой начинается с refs/heads/
. Так что ваш master
на самом деле просто ссылка с именем refs/heads/master
. Имя тега - это ссылка, полное имя которой начинается с refs/tags/
, поэтому v2.1
- это сокращение от refs/tags/v2.1
. Имя удаленного отслеживания начинается с refs/remotes/
и включает имя удаленного - origin
- и еще одну косую черту, поэтому ваше имя удаленного отслеживания для origin
master
равно refs/remotes/origin/master
.
Всякий раз, когда твой Gitдатирует любое из этих имен, оно сохраняет значение old в reflog для этого имени. Он помещает новое значение в это имя и помещает текущую дату и время в reflog вместе со старым значением.
Это означает, что если вы хотитеЕсли вы знаете, какой хеш-код был у вашего master
вчера, вы можете сделать так, чтобы ваш Git просматривал ваш журнал для вашего master
. Если оно было обновлено ранее сегодня, есть запись в этом журнале, и это показывает, что вчера у него был тот хэш-идентификатор, который у него был вчера.
Эти записи журнала в конечном итоге истекают и получаютвыбросил. Это очень отличается от коммитов , которые по большей части живут вечно. 3 Также важно помнить, что ваши reflogs ваши . Вы не можете видеть мое.
В Git есть специальная ссылка, записанная HEAD
(заглавными буквами), в которой обычно хранится имя ветви , а не необработанный идентификатор хеша. может хранить необработанный хэш-идентификатор;в этом режиме Git говорит, что у вас есть «отсоединенная ГОЛОВА». Но в основном он запоминает название ветви, на которой вы «находитесь» - например, если git status
говорит on branch master
, это означает, что HEAD
содержит внутри себя имя refs/heads/master
. Для HEAD существует журнал, в котором хранится необработанный идентификатор хеша, найденный путем следования через имя к базовому хешу коммита.
3 Технически, коммит живет до тех пор, пока выможет найти это. Это делает концепцию достижимости чрезвычайно важной. Подробнее о достижимости см. Think Like (a) Git .
git push
на самом деле здесь нечетный случай
Поток коммитов, который я описал вышедля git fetch
. Обратите внимание, что git pull
означает run git fetch
, затем выполните вторую команду Git . Вторая команда Git запускается только в вашем хранилище: ваш fetch
получает доступ только для чтения к другому хранилищу Git, получает от него коммиты (и другие данные), а затем обновляет имена для удаленного отслеживания. Команда second - это команда, которая включает новые коммиты в ваши ветки. Мне нравится откладывать эту вторую команду - обычно я хочу посмотреть, что git fetch
на самом деле принес , прежде чем принимать какое-либо решение о принятии или не принятии новых коммитов, поэтому я вообще редко использую git pull
.
Между тем, ближайшая вещь, противоположная извлечению, - git push
. При этом ваш Git вызывает другой Git - обычно под вашим собственным именем, опять же: git push origin
означает, что вы хотите, чтобы ваш Git вызывал Git по URL, который ваш Git сохранил под вашим именем origin
. После этого ваш Git не получает коммиты от исходного Git. Вместо этого ваш Git отправляет коммиты (и другие объекты) к ним.
Ваш Git скажет: У меня есть коммит 9876543...
для вас, у вас его уже есть? Если нет, ваш Git отправит его вам. Если у 9876543...
есть родительский a123456...
, ваш Git также удостоверится, что у его Git есть a123456...
, и так далее. В конце концов, ваш Git достигает коммита, который уже есть у его Git, и ему не нужно его отправлять, или достигает корневого коммита - такого, у которого нет родителя - так что больше нет коммитов для отправки.
Теперь, когдаваш Git отправил в Git все ваши коммиты, которые им не нужны, которые им понадобятся, ваш Git отправляет Git вежливый запрос: Пожалуйста, если все в порядке, установите для master
значение9876543...
. Это их Git, принять или отклонить этот запрос. Basic Git - в отличие от более популярных версий для продажи от таких людей, как GitHub, Bitbucket и Gitlab, - здесь очень простые правила (хотя вы можете написать свои собственные причудливые). Провайдеры веб-хостинга также обеспечивают аутентификацию пользователей, ведение журналов и т. Д., И они сами могут предоставить вам более эффективный контроль, если вы являетесь администратором. Встроенная проверка Basic Git просто: если я выполню этот запрос, смогу ли я найти коммит с ответвлением ветки, который уже есть в названии?
Этот тест - смогу ли я найти текущий коммит, если я приму этот новый хэш-идентификатор коммита - это проверка, чтобы определить, является ли операция fast forward . Это, опять же, все о достижимости : начиная с 9876543...
и работая в обратном направлении через родительские хеш-идентификаторы, могу ли я получить хеш-идентификатор, который у меня есть в имени сейчас? Если имя new , базовый Git просто принимает запрос, а если вежливый запрос на удаление имени, базовый Git просто принимает запрос.
Вы можете изменить этот вежливый запрос напринудительная команда: установите для master
значение 9876543...
! Они все еще могут отклонить его, но, опять же, основной Git последует за командой. Тест «это ускоренная перемотка» исчезает.
Правила обновления тегов и других имен более просты (но были разбиты до Git 1.8.2): имена тегов просто не могут бытьобновляется без --force
, и большинство других имен используют правило имени ветви («это ускоренная перемотка вперед»).
Когда кто-либо использует git push
, именно здесь происходит настоящая аутентификация, авторизация,и регистрация должна происходить на принимающей стороне. Basic Git предполагает, что это делает какая-то другая сущность: если вы преодолели какой-либо механизм, который предоставляет транспорт (https
или ssh
или любой другой), все должно быть хорошо! Если вы используете хостинг-провайдера, он может предоставить .