Подтвердить что ты не робот

Что делает GIT PUSH?

Я не могу найти хорошее объяснение этого.

Я знаю, что делает git pull:

1) a выборка, т.е. все дополнительные фиксации с сервера копируются в локальное репо, а указатель перехода источника/мастера перемещается в конец цепочки фиксации

2) a слияние ветки origin/master в ведущую ветвь, указатель главной ветки, перемещающийся к вновь созданному фиксации, в то время как указатель начала/мастер остается.

Я предполагаю, что git push делает что-то очень похожее, но я точно не знаю. Я считаю, что он делает одно из них или что-то подобное или что-то еще (?):

  • копирует все локальные коммиты и делает слияние там (обратное тому, что делает git pull); но в этом случае у сервера нет моей локальной ветки мастера, поэтому я не вижу, что это такое слияние.

ИЛИ

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

В настоящее время я использую git для основных операций, поэтому у меня все в порядке, но я хочу полностью понять эти внутренние функции.

4b9b3361

Ответ 1

Предполагая, что вы уже понимаете модель "w20" "объекты" (ваши коммиты и файлы и т.д. все являются "объектами в базе данных git", с "свободными" объектами - те, которые не упакованы для экономии пространства в .git/objects/12/34567... и т.п.)...

Вы правы: git fetch извлекает объекты "они" (origin, в этом случае), которые у вас нет, и наклеивает на них метки: origin/master и тому подобное. Более конкретно, ваш git вызывает их на интернет-телефоне (или любой другой подходящий транспорт) и спрашивает: какие у вас есть ветки и какие идентификаторы совершают? Они имеют master, а идентификатор 1234567..., поэтому ваш git запрашивает 1234567... и любые другие объекты, которых у вас еще нет, и делает ваш origin/master точкой для фиксации объекта 1234567....

Часть git push, которая является симметричной, такова: ваш git вызывает свои git на одном и том же интернет-телефоне, как обычно, но на этот раз вместо того, чтобы просто спрашивать их об их ветких, ваш git рассказывает о ваших ветвях и объектах репозитория git, а затем говорит: "Как насчет того, чтобы вы установили ваш master в 56789ab...?"

Их git рассматривает объекты, которые вы отправили (новый commit 56789ab... и любые другие объекты, которые у вас есть, что они не сделали, что им нужно будет их взять). Их git затем рассматривает запрос, чтобы установить их master в 56789ab....

Как Крис К уже ответил, здесь не происходит слияния: ваш git просто предлагает, чтобы их git перезаписывали их master с помощью этого нового коммита -Я БЫ. Это до их git, чтобы решить, разрешать ли это.

Если "они" (кто бы они ни были) не создали каких-либо специальных правил, правило по умолчанию, которое использует здесь git, очень просто: перезапись разрешена, если изменение является "быстрой перемоткой вперед". Он имеет одну дополнительную функцию: перезапись также разрешена, если изменение выполняется с установленным флагом "force". Обычно не рекомендуется устанавливать здесь флаг силы, поскольку правило по умолчанию "только быстрое переключение" обычно является правильным правилом.

Очевидный вопрос здесь: что такое быстрый перемотка вперед? Мы доберемся до этого через мгновение; сначала мне нужно немного расширить метки, или "ссылки" будут более формальными.

Git ссылки

В git веткой или тегом или даже такими вещами, как stash и HEAD, являются все ссылки. Большинство из них находятся в .git/refs/, подкаталоге репозитория git. (Несколько ссылок на верхний уровень, включая HEAD, находятся в самой строке .git). Все ссылки - это файл 1 содержащий идентификатор SHA-1, например 7452b4b5786778d5d87f5c90a94fab8936502e20. Идентификаторы SHA-1 громоздки и невозможны для людей, поэтому мы используем имена, такие как v2.1.0 (тег в этом случае, версия 2.1.0 самого git), чтобы сохранить их для нас.

Некоторые ссылки - или, по крайней мере, должны быть полностью статичными. Тег v2.1.0 никогда не должен ссылаться на что-то другое, кроме вышеописанного идентификатора SHA-1. Но некоторые ссылки более динамичны. В частности, ваши собственные локальные ветки, такие как master, перемещают цели. Один частный случай, HEAD, даже не является его собственной целью: он обычно содержит имя ветки с движущимся мишенью. Таким образом, существует одно исключение для "косвенных" ссылок: HEAD обычно содержит строку ref: refs/heads/master или ref: refs/heads/branch или что-то в этих строках; и git не позволяет (и не может) применять правило "никогда не менять" для ссылок. Особенно сильно меняются ветки.

