Но я получаю импликацию, что git может нажать на текущую ветку удаленного репозитория, начиная с Version Control с помощью Git, на Loeliger, 2ed, особенно тексты жирным шрифтом:
Операция push может обновлять состояние репозитория, включая HEAD совершить. То есть, хотя разработчик на удаленном конце ничего, ветка refs и HEAD может измениться, переставая синхронизироваться с проверенными файлами и индексом.
Разработчик, который активно работает в репозитории, в который асинхронное нажатие не увидит толчок. Но последующий фиксация этим разработчиком произойдет на неожиданном HEAD, создав странная история. Усиленный толчок потеряет толкаемые фиксации от другого разработчик. Разработчик в этом репозитории также может оказаться неспособная согласовать свою историю с каким-либо восходящим репозиторием или нисходящий клон, потому что они более не бывают быстрыми вперед, как они должны быть. И она не знает, почему: хранилище тихо из-под нее. Кошки и собаки будут жить вместе. Itll будет плохо.
В результате вам предлагается просто входить в открытый репозиторий. Это не жесткое правило, но его хорошее руководство к средний разработчик и считается лучшей практикой. Есть несколько примеры и варианты использования, в которых вы, возможно, захотите, но вы должны полностью понять его последствия. Когда вы хотите вставить в репозиторий разработки, вы можете следовать одному из двух основных подходов.
В первом сценарии вы действительно хотите, чтобы имел рабочий каталог с филиалом, извлеченным в принимающем репозитории. Вы можете знать, например, что никакой другой разработчик никогда не будет активен там есть и, следовательно, никто не может быть слепым в то время как молчащие изменения вставляются в его репозиторий.
В этом случае вам может потребоваться включить крюк в принимающем репозиторий выполнить проверку какой-либо ветки, возможно, только один помещается в рабочий каталог. Чтобы убедиться, что получающий репозиторий находится в нормальном состоянии до автоматического checkout, крючок должен следить за тем, чтобы работали нестационарные репозитории каталог не содержит изменений или измененных файлов и что его индекс имеет нет файлов в поэтапном, но незафиксированном состоянии, когда происходит нажатие. Когда эти условия не выполняются, вы рискуете потерять эти изменения или изменения, так как проверка перезаписывает их.
Существует еще один сценарий, в котором вхождение в нестационарный репозиторий может работать разумно Что ж. По соглашению, каждый разработчик, который меняет изменения, должен нажимать на неконтролируемый out, который считается просто принимающей ветвью. Разработчик никогда не подталкивает ветку, которая, как ожидается, будет проверена. Некоторые разработчики, в частности, управлять какой ветвью проверяется и когда. Возможно, этот человек несет ответственность за обрабатывая принимающие ветки и объединяя их в ведущую ветвь, прежде чем она выдан.
Означает ли это, что git может нажать на текущую ветку удаленного репозитория? (Мое предположение да, но я не уверен)
Является ли абзац до последнего (абзац, рекомендующий использовать крючок, который проверяет ветвь, обновленную push), предполагает, что ветвь, на которую нужно нажать, не является текущей ветвью в удаленном репозитории? (Моя мысль состоит в том, что проверка ветки на нажатие означает, что ветвь, на которую нужно нажать, не является текущей ветвью, но последний абзац указывает на "другой сценарий" нажатия на не проверенную ветку, что означает, что в предыдущем абзаце говорится о нажатии на выданную ветвь, т.е. текущую ветвь)
Ответ 2
На этом этапе я получу удар, но я не хочу увязнуть в деталях того, о чем говорит книга, которую вы цитируете.
Я думаю, что способ взглянуть на это с "принимающей стороны", т.е. думать о том, что происходит, когда вы обычный человек, использующий git, и кто-то делает толчок в ваш репозиторий (против того, что вы обычно делаете, который должен извлекать из их). git предоставляет много механизмов для этого, а политика по умолчанию работает нормально, а именно: "просто сказать" нет ".:-) Более новые версии git (2.3+) добавили еще несколько политик, обеспечивающих безопасность, позволяя некоторым из этих нажатий; вы бы назвали их" правильными "или" совершенными ", это скорее вопрос мнения. (Подумайте, что произойдет, если кто-то начнет редактирование на вашем небезовом" развернутом "хосте, а затем, скажем, засыпает, так что никто другой не может нажать на него, потому что теперь он" выглядит грязным" до git.)
Сначала помните, что репозиторий может быть установлен на "голый", который сообщает git не искать рабочее дерево. (Вы можете конвертировать не-обнаженное репо на гору или наоборот, но, по моему опыту, большинство людей сталкиваются с чем-то в этом процессе. Использование git clone --bare
сначала устанавливает голой клон и позволяет избежать создания рабочего дерева, что означает здесь нет возможности для путаницы или ошибки. 1). В репозитории, в котором нет рабочего дерева, никто никогда не заходит в свое дерево работы и не выполняет какую-либо работу, а "толкает винты вверх, прогресс работы" невозможно.
С учетом этого давайте посмотрим, что происходит, когда мы являемся получателем push, и у нас есть не-голый репозиторий, у которого есть фактическое дерево работы. Пусть также учитывается еще два вопроса:
- Поскольку у нас есть дерево работы, у нас также есть индексный файл (
.git/index
), который действует в своей обычной двойной роли "место для этапа следующего фиксации" и "кеш для ускорения git status
и аналогичных операции".
-
У нас также есть "текущая" ветвь, хранящаяся в файле HEAD
, 2 на которую мы можем смотреть напрямую, или использовать git symbolic-ref HEAD
для чтения (последнее официально утвержденный метод). Если текущая ветвь br
, файл HEAD
содержит одну строку, читающую ref: refs/heads/br
, например, и git symbolic-ref HEAD
выводит refs/heads/br
.
(Если мы находимся в режиме "отсоединенного HEAD", файл HEAD
содержит необработанный SHA-1, а не ref: refs/heads/branch
. В этом случае получение нажатия не приведет к сбою в работе, поэтому мы можем смело игнорировать этот случай.)
Вот основной механизм получения push:
-
Как получатель, мы начинаем с получения объектов для добавления в наш репозиторий. 3 Мы добавляем все эти объекты, даже если мы завершим отклонение одного или нескольких эталонных обновлений.
-
Теперь мы получаем список предложений, общая форма которых выглядит так: "пожалуйста, установите refs/heads/X
в 1234567...
", "принудительно установите refs/heads/Y
в fedcba9...
" и так далее. Они соответствуют refspecs, кто использует их push
. (Если поставляемый SHA-1 - это все нули, их git просит удалить эти ссылки.)
Мы принимаем во внимание каждое из этих запросов на обновление ссылок, частично по одному, а частично и полностью в глотках, применяя перечисленные ниже подправы. Для получения обновлений, которые мы передаем, мы устанавливаем прилагаемую ссылку на поставляемый SHA-1 и сообщим другой git "ok, done"; для обновлений, которые терпят неудачу, мы говорим другим git "нет, отклонено" и поставляем немного более "разумное" сообщение. (Мы также передаем вывод stderr, а иногда и вывод stdout, переходов на другой git. Там есть небольшой протокол, чтобы рассказать ему, какие части являются нашими собственными ответами и которые просто передаются на выходе, так что его git знает, какие обновления мы приняли.)
-
Как только все закончится, мы запустим "post-receive hook" и передаем ему успешные обновления (в том же виде, что и для предварительного приема, но исключая отклоненные обновления).
Теперь оставьте (слегка) правила, используемые для принятия или отклонения отдельных обновлений и/или обновлений как целого. Они не обязательно находятся в фактическом внутреннем порядке (и я буду игнорировать несколько особых случаев, например receive.shallowUpdates
):
-
Некоторые обновления должны проходить различные встроенные тесты, чаще всего это тест "быстрой перемотки вперед", а иногда и "никогда не меняйте этот" тест. Именно то, что refs проверяется, зависит от нашей версии git, нашей конфигурации и флага силы для этого обновления. Подробнее об этом см. документация git config
., обращая особое внимание на receive.denyDeletes
и receive.denyNonFastForwards
, и обратите внимание, что git используется для применения правил быстрой пересылки для тегов обновлений (но не для удаления тегов) до git 1.8.2, когда теги были изменены на "никогда изменить" (но все же разрешить удаление, если не установлен receive.denyDeletes
).
-
Весь набор обновлений отправляется на крючок pre-receive
(на его стандартный ввод, как ряд строк). Сначала они дополняются еще одним битом информации: текущий SHA-1, связанный с каждой ссылкой, или all-zeros, если у нас еще нет этой ссылки. Если этот крюк выходит из ненулевого, весь набор обновлений - весь push-отклоняется. (Если крючок не существует, мы считаем, что этот тест прошел.)
-
Каждое отдельное обновление отправляется на крючок update
(в качестве аргументов). Если этот крюк выходит из ненулевого значения, это конкретное обновление отклоняется, но мы продолжаем проверять остальные. (Как и раньше, если крючок не существует, тест представляет собой автоматический проход.)
-
Наконец, у нас есть правила "не голые репозитории", которые вам больше всего нравятся, и я разберусь в их собственный раздел.
Обновление не голого репозитория: что разрешено и почему
(Я вижу VonC избил меня до этого, но я расскажу подробнее.)
Новые записи конфигурации или значения в git 1.6.6, git 2.3 и git 2.4:
-
receive.denyDeleteCurrent
: этот параметр был фактически введен в git 1.6.2, но ничего не сделал до тех пор, пока git 1.6.6. До этого момента, получая push-to-delete любой текущей ветки, удаляли текущую ссылку на ветку. Когда это было сделано, HEAD
оставалось указывать на несуществующую ветку (для ее исправления вам пришлось использовать инструменты сантехники или напрямую изменить файл). В git 1.6.6 это прекращено по умолчанию. (Я еще не проверял, что вещь "плохой HEAD" все еще происходит.)
-
receive.denyCurrentBranch
: это также продолжалось в течение 1.6.2 и было включено (т.е. действие по умолчанию "отказ" продолжалось в реальном времени) в 1.6.6. Однако в git 2.3 новое значение "updateInstead" выросло.
Обратите внимание, что оба они специфичны для "текущей ветки", то есть (единственной) ссылки refs/heads/br
, к которой относится HEAD
. И снова они применяются только тогда, когда core.bare
не установлен. В этом случае есть дерево работы и оно содержит файлы, которые каким-то образом связаны с тем, что SHA-1 подано в refs/heads/br
. Существует также (возможно, 4) индексный файл, который может иметь или не иметь вещи add
-ed, rm
-ed и сохранять состояние слияния, если вы находитесь в середине конфликтное слияние.
Предположим, что через receive.denyCurrentBranch
вы разрешаете кому-то git push
изменять ваш репозиторий, хранящийся SHA-1, для refs/heads/br
. Предположим далее, что у вас нет настроек перехвата развертывания и не используются новые (2.3+) функции. Затем, в этом случае, если кто-то другой изменяет ваш refs/heads/br
, ваш собственный индекс и дерево работы остаются неизменными. Для конкретности предположим, что br
используется для указания на commit 2222222...
, а кто-то другой - Bob, например, только что успешно нажал и изменил его на 3333333...
.
Если вы закончите собственное редактирование/слияние/все, git add
результаты, как обычно, и запустите git commit
, git сделает новую фиксацию из вашего текущего индекса, которая состоит из "все от commit 2222222...
за исключением ваших git add
и git rm
s". Материал, который Боб сделал, который находится в 3333333...
, не находится в вашем индексе. Однако новый фиксатор, который git, будет иметь 3333333...
в качестве родителя, используя содержимое, взятое из вашего индекса, основанное на 2222222...
. Эффект заключается в том, что ваша фиксация возвращает все изменения Боба при добавлении всех ваших изменений: ваша новая фиксация против 2222222...
покажет вам, что вы делали, в то время как ваша новая фиксация против своего родителя будет отличаться от вас, будет показано, что вы поддерживаете всю работу Боба, сохраняя собственная работа.
Если у вас есть крючок, который выполняет какое-то развертывание, содержимое вашего индекса и/или дерева работ будет зависеть от того, что именно делает этот крючок. Например, если он имеет значение git checkout -f
, все, что изменил Боб, заменит то, что вы положили в индекс и рабочее дерево.
Ни один из этих результатов не является тем, что на самом деле хочет.
Новый параметр updateInstead
приближен к тому, что люди иногда хотят: до разрешения эталонного обновления (смена Боба refs/heads/br
от 2222222...
до 3333333...
), git проверяет, является ли ваш индекс и рабочее дерево match commit 2222222...
. Если они это сделают, 5 git позволяет Бобу нажать и применить это обновление к вашему индексу и дереву дерева, как если бы вы заметили Боб так или иначе, и сделали git checkout br
, или что-то подобное, чтобы обновить все.
Здесь по-прежнему существует потенциальная опасность. Например, предположим, что вы открыли README
для работы над ним. Вы потратили некоторое время на преследование некоторых ссылочных URL и набрали их в своем редакторе, но ничего не записывали. Между тем, Боб сделал исправление README
, и он запускает свой git push
. Ваш git видит, что ваше рабочее дерево "чистое" и что обновление "безопасно", поэтому оно обновляет ваш README
.
В зависимости от того, насколько вы умны ваш редактор, когда вы выходите, чтобы записать свой README
, вы можете перезаписать изменения Боба, или ваш редактор может сказать "эй, README
изменен, я возьму новый" и потерять работу и т.д. Можно утверждать, что это плохое поведение этого редактора (и я бы купил этот аргумент), но это все еще потенциальная проблема - и это не ограничивается редакторами; вы можете запускать медленный вычислительный процесс, который записывает файлы, которые вы контролируете с помощью источника, что может вызвать такие же проблемы.
Git не пытается решить, как справиться со всем этим. git просто дает вам параметры конфигурации (больше механизмов) и оставляет окончательную политику до вас. Я бы сказал, что git значения по умолчанию верны; режим fancier updateInstead
не является значением по умолчанию, потому что правильная политика неясна.
1 Есть еще другие возможные ошибки, в зависимости от того, хотите ли вы режим групповой записи и общий доступ для простых ssh-нажатий. На предыдущем рабочем месте мы в конце концов установили политику настройки push-to-repositories с помощью script: вы настроили бы то, что вы хотели видеть в нем как частное репо, затем запустите script самостоятельно или выполните запуск администратора он, предоставляя ему URL для вашего частного репо, для создания публичного и общего репо путем клонирования. После этого нам было все равно, что вы сделали с этим частным репо, но главное в том, что мы будем клонировать с --bare
вместо того, чтобы иметь кого-то - обычно я-хоп исправляю все разбитые биты.: -)
2 Даже у открытого репозитория есть файл HEAD
и, следовательно, имеет текущую ветку. Он также имеет индекс, но без работы-dir индекс обычно не имеет значения. (Некоторые сценарии развертывания завершаются с использованием индекса голого репо, что приводит к ошибкам в некоторых сценариях развертывания, но этот еще один вопрос полностью.) Текущая ветвь немного актуальна: она влияет на то, какая ветка кто-то еще git clone
будет проверять их в конце процесса клонирования, при условии, что они не указали конкретное имя ветки.
3 Обычно мы получаем их как "тонкую упаковку", то есть пакет, который может дельта-сжимать объекты, которые у нас уже есть. Для этого нужно сделать шаг перед шагом "получение объектов", где мы сообщаем отправителю, что у нас есть SHA-1. Вы можете видеть, что мы передаем отправителю, отправителем, используя git ls-remote
. Там также некоторые ранние шаги согласования протокола. Это относится к деталям более низкого уровня, но не для процесса, описанного выше.
4 Вы можете удалить .git/index
, а git будет переконструировать его позже, когда это потребуется. Я не рекомендую удалять его, но эффект заключается в том, чтобы потерять все сохраненные git add
и git rm
s вместе с любой информацией о слиянии, если вы находитесь в середине слияния.
5 И проходят дополнительные тесты (см. Ответ VonC). Некоторые из этих дополнительных тестов не были в первоначальном ударе в режиме updateInstead
и, я думаю, были найдены трудным способом.