Git push - это атом? - PullRequest
       97

Git push - это атом?

3 голосов
/ 07 октября 2019

Является ли git push с несколькими коммитами атомарной операции?

  1. относительно других операций git push в той же ветви
  2. относительно операций git pull изта же ветка

Для случая 1. Должно быть. В противном случае мои коммиты будут мешать чужим коммитам, возможно создавая непоследовательное или недействительное состояние. Git предотвращает это, либо заставляя меня сначала интегрировать чьи-то изменения (если я проиграю гонку), либо заставляя кого-то еще интегрировать мои изменения (если я выигрываю гонку).

Но как насчет 2.? Если мой репозиторий выглядит так:

          C---D---E master
         /
    A---B origin/master

Кто-нибудь делает git pull, пока я делаю git push, увидит ли A --- B или A --- B --- C---D --- E, или они могут также получить что-то промежуточное, например, A --- B --- C --- D?

1 Ответ

4 голосов
/ 07 октября 2019

Фактически, да.

Обратите внимание, что у вас нет контроля над тем, что кто-либо еще делает с их хранилищем. Но в то время как вы делаете git push для какого-либо другого хранилища (например, одного на GitHub), на самом деле происходит следующее:

  • Ваш Git отправляет любые коммиты и / или другиеобъекты, которые требует их Git, чтобы ваш Git выполнял свои запросы на создание или обновление или удаление. Имя может называть только некоторый фактический объект, хранящийся в репозитории, поэтому, чтобы вы попросили их установить master ветвь для фиксации a123456..., ваш Git должен сначала убедиться, что они имеют коммит a123456....

  • Затем для каждого имени , которое вы хотите, чтобы они обновляли (или создавали или удаляли), ваш Git-запрос (обычное нажатие) или команды (* 1021)* и другие операции, которые устанавливают флаг форсировки) их для обновления. Вы отправляете им имена N и хэши new-hash в виде списка запросов на обновление (или создание или удаление). Каждый запрос имеет один или иногда два, как показано ниже, хэши. (Полностью нулевой хеш означает «удалить».)

    • Ваш Git может отправить им вежливый запрос, который Git выполнит, если это новая ветка или тег, или если этозапрос на удаление, или если это обновление имени ветви, и обновление является ускоренным. (Помимо этих ограничений, тот, кто контролирует их Git, может устанавливать любые дополнительные ограничения, которые им нравятся, но это значения по умолчанию.)

    • Ваш Git может отправить команду без условий. По умолчанию их Git подчиняется (но, как и раньше, тот, кто контролирует их Git, может устанавливать дополнительные ограничения).

    • Или ваш Git может отправлять команду, но с вашим собственным условием,form: Я полагаю, что ваше имя N представляет идентификатор хэша old-H (для некоторых имен и хэшей, причем old-H - все нули, если вы ожидаете, что у них еще нет имени). Их Git будет подчиняться команде, если их имя N имеет хэш old-H (и, как и раньше, тот, кто контролирует их Git, может устанавливать дополнительные ограничения).

  • Эта процедура обновления происходит при блокировке, которую их Git устанавливает в их хранилище. Эта блокировка делает обновление «все или ничего», что касается вашего Git. Для каждого отправляемого вами имени обновление либо происходит - принимается, и теперь их имя N представляет новый хэш , который ваш Git попросил / приказал - или нет, и он отклонен иимя не изменилось.

Когда вы (или кто-либо другой) запускаете git pull, вы действительно запускаете git fetch, за которым следует вторая, чисто локальная команда Git. git fetch похож на git push в том, что ваш Git вызывает какой-то другой Git, но на этот раз передача данных идет другим путем:

  • Ваш Git получает список отих Git, всех их имен и хэш-идентификаторов. Если идет непрерывный push, каждая пара - имя и ID хеша - либо от до запрошенного или запрошенного обновления, либо от после: промежуточный элемент не виден, потому что их Gitуважает свои собственные блокировки.

  • Затем, используя имена и хэш-идентификаторы, найденные на этом шаге, ваш Git выводит новые объекты, которые вы хотите и у которых нет на основе этого списка.

  • В конце этого процесса ваш Git не не затрагивает ни одно из ваших названий веток - по крайней мере, по умолчанию (вы можете переопределитьэто с refspec аргументами). Вместо этого ваш Git обновляет ваши имена для удаленного отслеживания , такие как origin/master, в соответствии с их именами. (В зависимости от того, как вы запускаете git fetch, вы можете ограничить свой Git обновлением только одного или нескольких ваших имен, а не всех; если вы собираетесь обновить только origin/master, ваш Git может пропустить загрузкуновые объекты, которые достижимы только из их feature-X, которые станут вашими origin/feature-X.)

во-вторых, чисто локальная команда может делать то же, что и вторая команда (обычно слияние, если вы не выбрали rebase). Эта часть часто , а не атомарная: например, во время перебазирования ваша перебазировка может остановиться в середине с копированием только некоторых коммитов, заставляя вас исправить конфликт и запустить git rebase --continue. Но это все в вашем хранилище, которое никто больше не делит. (Ваш Git также выполняет свои собственные операции блокировки / разблокировки для ваших собственных обновлений имени ветки и другого имени, в случае, если вы выполняете другую команду Git в фоновом режиме, или через задание cron, или как угодно.)

Ваша система CI, как правило, будет иметь свой собственный репозиторий Git, который она обновляет, копируя из любого репозитория, который вы указали как его апстрим (например, GitHub). Ваша система CI запустит git fetch, чтобы обновил origin/master. Как ваша система CI выполняет проверку и создание этого origin/master коммита до него.

...