Откуда вы знаете, должна ли эта ссылка изменить? Ну, многое из этого просто по соглашению: ветки перемещаются, а тэги - нет. Но вы должны спросить: откуда вы знаете, является ли ссылка веткой или тегом, или что?

Обозначения пробелов: refs/heads/, refs/tags/ и т.д.

Кроме специальных ссылок верхнего уровня, все ссылки git находятся в refs/, как мы уже отмечали выше. Однако в каталоге refs/ (или "папке", если вы работаете на Windows или Mac), мы можем иметь целую коллекцию подкаталогов. git имеет на данный момент четыре четко определенных подкаталога: refs/heads/ содержит все ваши ветки, refs/tags/ содержит все ваши теги, refs/remotes/ содержит все ваши ветки удаленного отслеживания, а refs/notes/ содержит git "notes" (который я проигнорирую здесь, поскольку они немного усложняются).

Поскольку все ваши ветки находятся в refs/heads/, git может сказать, что они должны быть изменены, и поскольку все ваши теги находятся в refs/tags/, git может сказать, что это не должно.

Автоматическое движение ветвей

Когда вы делаете новый коммит и находитесь на ветке, например master, git будет автоматически перемещать ссылку. Ваша новая фиксация создается с ее "parent commit", являющейся предыдущей веткой, и после того, как ваша новая фиксация будет безопасно сохранена, git изменяет master, чтобы содержать идентификатор нового коммита. Другими словами, он гарантирует, что имя ветки, ссылка в подкаталоге heads, всегда указывает на максимальную фиксацию tip.

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

Что такое ускоренная перемотка вперед?

Обычно вы видите "быструю перемотку вперед" в контексте слияния, часто с объединением, выполненным как второй шаг в git pull. Но на самом деле "быстрая пересылка" на самом деле является свойством перемещения метки.

Давайте нарисуем немного графика фиксации. Маленькие узлы o представляют собой коммиты, и каждый из них имеет стрелку, указывающую влево, влево и вверх, или влево или вправо (или в одном случае, две стрелки) на родителя (или родителей). Чтобы иметь возможность ссылаться на три по имени, я дам им заглавные буквы вместо o. Кроме того, это произведение на основе персонажа не имеет стрелок, поэтому вы должны вообразить их; просто помните, что все они указывают налево или налево, как на три имени.

            o - A   <-- name1
          /
o - o - o - o - B   <-- name2
      \       /
        o - C       <-- name3

Если вы попросите git изменить ссылку, вы просто попросите ее вставить новый идентификатор фиксации в метку. В этом случае эти метки живут в refs/heads/ и, следовательно, являются именами ветвей, поэтому они должны иметь возможность принимать новые значения.

Если мы скажем git поставить B в name1, мы получим следующее:

            o - A
          /
o - o - o - o - B   <-- name1, name2
      \       /
        o - C       <-- name3

Обратите внимание, что commit A теперь не имеет имени, а o слева от него находится только путем нахождения A..., что трудно, так как A не имеет имени. Commit A был оставлен, и эти два коммита имеют право на "сбор мусора". (В git в "reflog" осталось "имя призрака", которое поддерживает ветвь с A около 30 дней в целом, но это совсем другая тема.)

Как сообщить git поставить B в name3? Если мы сделаем следующее, мы получим следующее:

            o - A
          /
o - o - o - o - B   <-- name1, name2, name3
      \       /
        o - C

Здесь у commit C все еще есть способ его найти: начинайте с B и работайте вниз и влево, с другим (вторым) родительским фиксатором, и вы обнаружите commit C. Так что commit C не оставлен.

Обновление name1, как это, не является быстрой перемоткой вперед, но обновление name3 есть.

Более конкретно, смена ссылок является "быстрой перемоткой вперед" тогда и только тогда, когда объект - обычно фиксация - что ссылка, используемая для указания точки, до сих пор доступна, начиная с нового места и работая назад, вдоль всех возможные обратные пути. В терминах графа это быстрый переход, если старый node является предком нового.

Создание push будет быстрой перемоткой вперед, путем слияния

Имя ветки fast-forward происходит, когда единственное, что вы делаете, это добавить новые коммиты; но также, когда, если вы добавили новые коммиты, вы также объединились - независимо от того, что новое совершает, кто-то добавил. То есть предположим, что у вашего репо есть это в нем, после того, как вы сделали одно новое сообщение:

             o   <-- master
           /
