Да, это относительно просто: например,
git fetch <remote-or-url> refs/pull/1234/head:refs/heads/pr1234
превратит их (GitHub) pull-request- # 1234 коммитов в вашу ветку pr1234
.
Фон
Способ, которым это работает, прост:
Все имена 1 в Git являются ссылками или ссылки . То есть имя ветви master
на самом деле просто refs/heads/master
; имя тега v1.2
на самом деле просто refs/tags/v1.2
; Ваше дистанционное отслеживание origin/master
действительно refs/remotes/origin/master
. Имена, которые имена ветвей начинаются с refs/heads/
. Git обычно удаляет ведущую часть любого имени, если вы знаете, что master
- это ветвь, v1.2
- это тег, а origin/master
- это имя для удаленного отслеживания. .
Когда вы запускаете git fetch
, ваш Git получает их коммитов (и других объектов) по имени-и-ха sh -ID пары, которые их Git показывает вашему Git. Затем он копирует любые необходимые коммиты (и другие объекты), чтобы ваш Git мог обновлять ваши имена для удаленного отслеживания и / или записывать записи в ваш файл Git .git/FETCH_HEAD
и так далее. И наконец, он делает пару вещей:
- обновляет ваши собственные ссылки, как указано; и
- запись
.git/FETCH_HEAD
.
Файл FETCH_HEAD
оставлен для кода git pull
, в основном; Это немного исторический артефакт, теперь, когда git pull
был переписан в C.
Хорошая вещь в refs заключается в том, что разделение на пространства имен Вы или кто-либо другой может изобрести свой собственный. Используются пробелы refs/heads/
и refs/tags/
и refs/remotes/
, а также refs/bisect/
и refs/replace/
и некоторые другие, но GitHub был в состоянии использовать refs/pull/
, который сам Git не может хранить их имен.
В этом refs/pull/
пространстве GitHub вставляет PR или номер выпуска (эти номера относятся к репозиторию и являются глобальными для репозитория), а затем /head
для подсказки commit и /merge
для результата автоматического выполнения c test git merge
. Если автомат c объединить завершится неудачно , GitHub просто не создаст ссылку merge
. Следовательно, если есть PR с номером 1234, существует refs/pull/1234/head
; Если этот PR был успешно объединен с тестом, refs/pull/1234/merge
также существует, а если нет, то его нет.
Обратите внимание, что преобразование из их (GitHub's) branch имен в ваши дистанционное отслеживание имен контролируется вашей собственной remote.origin.fetch
строкой конфигурации, которая по умолчанию:
+refs/heads/*:refs/remotes/origin/*
Это refspe c: пара ссылок , разделенные двоеточием и, возможно, префикс со знаком плюс +
(всегда используется для этого конкретного случая). Это соответствует их именам branch , поскольку левая сторона или шаблон source соответствуют именам ветвей. Это заставляет Git заменять имена их ветвей именами для удаленного отслеживания, поскольку правая сторона или шаблон destination заменяет refs/heads/
на refs/remotes/origin/
(при этом все совпадает с *
без изменений).
Это означает, что вы можете добавить:
+refs/pull/*/head:refs/heads/pr*
к вашим remote.origin.fetch
refspecs в вашем .git/config
, так что git fetch
будет автоматически, и почти всегда, 2 создайте или обновите ваши pr<em>number</em>
ветви. Тем не менее, он потенциально разрушит любую из ваших личных pr<em>number</em>
веток, которые вы создали самостоятельно, поэтому имейте в виду, что если вы сделаете это, вы должны избегать именования веток pr
-что-то (по крайней мере что-то числительное c) , но остерегайтесь обрезки, см. сноску 2).
1 Исключениями здесь являются HEAD
, MERGE_HEAD
, CHERRY_PICK_HEAD
и тому подобное. Хотя FETCH_HEAD
иногда работает как ссылка, файл FETCH_HEAD
особенно особенный, он может содержать несколько строк и некоторые дополнительные аннотации; другие содержат только (и точно) один га sh удостоверение личности или один символ c ref.
2"Всегда" слишком сильно, и даже мой слегка ласка формулируется почти всегда также может быть: каждый раз, когда вы запускаете git fetch
с некоторыми refspe c аргументом (ами), это переопределит это значение по умолчанию. Ваши сконфигурированные настройки remote.origin.fetch
используются только в том случае, если вы их не переопределяли. Вспомните, как это взаимодействует с fetch.prune
или git fetch -p
: *
в пункте назначения теперь означает, что Git автоматически удалит соответствующих ссылок, которые не были записаны действием извлечения.
Способность писать pr*
, а не, например, pr/*
, зависит от вашего Git года изготовления вина. В некоторых более старых версиях Git глобальные шаблоны *
в refspecs можно использовать только в «компоненте полного имени», например, refs/heads/*:refs/remotes/origin/*
всегда в порядке во всех Git версиях, независимо от того, насколько они древние, но иногда refs/heads/a*:refs/remotes/origin/a*
нет.