...- o - o       <-- origin/master

В этот момент перемещение origin/master вверх и вправо было бы быстрой перемоткой вперед. Тем не менее, кто-то еще приходит и обновляет другое (origin) репо, поэтому вы делаете git fetch и получаете от них новую фиксацию. Ваш git перемещает метку origin/master (в быстрой перемотке вашего репо, как это бывает):

             o   <-- master
           /
...- o - o - o   <-- origin/master

В этот момент перемещение origin/master в master не было бы быстрой перемоткой вперед, так как оно отказалось бы от этой новой фиксации.

Однако вы можете выполнить операцию git merge origin/master, чтобы сделать новую фиксацию на вашем master, с двумя родительскими идентификаторами фиксации. Пусть обозначается это M (для слияния):

             o - M  <-- master
           /   /
...- o - o - o   <-- origin/master

Теперь вы можете git push вернуться к origin и попросить их установить master, который вы вызываете origin/master, равным вашему (новому) M, потому что для них это теперь ускоренная работа!

Обратите внимание, что вы также можете сделать git rebase, но оставьте это для другой проводки stackoverflow.: -)


1 Фактически, ссылки git всегда начинаются как отдельные файлы в разных подкаталогах, но если ссылка не обновляется долгое время, она, как правило, становится "упакованной" "(вместе со всеми другими в основном статическими ссылками) в один файл, полный упакованных ссылок. Это просто оптимизация сбережений времени, и ключ здесь не зависит от конкретной реализации, а скорее использует команды git rev-parse и update-ref для извлечения текущего SHA-1 из ссылки или обновления ссылка на новый SHA-1.

Ответ 2

Выполняется только копия, нет слияния.

Более конкретно, он копирует части хранилища объектов, которые находятся в локальном репо/ветке, и отсутствуют на удаленной стороне. Это включает в себя объекты commit, refs, tree и blobs.

Тэги являются заметным исключением, они требуют включения флага -tags.

Следующее сообщение в блоге git проще, чем вы думаете, имеет более подробную информацию.

Ответ 3

Мое простейшее описание: просто выполните следующие действия: (предположим, что вы выполняете git push origin master)

  • Скопируйте локальные коммиты, которые не существуют в удаленном репо на удаленное репо
  • Переместите начало/мастер (как в локальном git, так и в удаленном git), чтобы указать на то же локальное /master commit
  • Вставить НЕ Слияние

ОДНАКО. Он проверит, находится ли ваш локальный/ведущий на основе источника/мастера. Концептуально это означает, что в графе git от локального/ведущего вы можете вернуться непосредственно к исходному/ведущему (а не к источнику/хозяину вашего локального git, но мастеру на удаленном репо), только перемещаясь "вниз" ", что означает, что до вашего толчка не было сделано никаких изменений в удаленном репо. В противном случае нажатие будет отклонено

Ответ 4

Технический, жаргонный ответ от руководство выглядит следующим образом:

git push "обновляет удаленные ссылки, используя локальные ссылки, при отправке объекты, необходимые для заполнения заданных ссылок.

Итак, в основном, это копирование информации, чтобы убедиться, что ваш пульт находится в актуальном состоянии с вашим местным репо. Но что такое refs и какие объекты? Перефразируя руководство:

  • Refs ручная запись - это файлы, которые "сохраняют значение SHA-1 [объекта, например, фиксации]" под простое имя, чтобы вы могли использовать этот указатель, а не необработанное значение SHA-1 "[для поиска связанного с ним содержимого]. Вы можете увидеть их, перейдя к каталогам типа .git/refs/heads/<branch name> или .git/refs/remotes/origin/<branch name> в своем репо.

  • Объекты (ручная запись) включают коммиты, деревья, капли и теги (последний из которых не задан по умолчанию), Например, цитируя Mark Longair из другого SO-ответа, "фиксация фиксирует точный контент исходного кода в этот момент времени с датой, именем автора и ссылки на родительские коммиты".

Таким образом, когда вы git push, git используете локальные ссылки (созданные путем ввода git commit) для обновления эквивалентных файлов на удаленном компьютере, таким образом обновляя указатели на самые последние коммиты, а затем любое новое содержимое, ve created будет скопирован в систему git как объекты, помеченные некоторыми метаданными и ссылками SHA-1.

В качестве дополнительной иллюстрации того, что ссылка, здесь, в документах API Github, они показывают пример JSON результаты запросов API, запрашивающих ссылки в данном репо. Это может помочь вам понять, как разные части информации относятся друг к другу.